重构了KBFunctionView

This commit is contained in:
2025-11-12 16:03:30 +08:00
parent 62f3ddae4a
commit fea22aecab
6 changed files with 294 additions and 68 deletions

View File

@@ -0,0 +1,27 @@
//
// KBFunctionTagListView.h
// 封装标签列表UICollectionView
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class KBFunctionTagListView;
@protocol KBFunctionTagListViewDelegate <NSObject>
@optional
- (void)tagListView:(KBFunctionTagListView *)view didSelectIndex:(NSInteger)index title:(NSString *)title;
@end
@interface KBFunctionTagListView : UIView
@property (nonatomic, weak, nullable) id<KBFunctionTagListViewDelegate> delegate;
@property (nonatomic, strong, readonly) UICollectionView *collectionView;
- (void)setItems:(NSArray<NSString *> *)items;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,68 @@
//
// KBFunctionTagListView.m
//
#import "KBFunctionTagListView.h"
#import "KBFunctionTagCell.h"
static NSString * const kKBFunctionTagCellId2 = @"KBFunctionTagCellId2";
@interface KBFunctionTagListView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionViewInternal;
@property (nonatomic, copy) NSArray<NSString *> *items;
@end
@implementation KBFunctionTagListView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
_collectionViewInternal = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
_collectionViewInternal.backgroundColor = [UIColor clearColor];
_collectionViewInternal.dataSource = self;
_collectionViewInternal.delegate = self;
[_collectionViewInternal registerClass:[KBFunctionTagCell class] forCellWithReuseIdentifier:kKBFunctionTagCellId2];
[self addSubview:_collectionViewInternal];
_collectionViewInternal.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[_collectionViewInternal.topAnchor constraintEqualToAnchor:self.topAnchor],
[_collectionViewInternal.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
[_collectionViewInternal.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
[_collectionViewInternal.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
]];
_items = @[];
}
return self;
}
- (void)setItems:(NSArray<NSString *> *)items { _items = [items copy]; [self.collectionViewInternal reloadData]; }
- (UICollectionView *)collectionView { return self.collectionViewInternal; }
#pragma mark - UICollectionView
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.items.count; }
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
KBFunctionTagCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBFunctionTagCellId2 forIndexPath:indexPath];
cell.titleLabel.text = (indexPath.item < self.items.count) ? self.items[indexPath.item] : @"";
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGFloat totalW = collectionView.bounds.size.width; CGFloat space = 10.0; NSInteger columns = 3;
CGFloat width = floor((totalW - space * (columns - 1)) / columns);
return CGSizeMake(width, 48);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { return 10.0; }
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { return 12.0; }
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if ([self.delegate respondsToSelector:@selector(tagListView:didSelectIndex:title:)]) {
NSString *title = (indexPath.item < self.items.count) ? self.items[indexPath.item] : @"";
[self.delegate tagListView:self didSelectIndex:indexPath.item title:title];
}
}
@end

View File

