This commit is contained in:
2026-01-27 18:53:19 +08:00
parent b34de116a3
commit db869552e4
16 changed files with 402 additions and 3 deletions

View File

@@ -144,6 +144,7 @@
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 */; };
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 */; };
@@ -544,6 +545,8 @@
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>"; };
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>"; };
@@ -1234,6 +1237,8 @@
049FB20D2EC1CD2800FAB05D /* KBAlert.m */,
042869FD2ECAEF2B00CE730C /* KBMoneyBtn.h */,
042869FE2ECAEF2B00CE730C /* KBMoneyBtn.m */,
048FFD252F28C6CF005D62AE /* KBImagePositionButton.h */,
048FFD262F28C6CF005D62AE /* KBImagePositionButton.m */,
);
path = V;
sourceTree = "<group>";
@@ -2444,6 +2449,7 @@
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 */,

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_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

@@ -74,6 +74,13 @@ typedef NS_ENUM(NSInteger, KBPersonaVisibility) {
/// 更新时间
@property (nonatomic, copy) NSString *updatedAt;
/// 评论数
@property (nonatomic, copy) NSString *commentCount;
/// 喜欢数
@property (nonatomic, copy) NSString *likeCount;
/// 是否喜欢
@property (nonatomic, assign) BOOL liked;
#pragma mark - 扩展属性

View File

@@ -89,7 +89,8 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟
make.edges.equalTo(self);
}];
self.contentBottomInset = KB_TABBAR_HEIGHT + 40 + 10;
// contentBottomInset chatView
self.contentBottomInset = 20; //
[self updateContentBottomInset:self.contentBottomInset];
__weak typeof(self) weakSelf = self;

View File

