新增接口,界面
This commit is contained in:
24
keyBoard/Class/AiTalk/V/KBPersonaChatCell.h
Normal file
24
keyBoard/Class/AiTalk/V/KBPersonaChatCell.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// KBPersonaChatCell.h
|
||||
// keyBoard
|
||||
//
|
||||
// Created by Kiro on 2026/1/26.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "KBPersonaModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 人设聊天 Cell
|
||||
@interface KBPersonaChatCell : UICollectionViewCell
|
||||
|
||||
/// 人设数据
|
||||
@property (nonatomic, strong) KBPersonaModel *persona;
|
||||
|
||||
/// 预加载数据
|
||||
- (void)preloadDataIfNeeded;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
224
keyBoard/Class/AiTalk/V/KBPersonaChatCell.m
Normal file
224
keyBoard/Class/AiTalk/V/KBPersonaChatCell.m
Normal file
@@ -0,0 +1,224 @@
|
||||
//
|
||||
// KBPersonaChatCell.m
|
||||
// keyBoard
|
||||
//
|
||||
// Created by Kiro on 2026/1/26.
|
||||
//
|
||||
|
||||
#import "KBPersonaChatCell.h"
|
||||
#import "KBChatTableView.h"
|
||||
#import "KBAiChatMessage.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
|
||||
@interface KBPersonaChatCell () <UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
/// 背景图
|
||||
@property (nonatomic, strong) UIImageView *backgroundImageView;
|
||||
|
||||
/// 头像
|
||||
@property (nonatomic, strong) UIImageView *avatarImageView;
|
||||
|
||||
/// 人设名称
|
||||
@property (nonatomic, strong) UILabel *nameLabel;
|
||||
|
||||
/// 开场白
|
||||
@property (nonatomic, strong) UILabel *openingLabel;
|
||||
|
||||
/// 聊天列表
|
||||
@property (nonatomic, strong) UITableView *tableView;
|
||||
|
||||
/// 聊天消息
|
||||
@property (nonatomic, strong) NSMutableArray<KBAiChatMessage *> *messages;
|
||||
|
||||
/// 是否已加载数据
|
||||
@property (nonatomic, assign) BOOL hasLoadedData;
|
||||
|
||||
@end
|
||||
|
||||
@implementation KBPersonaChatCell
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setupUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - 1:控件初始化
|
||||
|
||||
- (void)setupUI {
|
||||
// 背景图
|
||||
[self.contentView addSubview:self.backgroundImageView];
|
||||
[self.backgroundImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
// 半透明遮罩
|
||||
UIView *maskView = [[UIView alloc] init];
|
||||
maskView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3];
|
||||
[self.contentView addSubview:maskView];
|
||||
[maskView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
// 头像
|
||||
[self.contentView addSubview:self.avatarImageView];
|
||||
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.contentView).offset(80);
|
||||
make.centerX.equalTo(self.contentView);
|
||||
make.size.mas_equalTo(CGSizeMake(80, 80));
|
||||
}];
|
||||
|
||||
// 人设名称
|
||||
[self.contentView addSubview:self.nameLabel];
|
||||
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.avatarImageView.mas_bottom).offset(12);
|
||||
make.centerX.equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
// 开场白
|
||||
[self.contentView addSubview:self.openingLabel];
|
||||
[self.openingLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.nameLabel.mas_bottom).offset(8);
|
||||
make.left.equalTo(self.contentView).offset(40);
|
||||
make.right.equalTo(self.contentView).offset(-40);
|
||||
}];
|
||||
|
||||
// 聊天列表
|
||||
[self.contentView addSubview:self.tableView];
|
||||
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.openingLabel.mas_bottom).offset(30);
|
||||
make.left.right.bottom.equalTo(self.contentView);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Setter
|
||||
|
||||
- (void)setPersona:(KBPersonaModel *)persona {
|
||||
_persona = persona;
|
||||
|
||||
// 重置状态
|
||||
self.hasLoadedData = NO;
|
||||
self.messages = [NSMutableArray array];
|
||||
|
||||
// 设置 UI
|
||||
[self.backgroundImageView sd_setImageWithURL:[NSURL URLWithString:persona.coverImageUrl]
|
||||
placeholderImage:[UIImage imageNamed:@"placeholder_bg"]];
|
||||
[self.avatarImageView sd_setImageWithURL:[NSURL URLWithString:persona.avatarUrl]
|
||||
placeholderImage:[UIImage imageNamed:@"placeholder_avatar"]];
|
||||
self.nameLabel.text = persona.name;
|
||||
self.openingLabel.text = persona.shortDesc.length > 0 ? persona.shortDesc : persona.introText;
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - 2:数据加载
|
||||
|
||||
- (void)preloadDataIfNeeded {
|
||||
if (self.hasLoadedData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 这里后续需要用 chatId 去请求聊天记录
|
||||
// 目前先添加开场白作为第一条消息
|
||||
self.hasLoadedData = YES;
|
||||
|
||||
if (self.persona.introText.length > 0) {
|
||||
KBAiChatMessage *openingMsg = [KBAiChatMessage assistantMessageWithText:self.persona.introText];
|
||||
openingMsg.isComplete = YES;
|
||||
[self.messages addObject:openingMsg];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.messages.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
|
||||
cell.backgroundColor = [UIColor clearColor];
|
||||
cell.textLabel.textColor = [UIColor whiteColor];
|
||||
cell.textLabel.numberOfLines = 0;
|
||||
}
|
||||
|
||||
KBAiChatMessage *message = self.messages[indexPath.row];
|
||||
cell.textLabel.text = message.text;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return UITableViewAutomaticDimension;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy Load
|
||||
|
||||
- (UIImageView *)backgroundImageView {
|
||||
if (!_backgroundImageView) {
|
||||
_backgroundImageView = [[UIImageView alloc] init];
|
||||
_backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_backgroundImageView.clipsToBounds = YES;
|
||||
}
|
||||
return _backgroundImageView;
|
||||
}
|
||||
|
||||
- (UIImageView *)avatarImageView {
|
||||
if (!_avatarImageView) {
|
||||
_avatarImageView = [[UIImageView alloc] init];
|
||||
_avatarImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_avatarImageView.layer.cornerRadius = 40;
|
||||
_avatarImageView.layer.borderWidth = 3;
|
||||
_avatarImageView.layer.borderColor = [UIColor whiteColor].CGColor;
|
||||
_avatarImageView.clipsToBounds = YES;
|
||||
}
|
||||
return _avatarImageView;
|
||||
}
|
||||
|
||||
- (UILabel *)nameLabel {
|
||||
if (!_nameLabel) {
|
||||
_nameLabel = [[UILabel alloc] init];
|
||||
_nameLabel.font = [UIFont boldSystemFontOfSize:20];
|
||||
_nameLabel.textColor = [UIColor whiteColor];
|
||||
_nameLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _nameLabel;
|
||||
}
|
||||
|
||||
- (UILabel *)openingLabel {
|
||||
if (!_openingLabel) {
|
||||
_openingLabel = [[UILabel alloc] init];
|
||||
_openingLabel.font = [UIFont systemFontOfSize:14];
|
||||
_openingLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9];
|
||||
_openingLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_openingLabel.numberOfLines = 2;
|
||||
}
|
||||
return _openingLabel;
|
||||
}
|
||||
|
||||
- (UITableView *)tableView {
|
||||
if (!_tableView) {
|
||||
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||
_tableView.delegate = self;
|
||||
_tableView.dataSource = self;
|
||||
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
_tableView.backgroundColor = [UIColor clearColor];
|
||||
_tableView.showsVerticalScrollIndicator = NO;
|
||||
_tableView.estimatedRowHeight = 60;
|
||||
_tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
|
||||
if (@available(iOS 11.0, *)) {
|
||||
_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user