@@ -0,0 +1,28 @@
//
// KBStreamOverlayView.h
// 自带关闭按钮的流式展示层,内部持有 KBStreamTextView。
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class KBStreamTextView, KBStreamOverlayView;
@protocol KBStreamOverlayViewDelegate <NSObject>
@optional
- (void)streamOverlayDidTapClose:(KBStreamOverlayView *)overlay;
@end
@interface KBStreamOverlayView : UIView
@property (nonatomic, strong, readonly) KBStreamTextView *textView;
@property (nonatomic, weak, nullable) id<KBStreamOverlayViewDelegate> delegate;
- (void)appendChunk:(NSString *)text;
- (void)finish;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,80 @@
//
// KBStreamOverlayView.m
//
#import "KBStreamOverlayView.h"
#import "KBStreamTextView.h"
#import "Masonry.h"
@interface KBStreamOverlayView ()
@property (nonatomic, strong) KBStreamTextView *textViewInternal;
@property (nonatomic, strong) UIButton *closeButton;
@end
@implementation KBStreamOverlayView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.92];
self.layer.cornerRadius = 12.0; self.layer.masksToBounds = YES;
[self addSubview:self.textViewInternal];
[self addSubview:self.closeButton];
[self.textViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left).offset(0);
make.right.equalTo(self.mas_right).offset(0);
make.bottom.equalTo(self.mas_bottom).offset(0);
make.top.equalTo(self.mas_top).offset(0);
}];
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_top).offset(8);
make.right.equalTo(self.mas_right).offset(-8);
make.height.mas_equalTo(28);
make.width.mas_greaterThanOrEqualTo(56);
}];
}
return self;
}
- (KBStreamTextView *)textViewInternal {
if (!_textViewInternal) {
_textViewInternal = [[KBStreamTextView alloc] init];
}
return _textViewInternal;
}
- (UIButton *)closeButton {
if (!_closeButton) {
UIButton *del = [UIButton buttonWithType:UIButtonTypeSystem];
del.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.35];
del.layer.cornerRadius = 14; del.layer.masksToBounds = YES;
del.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightSemibold];
[del setTitle:@"删除" forState:UIControlStateNormal];
[del setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[del addTarget:self action:@selector(onTapClose) forControlEvents:UIControlEventTouchUpInside];
_closeButton = del;
}
return _closeButton;
}
- (void)onTapClose {
if ([self.delegate respondsToSelector:@selector(streamOverlayDidTapClose:)]) {
[self.delegate streamOverlayDidTapClose:self];
}
}
- (void)appendChunk:(NSString *)text {
if (text.length == 0) return;
[self.textViewInternal appendStreamText:text];
}
- (void)finish {
[self.textViewInternal finishStreaming];
}
- (KBStreamTextView *)textView { return self.textViewInternal; }
@end

View File