@@ -10,6 +10,7 @@
#import "KBAiChatMessage.h"
#import "KBChatHistoryPageModel.h"
#import "AiVM.h"
#import "KBImagePositionButton.h"
#import <Masonry/Masonry.h>
#import <SDWebImage/SDWebImage.h>
@@ -48,6 +49,12 @@
/// AiVM
@property (nonatomic, strong) AiVM *aiVM;
///
@property (nonatomic, strong) KBImagePositionButton *commentButton;
///
@property (nonatomic, strong) KBImagePositionButton *likeButton;
@end
@implementation KBPersonaChatCell
@@ -113,6 +120,24 @@
make.centerY.equalTo(self.avatarImageView);
}];
//
[self.contentView addSubview:self.commentButton];
[self.commentButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.contentView).offset(-20);
make.centerY.equalTo(self.avatarImageView);
make.width.mas_equalTo(40);
make.height.mas_equalTo(50);
}];
// 20px
[self.contentView addSubview:self.likeButton];
[self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.commentButton.mas_left).offset(-20);
make.centerY.equalTo(self.avatarImageView);
make.width.mas_equalTo(40);
make.height.mas_equalTo(50);
}];
//
[self.contentView addSubview:self.chatView];
[self.chatView mas_makeConstraints:^(MASConstraintMaker *make) {
@@ -147,6 +172,10 @@
//
[self.chatView stopPlayingAudio];
[self.chatView clearMessages];
[self.commentButton setTitle:persona.commentCount forState:UIControlStateNormal];
[self.likeButton setTitle:persona.likeCount forState:UIControlStateNormal];
self.likeButton.selected = persona.liked;
}
#pragma mark - 2
@@ -350,7 +379,7 @@
- (UILabel *)nameLabel {
if (!_nameLabel) {
_nameLabel = [[UILabel alloc] init];
_nameLabel.font = [UIFont boldSystemFontOfSize:20];
_nameLabel.font = [UIFont boldSystemFontOfSize:12];
_nameLabel.textColor = [UIColor whiteColor];
_nameLabel.textAlignment = NSTextAlignmentCenter;
}
@@ -377,4 +406,63 @@
return _chatView;
}
- (KBImagePositionButton *)commentButton {
if (!_commentButton) {
//
_commentButton = [[KBImagePositionButton alloc] initWithImagePosition:KBImagePositionTop spacing:4];
//
_commentButton.titleLabel.font = [UIFont systemFontOfSize:10];
//
[_commentButton setImage:[UIImage imageNamed:@"ai_comment_icon"] forState:UIControlStateNormal];
//
[_commentButton setTitle:@"0" forState:UIControlStateNormal];
[_commentButton setTitleColor:[[UIColor whiteColor] colorWithAlphaComponent:0.8] forState:UIControlStateNormal];
//
[_commentButton addTarget:self action:@selector(commentButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
}
return _commentButton;
}
- (KBImagePositionButton *)likeButton {
if (!_likeButton) {
//
_likeButton = [[KBImagePositionButton alloc] initWithImagePosition:KBImagePositionTop spacing:4];
//
_likeButton.titleLabel.font = [UIFont systemFontOfSize:10];
//
[_likeButton setImage:[UIImage imageNamed:@"ai_live_icon"] forState:UIControlStateNormal];
[_likeButton setImage:[UIImage imageNamed:@"ai_livesel_icon"] forState:UIControlStateSelected];
//
[_likeButton setTitle:@"0" forState:UIControlStateNormal];
[_likeButton setTitleColor:[[UIColor whiteColor] colorWithAlphaComponent:0.8] forState:UIControlStateNormal];
//
[_likeButton addTarget:self action:@selector(likeButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
}
return _likeButton;
}
#pragma mark - Button Actions
- (void)commentButtonTapped:(KBImagePositionButton *)sender {
sender.selected = !sender.selected;
NSLog(@"[KBPersonaChatCell] 评论按钮点击,选中状态:%d", sender.selected);
// TODO:
}
- (void)likeButtonTapped:(KBImagePositionButton *)sender {
sender.selected = !sender.selected;
NSLog(@"[KBPersonaChatCell] 喜欢按钮点击,选中状态:%d", sender.selected);
// TODO:
}
@end

View File

@@ -422,7 +422,12 @@
- (void)updateChatViewBottomInset {
CGFloat bottomSpacing = (self.currentKeyboardHeight > 0.0) ? (self.currentKeyboardHeight + 8.0) : self.baseInputBarBottomSpacing;
CGFloat bottomInset = self.voiceInputBarHeight + bottomSpacing;
// bottomInset chatView avatar
// 20 chatView
CGFloat bottomInset = 20; //
NSLog(@"[KBAIHomeVC] 更新 ChatView bottomInset: %.2f", bottomInset);
for (NSIndexPath *indexPath in self.collectionView.indexPathsForVisibleItems) {
KBPersonaChatCell *cell = (KBPersonaChatCell *)[self.collectionView cellForItemAtIndexPath:indexPath];

View File

@@ -0,0 +1,39 @@
//
// KBImagePositionButton.h
// keyBoard
//
// Created by Kiro on 2026/1/27.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/// 图片位置枚举
typedef NS_ENUM(NSInteger, KBImagePosition) {
KBImagePositionTop, // 图片在上,文字在下
KBImagePositionBottom, // 图片在下,文字在上
KBImagePositionLeft, // 图片在左,文字在右(默认)
KBImagePositionRight // 图片在右,文字在左
};
/// 可以指定图片位置的按钮
@interface KBImagePositionButton : UIButton
/// 图片位置(默认 KBImagePositionLeft
@property (nonatomic, assign) KBImagePosition imagePosition;
/// 图片和文字之间的间距(默认 8
@property (nonatomic, assign) CGFloat spacing;
/**
便捷初始化方法
@param imagePosition 图片位置
@param spacing 图片和文字之间的间距
*/
- (instancetype)initWithImagePosition:(KBImagePosition)imagePosition spacing:(CGFloat)spacing;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,187 @@
//
// KBImagePositionButton.m
// keyBoard
//
// Created by Kiro on 2026/1/27.
//
#import "KBImagePositionButton.h"
@implementation KBImagePositionButton
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupDefault];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self setupDefault];
}
return self;
}
- (instancetype)initWithImagePosition:(KBImagePosition)imagePosition spacing:(CGFloat)spacing {
if (self = [super initWithFrame:CGRectZero]) {
_imagePosition = imagePosition;
_spacing = spacing;
[self setupDefault];
}
return self;
}
- (void)setupDefault {
// _imagePosition == 0 KBImagePositionTop 0
// initWithFrame initWithCoder _imagePosition 0 (KBImagePositionTop)
// initWithImagePosition _imagePosition
//
if (self.spacing == 0) {
_spacing = 8;
}
[self updateEdgeInsets];
}
#pragma mark - Setter
- (void)setImagePosition:(KBImagePosition)imagePosition {
_imagePosition = imagePosition;
[self updateEdgeInsets];
[self setNeedsLayout];
}
- (void)setSpacing:(CGFloat)spacing {
_spacing = spacing;
[self updateEdgeInsets];
[self setNeedsLayout];
}
- (void)setImage:(UIImage *)image forState:(UIControlState)state {
[super setImage:image forState:state];
// image
dispatch_async(dispatch_get_main_queue(), ^{
[self updateEdgeInsets];
});
}
- (void)setTitle:(NSString *)title forState:(UIControlState)state {
[super setTitle:title forState:state];
// title
dispatch_async(dispatch_get_main_queue(), ^{
[self updateEdgeInsets];
});
}
#pragma mark - EdgeInsets
- (void)updateEdgeInsets {
CGSize imageSize = self.currentImage.size;
CGSize titleSize = CGSizeZero;
if (self.currentTitle.length > 0 && self.titleLabel.font) {
NSDictionary *attributes = @{NSFontAttributeName: self.titleLabel.font};
titleSize = [self.currentTitle sizeWithAttributes:attributes];
}
switch (self.imagePosition) {
case KBImagePositionTop: {
//
self.imageEdgeInsets = UIEdgeInsetsMake(
-(titleSize.height + self.spacing), // top:
0, // left
0, // bottom
-titleSize.width // right:
);
self.titleEdgeInsets = UIEdgeInsetsMake(
imageSize.height + self.spacing, // top:
-imageSize.width, // left:
0, // bottom
0 // right
);
break;
}
case KBImagePositionBottom: {
//
self.imageEdgeInsets = UIEdgeInsetsMake(
titleSize.height + self.spacing, // top:
0, // left
0, // bottom
-titleSize.width // right
);
self.titleEdgeInsets = UIEdgeInsetsMake(
-(imageSize.height + self.spacing), // top:
-imageSize.width, // left
0, // bottom
0 // right
);
break;
}
case KBImagePositionLeft: {
//
self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, self.spacing);
self.titleEdgeInsets = UIEdgeInsetsMake(0, self.spacing, 0, 0);
break;
}
case KBImagePositionRight: {
//
self.imageEdgeInsets = UIEdgeInsetsMake(
0,
titleSize.width + self.spacing,
0,
-(titleSize.width + self.spacing)
);
self.titleEdgeInsets = UIEdgeInsetsMake(
0,
-(imageSize.width + self.spacing),
0,
imageSize.width + self.spacing
);
break;
}
}
NSLog(@"imageEdgeInsets: %@", NSStringFromUIEdgeInsets(self.imageEdgeInsets));
NSLog(@"titleEdgeInsets: %@", NSStringFromUIEdgeInsets(self.titleEdgeInsets));
}
- (CGSize)intrinsicContentSize {
CGSize imageSize = self.currentImage ? self.currentImage.size : CGSizeZero;
CGSize titleSize = CGSizeZero;
if (self.currentTitle.length > 0 && self.titleLabel.font) {
NSDictionary *attributes = @{NSFontAttributeName: self.titleLabel.font};
titleSize = [self.currentTitle sizeWithAttributes:attributes];
}
CGSize size = CGSizeZero;
switch (self.imagePosition) {
case KBImagePositionTop:
case KBImagePositionBottom: {
//
size.width = MAX(imageSize.width, titleSize.width);
size.height = imageSize.height + self.spacing + titleSize.height;
break;
}
case KBImagePositionLeft:
case KBImagePositionRight: {
//
size.width = imageSize.width + self.spacing + titleSize.width;
size.height = MAX(imageSize.height, titleSize.height);
break;
}
}
return size;
}
@end