@@ -17,30 +17,25 @@
#import "KBSkinManager.h"
#import "KBURLOpenBridge.h" // openURL:
#import "KBStreamTextView.h" //
#import "KBStreamOverlayView.h" //
#import "KBFunctionTagListView.h"
#import "KBStreamFetcher.h" //
static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
@interface KBFunctionView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, KBFunctionBarViewDelegate>
@interface KBFunctionView () <KBFunctionBarViewDelegate, KBStreamOverlayViewDelegate, KBFunctionTagListViewDelegate>
// UI
@property (nonatomic, strong) KBFunctionBarView *barViewInternal;
@property (nonatomic, strong) KBFunctionPasteView *pasteViewInternal;
@property (nonatomic, strong) UICollectionView *collectionViewInternal;
@property (nonatomic, strong) KBFunctionTagListView *tagListView;
@property (nonatomic, strong) UIView *rightButtonContainer; //
@property (nonatomic, strong) UIButton *pasteButtonInternal;
@property (nonatomic, strong) UIButton *deleteButtonInternal;
@property (nonatomic, strong) UIButton *clearButtonInternal;
@property (nonatomic, strong) UIButton *sendButtonInternal;
//
@property (nonatomic, strong, nullable) KBStreamTextView *streamTextView;
@property (nonatomic, strong, nullable) UIButton *streamDeleteButton;
// &
@property (nonatomic, strong, nullable) NSTimer *streamMockTimer;
@property (nonatomic, strong, nullable) NSArray<NSString *> *streamMockChunks;
@property (nonatomic, assign) NSInteger streamMockIndex;
@property (nonatomic, copy, nullable) NSString *streamMockSource; // \t
@property (nonatomic, assign) NSInteger streamMockCursor; //
// +
@property (nonatomic, strong, nullable) KBStreamOverlayView *streamOverlay;
//
@property (nonatomic, strong, nullable) KBStreamFetcher *streamFetcher;
@@ -152,9 +147,9 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
make.height.mas_equalTo(48);
}];
// 3. CollectionView
[self addSubview:self.collectionViewInternal];
[self.collectionViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
// 3. Tag List View
[self addSubview:self.tagListView];
[self.tagListView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left).offset(12);
make.right.equalTo(self.rightButtonContainer.mas_left).offset(-12);
make.top.equalTo(self.pasteViewInternal.mas_bottom).offset(10);
@@ -167,7 +162,7 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
- (void)reloadDemoData {
//
self.itemsInternal = @[@"高情商", @"暖味拉扯", @"风趣幽默", @"撩女生", @"社交惬匿", @"情场高手", @"一枚暖男", @"聊天搭子", @"表达爱意", @"更多话术"];
[self.collectionViewInternal reloadData];
[self.tagListView setItems:self.itemsInternal];
}
#pragma mark - UICollectionView
@@ -201,43 +196,21 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
- (void)kb_showStreamTextViewIfNeededWithTitle:(NSString *)title {
//
if (self.streamTextView.superview) { return; }
if (self.streamOverlay.superview) { return; }
// 使
self.collectionViewInternal.hidden = YES;
self.tagListView.hidden = YES;
KBStreamTextView *sv = [[KBStreamTextView alloc] init];
sv.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.92];
sv.layer.cornerRadius = 12.0; sv.layer.masksToBounds = YES;
//
if (title.length > 0) {
[sv appendStreamText:[NSString stringWithFormat:@"%@\t", title]]; //
}
[self addSubview:sv];
[sv mas_makeConstraints:^(MASConstraintMaker *make) {
KBStreamOverlayView *overlay = [[KBStreamOverlayView alloc] init];
overlay.delegate = (id)self;
[self addSubview:overlay];
[overlay mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left).offset(12);
make.right.equalTo(self.rightButtonContainer.mas_left).offset(-12);
make.top.equalTo(self.pasteViewInternal.mas_bottom).offset(10);
make.bottom.equalTo(self.mas_bottom).offset(-10);
}];
self.streamTextView = sv;
//
UIButton *del = [UIButton buttonWithType:UIButtonTypeSystem];
del.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.35];
del.layer.cornerRadius = 14; del.layer.masksToBounds = YES;
del.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightSemibold];
[del setTitle:@"删除" forState:UIControlStateNormal];
[del setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[del addTarget:self action:@selector(kb_onTapStreamDelete) forControlEvents:UIControlEventTouchUpInside];
[sv addSubview:del];
[del mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(sv.mas_top).offset(8);
make.right.equalTo(sv.mas_right).offset(-8);
make.height.mas_equalTo(28);
make.width.mas_greaterThanOrEqualTo(56);
}];
self.streamDeleteButton = del;
self.streamOverlay = overlay;
// GET
[self kb_startNetworkStreamingWithSeed:title];
@@ -246,11 +219,14 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
- (void)kb_onTapStreamDelete {
//
[self kb_stopNetworkStreaming];
[self.streamDeleteButton removeFromSuperview];
self.streamDeleteButton = nil;
[self.streamTextView removeFromSuperview];
self.streamTextView = nil;
self.collectionViewInternal.hidden = NO;
[self.streamOverlay removeFromSuperview];
self.streamOverlay = nil;
self.tagListView.hidden = NO;
}
//
- (void)streamOverlayDidTapClose:(KBStreamOverlayView *)overlay {
[self kb_onTapStreamDelete];
}
@@ -282,12 +258,8 @@ static NSString * const kKBStreamDemoURL = @"http://192.168.1.144:7529/api/demo/
};
fetcher.onFinish = ^(NSError * _Nullable error) {
__strong typeof(weakSelf) self = weakSelf; if (!self) return;
if (error) {
[KBHUD showInfo:@"拉取失败"];
[self.streamTextView finishStreaming];
} else {
[self.streamTextView finishStreaming];
}
if (error) { [KBHUD showInfo:@"拉取失败"]; }
[self.streamOverlay finish];
};
self.streamFetcher = fetcher;
[self.streamFetcher start];
@@ -305,11 +277,47 @@ static NSString * const kKBStreamDemoURL = @"http://192.168.1.144:7529/api/demo/
/// - KBStreamFetcher /t->\t \t
/// - UI
- (void)kb_appendChunkToStreamView:(NSString *)chunk {
if (chunk.length == 0 || !self.streamTextView) return;
[self.streamTextView appendStreamText:chunk];
if (chunk.length == 0 || !self.streamOverlay) return;
[self.streamOverlay appendChunk:chunk];
self.streamHasOutput = YES;
}
#pragma mark - KBFunctionTagListViewDelegate
- (void)tagListView:(KBFunctionTagListView *)view didSelectIndex:(NSInteger)index title:(NSString *)title {
// + 访访
if ([[KBFullAccessManager shared] hasFullAccess]) {
[self kb_showStreamTextViewIfNeededWithTitle:title ?: @""];
return;
}
// App
[KBHUD showInfo:@"处理中…"];
UIInputViewController *ivc = KBFindInputViewController(self);
if (!ivc) return;
NSString *encodedTitle = [title stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]] ?: @"";
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=functionView&index=%ld&title=%@", KB_UL_LOGIN, (long)index, encodedTitle]];
if (!ul) return;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[ivc.extensionContext openURL:ul completionHandler:^(BOOL ok) {
if (ok) return; // Universal Link
NSURL *scheme = [NSURL URLWithString:[NSString stringWithFormat:@"%@@//login?src=functionView&index=%ld&title=%@", KB_APP_SCHEME, (long)index, encodedTitle]];
[ivc.extensionContext openURL:scheme completionHandler:^(BOOL ok2) {
if (ok2) return;
BOOL bridged = NO;
@try {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
bridged = [KBURLOpenBridge openURLViaResponder:scheme from:self];
#pragma clang diagnostic pop
} @catch (__unused NSException *e) { bridged = NO; }
if (!bridged) {
dispatch_async(dispatch_get_main_queue(), ^{ [[KBFullAccessManager shared] ensureFullAccessOrGuideInView:self]; });
}
}];
}];
});
}
// UL App Scheme访
// 访 KBStreamTextView
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
@@ -501,17 +509,12 @@ static NSString * const kKBStreamDemoURL = @"http://192.168.1.144:7529/api/demo/
return _pasteViewInternal;
}
- (UICollectionView *)collectionViewInternal {
if (!_collectionViewInternal) {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.sectionInset = UIEdgeInsetsZero; //
_collectionViewInternal = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
_collectionViewInternal.backgroundColor = [UIColor clearColor];
_collectionViewInternal.dataSource = self;
_collectionViewInternal.delegate = self;
[_collectionViewInternal registerClass:[KBFunctionTagCell class] forCellWithReuseIdentifier:kKBFunctionTagCellId];
- (KBFunctionTagListView *)tagListView {
if (!_tagListView) {
_tagListView = [[KBFunctionTagListView alloc] init];
_tagListView.delegate = (id)self;
}
return _collectionViewInternal;
return _tagListView;
}
- (UIView *)rightButtonContainer {
@@ -580,7 +583,7 @@ static NSString * const kKBStreamDemoURL = @"http://192.168.1.144:7529/api/demo/
#pragma mark - Expose
- (UICollectionView *)collectionView { return self.collectionViewInternal; }
- (UICollectionView *)collectionView { return self.tagListView.collectionView; }
- (NSArray<NSString *> *)items { return self.itemsInternal; }
- (KBFunctionBarView *)barView { return self.barViewInternal; }
- (KBFunctionPasteView *)pasteView { return self.pasteViewInternal; }

View File

@@ -89,6 +89,8 @@
049FB22F2EC34EB900FAB05D /* KBStreamTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB22E2EC34EB900FAB05D /* KBStreamTextView.m */; };
049FB2322EC45A0000FAB05D /* KBStreamFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2312EC45A0000FAB05D /* KBStreamFetcher.m */; };
049FB2352EC45C6A00FAB05D /* NetworkStreamHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2342EC45C6A00FAB05D /* NetworkStreamHandler.m */; };
049FB23B2EC4766700FAB05D /* KBFunctionTagListView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2372EC4766700FAB05D /* KBFunctionTagListView.m */; };
049FB23C2EC4766700FAB05D /* KBStreamOverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2392EC4766700FAB05D /* KBStreamOverlayView.m */; };
049FB31D2EC21BCD00FAB05D /* KBMyKeyboardCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB31C2EC21BCD00FAB05D /* KBMyKeyboardCell.m */; };
04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; };
04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
@@ -308,6 +310,10 @@
049FB2312EC45A0000FAB05D /* KBStreamFetcher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBStreamFetcher.m; sourceTree = "<group>"; };
049FB2332EC45C6A00FAB05D /* NetworkStreamHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NetworkStreamHandler.h; sourceTree = "<group>"; };
049FB2342EC45C6A00FAB05D /* NetworkStreamHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NetworkStreamHandler.m; sourceTree = "<group>"; };
049FB2362EC4766700FAB05D /* KBFunctionTagListView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionTagListView.h; sourceTree = "<group>"; };
049FB2372EC4766700FAB05D /* KBFunctionTagListView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionTagListView.m; sourceTree = "<group>"; };
049FB2382EC4766700FAB05D /* KBStreamOverlayView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBStreamOverlayView.h; sourceTree = "<group>"; };
049FB2392EC4766700FAB05D /* KBStreamOverlayView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBStreamOverlayView.m; sourceTree = "<group>"; };
049FB31B2EC21BCD00FAB05D /* KBMyKeyboardCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyKeyboardCell.h; sourceTree = "<group>"; };
049FB31C2EC21BCD00FAB05D /* KBMyKeyboardCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyKeyboardCell.m; sourceTree = "<group>"; };
04A9A67D2EB9E1690023B8F4 /* KBResponderUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBResponderUtils.h; sourceTree = "<group>"; };
@@ -680,6 +686,17 @@
path = BMLongPressDragCellCollectionView;
sourceTree = "<group>";
};
049FB23A2EC4766700FAB05D /* Function */ = {
isa = PBXGroup;
children = (
049FB2362EC4766700FAB05D /* KBFunctionTagListView.h */,
049FB2372EC4766700FAB05D /* KBFunctionTagListView.m */,
049FB2382EC4766700FAB05D /* KBStreamOverlayView.h */,
049FB2392EC4766700FAB05D /* KBStreamOverlayView.m */,
);
path = Function;
sourceTree = "<group>";
};
04A9FE122EB4D0D20020DB6D /* Manager */ = {
isa = PBXGroup;
children = (
@@ -759,6 +776,7 @@
04FC95B12EB0B2CC007BD342 /* KBSettingView.m */,
049FB22D2EC34EB900FAB05D /* KBStreamTextView.h */,
049FB22E2EC34EB900FAB05D /* KBStreamTextView.m */,
049FB23A2EC4766700FAB05D /* Function */,
);
path = View;
sourceTree = "<group>";
@@ -1409,6 +1427,8 @@
049FB2352EC45C6A00FAB05D /* NetworkStreamHandler.m in Sources */,
04FC956A2EB05497007BD342 /* KBKeyButton.m in Sources */,
04FC95B22EB0B2CC007BD342 /* KBSettingView.m in Sources */,
049FB23B2EC4766700FAB05D /* KBFunctionTagListView.m in Sources */,
049FB23C2EC4766700FAB05D /* KBStreamOverlayView.m in Sources */,
049FB22F2EC34EB900FAB05D /* KBStreamTextView.m in Sources */,
04FC95702EB09516007BD342 /* KBFunctionView.m in Sources */,
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */,