3
This commit is contained in:
@@ -85,13 +85,16 @@
|
||||
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:date];
|
||||
|
||||
if (interval < 60) {
|
||||
return @"刚刚";
|
||||
return KBLocalized(@"Just now");
|
||||
} else if (interval < 3600) {
|
||||
return [NSString stringWithFormat:@"%.0f分钟前", interval / 60];
|
||||
return [NSString stringWithFormat:KBLocalized(@"%.0f minutes ago"),
|
||||
interval / 60];
|
||||
} else if (interval < 86400) {
|
||||
return [NSString stringWithFormat:@"%.0f小时前", interval / 3600];
|
||||
return [NSString stringWithFormat:KBLocalized(@"%.0f hours ago"),
|
||||
interval / 3600];
|
||||
} else if (interval < 86400 * 30) {
|
||||
return [NSString stringWithFormat:@"%.0f天前", interval / 86400];
|
||||
return [NSString stringWithFormat:KBLocalized(@"%.0f days ago"),
|
||||
interval / 86400];
|
||||
} else {
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.dateFormat = @"MM-dd";
|
||||
|
||||
@@ -68,13 +68,16 @@
|
||||
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:date];
|
||||
|
||||
if (interval < 60) {
|
||||
return @"刚刚";
|
||||
return KBLocalized(@"Just now");
|
||||
} else if (interval < 3600) {
|
||||
return [NSString stringWithFormat:@"%.0f分钟前", interval / 60];
|
||||
return [NSString stringWithFormat:KBLocalized(@"%.0f minutes ago"),
|
||||
interval / 60];
|
||||
} else if (interval < 86400) {
|
||||
return [NSString stringWithFormat:@"%.0f小时前", interval / 3600];
|
||||
return [NSString stringWithFormat:KBLocalized(@"%.0f hours ago"),
|
||||
interval / 3600];
|
||||
} else if (interval < 86400 * 30) {
|
||||
return [NSString stringWithFormat:@"%.0f天前", interval / 86400];
|
||||
return [NSString stringWithFormat:KBLocalized(@"%.0f days ago"),
|
||||
interval / 86400];
|
||||
} else {
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.dateFormat = @"MM-dd";
|
||||
@@ -95,7 +98,8 @@
|
||||
// 用户名高度(可能包含 "回复 @xxx")
|
||||
NSMutableString *userNameText = [NSMutableString stringWithString:self.userName ?: @""];
|
||||
if (self.replyToUserName.length > 0) {
|
||||
[userNameText appendFormat:@" 回复 @%@", self.replyToUserName];
|
||||
[userNameText appendFormat:@" %@ @%@", KBLocalized(@"Reply"),
|
||||
self.replyToUserName];
|
||||
}
|
||||
UIFont *userNameFont = [UIFont systemFontOfSize:13 weight:UIFontWeightMedium];
|
||||
CGRect userNameRect = [userNameText boundingRectWithSize:CGSizeMake(contentWidth, CGFLOAT_MAX)
|
||||
|
||||
@@ -58,10 +58,12 @@
|
||||
formatter.dateFormat = @"HH:mm";
|
||||
} else if ([calendar isDateInYesterday:timestamp]) {
|
||||
// 昨天
|
||||
formatter.dateFormat = @"'昨天' HH:mm";
|
||||
formatter.dateFormat = @"HH:mm";
|
||||
NSString *timeText = [formatter stringFromDate:timestamp];
|
||||
return [NSString stringWithFormat:@"%@ %@", KBLocalized(@"Yesterday"), timeText];
|
||||
} else {
|
||||
// 其他:显示日期 + 时间
|
||||
formatter.dateFormat = @"MM月dd日 HH:mm";
|
||||
formatter.dateFormat = @"MM-dd HH:mm";
|
||||
}
|
||||
|
||||
return [formatter stringFromDate:timestamp];
|
||||
|
||||
@@ -61,8 +61,8 @@
|
||||
}
|
||||
case KBAIReplyFooterStateExpand: {
|
||||
self.actionButton.hidden = NO;
|
||||
title = [NSString
|
||||
stringWithFormat:@"展开%ld条回复", (long)comment.totalReplyCount];
|
||||
title = [NSString stringWithFormat:KBLocalized(@"View %ld replies"),
|
||||
(long)comment.totalReplyCount];
|
||||
[self.actionButton setImage:[UIImage systemImageNamed:@"chevron.down"]
|
||||
forState:UIControlStateNormal];
|
||||
break;
|
||||
@@ -71,15 +71,15 @@
|
||||
self.actionButton.hidden = NO;
|
||||
NSInteger remaining =
|
||||
comment.totalReplyCount - comment.displayedReplies.count;
|
||||
title =
|
||||
[NSString stringWithFormat:@"展开更多回复(%ld条)", (long)remaining];
|
||||
title = [NSString stringWithFormat:KBLocalized(@"View more replies (%ld)"),
|
||||
(long)remaining];
|
||||
[self.actionButton setImage:[UIImage systemImageNamed:@"chevron.down"]
|
||||
forState:UIControlStateNormal];
|
||||
break;
|
||||
}
|
||||
case KBAIReplyFooterStateCollapse: {
|
||||
self.actionButton.hidden = NO;
|
||||
title = @"收起";
|
||||
title = KBLocalized(@"Collapse");
|
||||
[self.actionButton setImage:[UIImage systemImageNamed:@"chevron.up"]
|
||||
forState:UIControlStateNormal];
|
||||
break;
|
||||
|
||||
@@ -94,8 +94,9 @@
|
||||
self.timeLabel.text = [comment formattedTime];
|
||||
|
||||
// 点赞按钮
|
||||
NSString *likeText =
|
||||
comment.likeCount > 0 ? [self formatLikeCount:comment.likeCount] : @"赞";
|
||||
NSString *likeText = comment.likeCount > 0
|
||||
? [self formatLikeCount:comment.likeCount]
|
||||
: KBLocalized(@"Like");
|
||||
self.likeButton.textLabel.text = likeText;
|
||||
|
||||
UIImage *likeImage = comment.liked
|
||||
@@ -174,7 +175,7 @@
|
||||
if (!_replyButton) {
|
||||
_replyButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_replyButton.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
[_replyButton setTitle:@"回复" forState:UIControlStateNormal];
|
||||
[_replyButton setTitle:KBLocalized(@"Reply") forState:UIControlStateNormal];
|
||||
[_replyButton setTitleColor:[UIColor colorWithHex:0x9F9F9F] forState:UIControlStateNormal];
|
||||
[_replyButton addTarget:self
|
||||
action:@selector(replyButtonTapped)
|
||||
|
||||
@@ -35,23 +35,23 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
|
||||
@property(nonatomic, strong) NSMutableArray<KBAICommentModel *> *comments;
|
||||
|
||||
/// 分页参数
|
||||
/// Pagination params
|
||||
@property(nonatomic, assign) NSInteger currentPage;
|
||||
@property(nonatomic, assign) NSInteger pageSize;
|
||||
@property(nonatomic, assign) BOOL isLoading;
|
||||
@property(nonatomic, assign) BOOL hasMoreData;
|
||||
|
||||
/// 键盘高度
|
||||
/// Keyboard height
|
||||
@property(nonatomic, assign) CGFloat keyboardHeight;
|
||||
/// 输入框底部约束
|
||||
/// Bottom constraint for input view
|
||||
@property(nonatomic, strong) MASConstraint *inputBottomConstraint;
|
||||
|
||||
/// 当前回复的目标(一级评论)
|
||||
/// Current reply target (top-level comment)
|
||||
@property(nonatomic, weak) KBAICommentModel *replyToComment;
|
||||
/// 当前回复的目标(二级评论)
|
||||
/// Current reply target (reply)
|
||||
@property(nonatomic, weak) KBAIReplyModel *replyToReply;
|
||||
|
||||
/// AiVM 实例
|
||||
/// AiVM instance
|
||||
@property(nonatomic, strong) AiVM *aiVM;
|
||||
|
||||
@end
|
||||
@@ -65,7 +65,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
if (user.nickName.length > 0) {
|
||||
return user.nickName;
|
||||
}
|
||||
return @"我";
|
||||
return KBLocalized(@"Me");
|
||||
}
|
||||
|
||||
- (NSString *)currentUserId {
|
||||
@@ -80,7 +80,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
|
||||
- (NSString *)generateTempIdString {
|
||||
long long ms = (long long)([[NSDate date] timeIntervalSince1970] * 1000.0);
|
||||
// 使用负数避免与后端 ID 冲突
|
||||
// Use negative values to avoid colliding with server IDs
|
||||
long long tmp = -ms;
|
||||
return [NSString stringWithFormat:@"%lld", tmp];
|
||||
}
|
||||
@@ -155,13 +155,13 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
#pragma mark - UI Setup
|
||||
|
||||
- (void)setupUI {
|
||||
// 设置背景为透明,让模糊效果可见
|
||||
// Make background transparent so blur effect is visible
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.layer.cornerRadius = 12;
|
||||
self.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
|
||||
self.clipsToBounds = YES;
|
||||
|
||||
// 添加模糊背景(最底层)
|
||||
// Add blur background (bottom-most layer)
|
||||
[self addSubview:self.blurBackgroundView];
|
||||
[self.blurBackgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
@@ -201,7 +201,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
make.bottom.equalTo(self.inputView.mas_top);
|
||||
}];
|
||||
|
||||
// 上拉加载更多
|
||||
// Load more on pull-up
|
||||
__weak typeof(self) weakSelf = self;
|
||||
MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
@@ -302,7 +302,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
|
||||
- (void)fetchCommentsAtPage:(NSInteger)page append:(BOOL)append {
|
||||
if (self.companionId <= 0) {
|
||||
NSLog(@"[KBAICommentView] companionId 未设置,无法加载评论");
|
||||
NSLog(@"[KBAICommentView] companionId is not set, cannot load comments");
|
||||
[self showEmptyState];
|
||||
[self.tableView.mj_footer endRefreshing];
|
||||
return;
|
||||
@@ -323,7 +323,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
strongSelf.isLoading = NO;
|
||||
|
||||
if (error) {
|
||||
NSLog(@"[KBAICommentView] 加载评论失败:%@", error.localizedDescription);
|
||||
NSLog(@"[KBAICommentView] Failed to load comments: %@", error.localizedDescription);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (append) {
|
||||
[strongSelf.tableView.mj_footer endRefreshing];
|
||||
@@ -340,11 +340,11 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
}];
|
||||
}
|
||||
|
||||
/// 更新评论数据(从后端返回的 KBCommentPageModel 转换为 UI 层的 KBAICommentModel)
|
||||
/// Update comments (convert backend KBCommentPageModel to UI KBAICommentModel)
|
||||
- (void)updateCommentsWithPageModel:(KBCommentPageModel *)pageModel append:(BOOL)append {
|
||||
if (!pageModel) {
|
||||
NSLog(@"[KBAICommentView] pageModel 为空");
|
||||
// 数据为空,显示空态
|
||||
NSLog(@"[KBAICommentView] pageModel is nil");
|
||||
// Data is empty, show empty state
|
||||
[self showEmptyState];
|
||||
[self.tableView.mj_footer endRefreshing];
|
||||
return;
|
||||
@@ -356,19 +356,20 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
[self.comments removeAllObjects];
|
||||
}
|
||||
|
||||
// 获取 tableView 宽度用于计算高度
|
||||
// Get tableView width for height calculation
|
||||
CGFloat tableWidth = self.tableView.bounds.size.width;
|
||||
if (tableWidth <= 0) {
|
||||
tableWidth = [UIScreen mainScreen].bounds.size.width;
|
||||
}
|
||||
|
||||
NSLog(@"[KBAICommentView] 加载到 %ld 条评论,共 %ld 条,页码:%ld/%ld", (long)pageModel.records.count, (long)pageModel.total, (long)pageModel.current, (long)pageModel.pages);
|
||||
NSLog(@"[KBAICommentView] Loaded %ld comments, total %ld, page: %ld/%ld", (long)pageModel.records.count, (long)pageModel.total, (long)pageModel.current, (long)pageModel.pages);
|
||||
|
||||
for (KBCommentItem *item in pageModel.records) {
|
||||
// 转换为 KBAICommentModel(使用 MJExtension)
|
||||
// 注意:KBCommentItem 通过 MJExtension 将后端字段 id 映射为了 commentId。
|
||||
// 这里如果直接用 mj_keyValues,会导致字典里只有 commentId,KBAICommentModel/KBAIReplyModel
|
||||
// 的映射(commentId/replyId -> id)拿不到值,最终 commentId/replyId 为空,进而影响发送回复时的 parentId/rootId。
|
||||
// Convert to KBAICommentModel (via MJExtension)
|
||||
// Note: KBCommentItem maps backend field id to commentId via MJExtension.
|
||||
// If we directly use mj_keyValues, the dictionary only has commentId and
|
||||
// KBAICommentModel/KBAIReplyModel mapping (commentId/replyId -> id) misses it.
|
||||
// That would make commentId/replyId empty and break parentId/rootId when replying.
|
||||
NSMutableDictionary *itemKV = [[item mj_keyValues] mutableCopy];
|
||||
id commentIdVal = itemKV[@"commentId"];
|
||||
if (commentIdVal) {
|
||||
@@ -397,10 +398,10 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
|
||||
KBAICommentModel *comment = [KBAICommentModel mj_objectWithKeyValues:[itemKV copy]];
|
||||
|
||||
// 预先计算并缓存 Header 高度
|
||||
// Precompute and cache header height
|
||||
comment.cachedHeaderHeight = [comment calculateHeaderHeightWithMaxWidth:tableWidth];
|
||||
|
||||
// 预先计算并缓存所有 Reply 高度
|
||||
// Precompute and cache all reply heights
|
||||
for (KBAIReplyModel *reply in comment.replies) {
|
||||
reply.cachedCellHeight = [reply calculateCellHeightWithMaxWidth:tableWidth];
|
||||
}
|
||||
@@ -411,7 +412,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
[self updateTitle];
|
||||
[self.tableView reloadData];
|
||||
|
||||
// 更新分页状态
|
||||
// Update pagination state
|
||||
self.currentPage = pageModel.current > 0 ? pageModel.current : self.currentPage;
|
||||
if (pageModel.pages > 0) {
|
||||
self.hasMoreData = pageModel.current < pageModel.pages;
|
||||
@@ -425,7 +426,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
[self.tableView.mj_footer endRefreshingWithNoMoreData];
|
||||
}
|
||||
|
||||
// 根据数据是否为空,动态控制空态显示
|
||||
// Toggle empty state based on data
|
||||
if (self.comments.count == 0) {
|
||||
[self showEmptyState];
|
||||
} else {
|
||||
@@ -433,25 +434,25 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
}
|
||||
}
|
||||
|
||||
/// 显示空态视图
|
||||
/// Show empty state view
|
||||
- (void)showEmptyState {
|
||||
self.tableView.useEmptyDataSet = YES;
|
||||
self.tableView.emptyTitleText = @"暂无评论";
|
||||
self.tableView.emptyDescriptionText = @"快来抢沙发吧~";
|
||||
self.tableView.emptyImage = nil; // 可选:设置空态图片
|
||||
self.tableView.emptyVerticalOffset = -50; // 向上偏移一点
|
||||
self.tableView.emptyTitleText = KBLocalized(@"No comments yet");
|
||||
self.tableView.emptyDescriptionText = KBLocalized(@"Be the first to comment");
|
||||
self.tableView.emptyImage = nil; // Optional: set empty-state image
|
||||
self.tableView.emptyVerticalOffset = -50; // Slight upward offset
|
||||
[self.tableView kb_reloadEmptyDataSet];
|
||||
}
|
||||
|
||||
/// 显示错误空态视图
|
||||
/// Show error empty state view
|
||||
- (void)showEmptyStateWithError {
|
||||
self.tableView.useEmptyDataSet = YES;
|
||||
self.tableView.emptyTitleText = @"加载失败";
|
||||
self.tableView.emptyDescriptionText = @"点击重新加载";
|
||||
self.tableView.emptyTitleText = KBLocalized(@"Load failed");
|
||||
self.tableView.emptyDescriptionText = KBLocalized(@"Tap to retry");
|
||||
self.tableView.emptyImage = nil;
|
||||
self.tableView.emptyVerticalOffset = -50;
|
||||
|
||||
// 点击重新加载
|
||||
// Tap to reload
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self.tableView.emptyDidTapView = ^{
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
@@ -463,7 +464,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
[self.tableView kb_reloadEmptyDataSet];
|
||||
}
|
||||
|
||||
/// 隐藏空态视图
|
||||
/// Hide empty state view
|
||||
- (void)hideEmptyState {
|
||||
self.tableView.useEmptyDataSet = NO;
|
||||
[self.tableView kb_reloadEmptyDataSet];
|
||||
@@ -473,10 +474,10 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
NSString *countText;
|
||||
if (self.totalCommentCount >= 10000) {
|
||||
countText = [NSString
|
||||
stringWithFormat:@"%.1fw条评论", self.totalCommentCount / 10000.0];
|
||||
stringWithFormat:KBLocalized(@"%.1fw comments"), self.totalCommentCount / 10000.0];
|
||||
} else {
|
||||
countText =
|
||||
[NSString stringWithFormat:@"%ld条评论", (long)self.totalCommentCount];
|
||||
[NSString stringWithFormat:KBLocalized(@"%ld comments"), (long)self.totalCommentCount];
|
||||
}
|
||||
self.titleLabel.text = countText;
|
||||
}
|
||||
@@ -510,41 +511,41 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取评论 ID(需要转换为 NSInteger)
|
||||
// Get comment ID (convert to NSInteger)
|
||||
NSInteger commentId = [reply.replyId integerValue];
|
||||
|
||||
// 调用点赞接口
|
||||
// Call like API
|
||||
[strongSelf.aiVM likeCommentWithCommentId:commentId completion:^(KBCommentLikeResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
NSLog(@"[KBAICommentView] 二级评论点赞失败:%@", error.localizedDescription);
|
||||
// TODO: 显示错误提示
|
||||
NSLog(@"[KBAICommentView] Failed to like reply: %@", error.localizedDescription);
|
||||
// TODO: Show error message
|
||||
return;
|
||||
}
|
||||
|
||||
if (response && response.code == 0) {
|
||||
// data = true: 点赞成功,data = false: 取消点赞成功
|
||||
// data = true: liked, data = false: unliked
|
||||
BOOL isNowLiked = response.data;
|
||||
|
||||
// 更新模型状态
|
||||
// Update model state
|
||||
if (isNowLiked) {
|
||||
// 点赞成功:喜欢数+1
|
||||
// Like succeeded: like count +1
|
||||
reply.liked = YES;
|
||||
reply.likeCount = MAX(0, reply.likeCount + 1);
|
||||
NSLog(@"[KBAICommentView] 二级评论点赞成功,ID: %ld", (long)commentId);
|
||||
NSLog(@"[KBAICommentView] Reply liked successfully, ID: %ld", (long)commentId);
|
||||
} else {
|
||||
// 取消点赞成功:喜欢数-1
|
||||
// Unlike succeeded: like count -1
|
||||
reply.liked = NO;
|
||||
reply.likeCount = MAX(0, reply.likeCount - 1);
|
||||
NSLog(@"[KBAICommentView] 二级评论取消点赞成功,ID: %ld", (long)commentId);
|
||||
NSLog(@"[KBAICommentView] Reply unliked successfully, ID: %ld", (long)commentId);
|
||||
}
|
||||
|
||||
// 刷新对应的行
|
||||
// Refresh target row
|
||||
[strongSelf.tableView reloadRowsAtIndexPaths:@[ indexPath ]
|
||||
withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
NSLog(@"[KBAICommentView] 二级评论点赞失败:%@", response.message ?: @"未知错误");
|
||||
// TODO: 显示错误提示
|
||||
NSLog(@"[KBAICommentView] Failed to like reply: %@", response.message ?: @"Unknown error");
|
||||
// TODO: Show error message
|
||||
}
|
||||
});
|
||||
}];
|
||||
@@ -574,41 +575,41 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取评论 ID(需要转换为 NSInteger)
|
||||
// Get comment ID (convert to NSInteger)
|
||||
NSInteger commentId = [comment.commentId integerValue];
|
||||
|
||||
// 调用点赞接口
|
||||
// Call like API
|
||||
[strongSelf.aiVM likeCommentWithCommentId:commentId completion:^(KBCommentLikeResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
NSLog(@"[KBAICommentView] 一级评论点赞失败:%@", error.localizedDescription);
|
||||
// TODO: 显示错误提示
|
||||
NSLog(@"[KBAICommentView] Failed to like top-level comment: %@", error.localizedDescription);
|
||||
// TODO: Show error message
|
||||
return;
|
||||
}
|
||||
|
||||
if (response && response.code == 0) {
|
||||
// data = true: 点赞成功,data = false: 取消点赞成功
|
||||
// data = true: liked, data = false: unliked
|
||||
BOOL isNowLiked = response.data;
|
||||
|
||||
// 更新模型状态
|
||||
// Update model state
|
||||
if (isNowLiked) {
|
||||
// 点赞成功:喜欢数+1
|
||||
// Like succeeded: like count +1
|
||||
comment.liked = YES;
|
||||
comment.likeCount = MAX(0, comment.likeCount + 1);
|
||||
NSLog(@"[KBAICommentView] 一级评论点赞成功,ID: %ld", (long)commentId);
|
||||
NSLog(@"[KBAICommentView] Top-level comment liked successfully, ID: %ld", (long)commentId);
|
||||
} else {
|
||||
// 取消点赞成功:喜欢数-1
|
||||
// Unlike succeeded: like count -1
|
||||
comment.liked = NO;
|
||||
comment.likeCount = MAX(0, comment.likeCount - 1);
|
||||
NSLog(@"[KBAICommentView] 一级评论取消点赞成功,ID: %ld", (long)commentId);
|
||||
NSLog(@"[KBAICommentView] Top-level comment unliked successfully, ID: %ld", (long)commentId);
|
||||
}
|
||||
|
||||
// 刷新对应的 section
|
||||
// Refresh target section
|
||||
[strongSelf.tableView reloadSections:[NSIndexSet indexSetWithIndex:section]
|
||||
withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
NSLog(@"[KBAICommentView] 一级评论点赞失败:%@", response.message ?: @"未知错误");
|
||||
// TODO: 显示错误提示
|
||||
NSLog(@"[KBAICommentView] Failed to like top-level comment: %@", response.message ?: @"Unknown error");
|
||||
// TODO: Show error message
|
||||
}
|
||||
});
|
||||
}];
|
||||
@@ -626,7 +627,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
KBAICommentModel *comment = self.comments[section];
|
||||
KBAIReplyFooterState state = [comment footerState];
|
||||
|
||||
// 无二级评论时返回空视图
|
||||
// Return empty view when there are no replies
|
||||
if (state == KBAIReplyFooterStateHidden) {
|
||||
return nil;
|
||||
}
|
||||
@@ -669,7 +670,7 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
|
||||
#pragma mark - Footer Actions
|
||||
|
||||
/// 每次加载的回复数量
|
||||
/// Number of replies loaded each time
|
||||
static NSInteger const kRepliesLoadCount = 5;
|
||||
|
||||
- (void)handleFooterActionForSection:(NSInteger)section {
|
||||
@@ -695,10 +696,10 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
KBAICommentModel *comment = self.comments[section];
|
||||
NSInteger currentCount = comment.displayedReplies.count;
|
||||
|
||||
// 加载更多回复
|
||||
// Load more replies
|
||||
[comment loadMoreReplies:kRepliesLoadCount];
|
||||
|
||||
// 计算新增的行
|
||||
// Calculate newly inserted rows
|
||||
NSInteger newCount = comment.displayedReplies.count;
|
||||
NSMutableArray *insertIndexPaths = [NSMutableArray array];
|
||||
for (NSInteger i = currentCount; i < newCount; i++) {
|
||||
@@ -706,7 +707,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
inSection:section]];
|
||||
}
|
||||
|
||||
// 插入行(不刷新 Header,避免头像闪烁)
|
||||
// Insert rows (do not refresh header to avoid avatar flicker)
|
||||
[self.tableView beginUpdates];
|
||||
if (insertIndexPaths.count > 0) {
|
||||
[self.tableView insertRowsAtIndexPaths:insertIndexPaths
|
||||
@@ -714,7 +715,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
}
|
||||
[self.tableView endUpdates];
|
||||
|
||||
// 手动刷新 Footer
|
||||
// Manually refresh footer
|
||||
KBAICommentFooterView *footerView =
|
||||
(KBAICommentFooterView *)[self.tableView footerViewForSection:section];
|
||||
if (footerView) {
|
||||
@@ -726,17 +727,17 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
KBAICommentModel *comment = self.comments[section];
|
||||
NSInteger rowCount = comment.displayedReplies.count;
|
||||
|
||||
// 计算要删除的行
|
||||
// Calculate rows to delete
|
||||
NSMutableArray *deleteIndexPaths = [NSMutableArray array];
|
||||
for (NSInteger i = 0; i < rowCount; i++) {
|
||||
[deleteIndexPaths addObject:[NSIndexPath indexPathForRow:i
|
||||
inSection:section]];
|
||||
}
|
||||
|
||||
// 收起全部回复
|
||||
// Collapse all replies
|
||||
[comment collapseReplies];
|
||||
|
||||
// 删除行(不刷新 Header,避免头像闪烁)
|
||||
// Delete rows (do not refresh header to avoid avatar flicker)
|
||||
[self.tableView beginUpdates];
|
||||
if (deleteIndexPaths.count > 0) {
|
||||
[self.tableView deleteRowsAtIndexPaths:deleteIndexPaths
|
||||
@@ -744,7 +745,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
}
|
||||
[self.tableView endUpdates];
|
||||
|
||||
// 手动刷新 Footer
|
||||
// Manually refresh footer
|
||||
KBAICommentFooterView *footerView =
|
||||
(KBAICommentFooterView *)[self.tableView footerViewForSection:section];
|
||||
if (footerView) {
|
||||
@@ -756,7 +757,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
|
||||
- (void)closeButtonTapped {
|
||||
[self.popView dismiss];
|
||||
// 关闭评论视图(由外部处理)
|
||||
// Close comment view (handled by outside)
|
||||
// [[NSNotificationCenter defaultCenter]
|
||||
// postNotificationName:@"KBAICommentViewCloseNotification"
|
||||
// object:nil];
|
||||
@@ -766,13 +767,13 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
|
||||
- (UIVisualEffectView *)blurBackgroundView {
|
||||
if (!_blurBackgroundView) {
|
||||
// 创建模糊效果(43pt 的模糊半径)
|
||||
// iOS 的 UIBlurEffect 没有直接设置模糊半径的 API,使用系统预设的 dark 效果
|
||||
// Create blur effect (43pt blur radius in design)
|
||||
// iOS UIBlurEffect has no direct blur-radius API; use system dark style
|
||||
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
_blurBackgroundView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
|
||||
|
||||
// 在模糊效果上叠加一个半透明黑色遮罩来调整透明度和颜色
|
||||
// 颜色:#000000,透明度:0.31
|
||||
// Overlay a semi-transparent black layer to tune tone and opacity
|
||||
// Color: #000000, alpha: 0.31
|
||||
UIView *darkOverlay = [[UIView alloc] init];
|
||||
darkOverlay.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.31];
|
||||
[_blurBackgroundView.contentView addSubview:darkOverlay];
|
||||
@@ -796,7 +797,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
_titleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium];
|
||||
_titleLabel.textColor = [UIColor whiteColor];
|
||||
_titleLabel.text = @"0条评论";
|
||||
_titleLabel.text = [NSString stringWithFormat:KBLocalized(@"%ld comments"), (long)0];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
@@ -824,10 +825,10 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
_tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
|
||||
_tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 0.01)];
|
||||
|
||||
// 关闭空数据占位,避免加载时显示"暂无数据"
|
||||
// Disable empty placeholder by default to avoid showing "No data" while loading
|
||||
_tableView.useEmptyDataSet = NO;
|
||||
|
||||
// 注册 Header/Cell/Footer
|
||||
// Register Header/Cell/Footer
|
||||
[_tableView registerClass:[KBAICommentHeaderView class]
|
||||
forHeaderFooterViewReuseIdentifier:kCommentHeaderIdentifier];
|
||||
[_tableView registerClass:[KBAIReplyCell class]
|
||||
@@ -835,7 +836,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
[_tableView registerClass:[KBAICommentFooterView class]
|
||||
forHeaderFooterViewReuseIdentifier:kCommentFooterIdentifier];
|
||||
|
||||
// 去掉顶部间距
|
||||
// Remove top padding
|
||||
if (@available(iOS 15.0, *)) {
|
||||
_tableView.sectionHeaderTopPadding = 0;
|
||||
}
|
||||
@@ -846,7 +847,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
- (KBAICommentInputView *)inputView {
|
||||
if (!_inputView) {
|
||||
_inputView = [[KBAICommentInputView alloc] init];
|
||||
_inputView.placeholder = @"Send A Message";
|
||||
_inputView.placeholder = KBLocalized(@"Send A Message");
|
||||
_inputView.layer.cornerRadius = 26;
|
||||
_inputView.clipsToBounds = true;
|
||||
__weak typeof(self) weakSelf = self;
|
||||
@@ -865,26 +866,26 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
self.replyToReply = reply;
|
||||
|
||||
if (reply) {
|
||||
// 回复二级评论
|
||||
// Reply to a second-level comment
|
||||
self.inputView.placeholder =
|
||||
[NSString stringWithFormat:@"回复 @%@", reply.userName];
|
||||
[NSString stringWithFormat:KBLocalized(@"Reply to @%@"), reply.userName];
|
||||
} else if (comment) {
|
||||
// 回复一级评论
|
||||
// Reply to a top-level comment
|
||||
self.inputView.placeholder =
|
||||
[NSString stringWithFormat:@"回复 @%@", comment.userName];
|
||||
[NSString stringWithFormat:KBLocalized(@"Reply to @%@"), comment.userName];
|
||||
} else {
|
||||
// 普通评论
|
||||
self.inputView.placeholder = @"说点什么...";
|
||||
// New comment
|
||||
self.inputView.placeholder = KBLocalized(@"Say something...");
|
||||
}
|
||||
|
||||
// 弹起键盘
|
||||
// Show keyboard
|
||||
[self.inputView showKeyboard];
|
||||
}
|
||||
|
||||
- (void)clearReplyTarget {
|
||||
self.replyToComment = nil;
|
||||
self.replyToReply = nil;
|
||||
self.inputView.placeholder = @"说点什么...";
|
||||
self.inputView.placeholder = KBLocalized(@"Say something...");
|
||||
}
|
||||
|
||||
#pragma mark - Send Comment
|
||||
@@ -899,20 +900,20 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
}
|
||||
|
||||
if (self.replyToComment) {
|
||||
// 回复评论(添加二级评论)
|
||||
// Send reply (add second-level comment)
|
||||
[self sendReplyWithText:text tableWidth:tableWidth];
|
||||
} else {
|
||||
// 发送一级评论
|
||||
// Send top-level comment
|
||||
[self sendNewCommentWithText:text tableWidth:tableWidth];
|
||||
}
|
||||
|
||||
// 清空输入框和回复目标
|
||||
// Clear input and reply target
|
||||
[self.inputView clearText];
|
||||
[self clearReplyTarget];
|
||||
}
|
||||
|
||||
- (void)sendNewCommentWithText:(NSString *)text tableWidth:(CGFloat)tableWidth {
|
||||
NSLog(@"[KBAICommentView] 发送一级评论:%@", text);
|
||||
NSLog(@"[KBAICommentView] Send top-level comment: %@", text);
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self.aiVM addCommentWithCompanionId:self.companionId
|
||||
@@ -927,11 +928,11 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error || code != 0) {
|
||||
NSLog(@"[KBAICommentView] 发送一级评论失败:%@", error.localizedDescription ?: @"");
|
||||
NSLog(@"[KBAICommentView] Failed to send top-level comment: %@", error.localizedDescription ?: @"");
|
||||
return;
|
||||
}
|
||||
|
||||
// 本地插入新评论到第一条,不再全量刷新
|
||||
// Insert new comment locally at first position; avoid full reload
|
||||
KBAICommentModel *localComment =
|
||||
[strongSelf buildLocalNewCommentWithText:text
|
||||
serverItem:newItem
|
||||
@@ -954,29 +955,29 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
});
|
||||
}];
|
||||
|
||||
// 示例代码:
|
||||
// Example code:
|
||||
// [self.aiVM sendCommentWithCompanionId:self.companionId
|
||||
// content:text
|
||||
// completion:^(KBCommentItem *newItem, NSError *error) {
|
||||
// if (error) {
|
||||
// NSLog(@"[KBAICommentView] 发送评论失败:%@", error.localizedDescription);
|
||||
// NSLog(@"[KBAICommentView] Failed to send comment: %@", error.localizedDescription);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 转换为 KBAICommentModel
|
||||
// // Convert to KBAICommentModel
|
||||
// KBAICommentModel *comment = [KBAICommentModel mj_objectWithKeyValues:[newItem mj_keyValues]];
|
||||
// comment.cachedHeaderHeight = [comment calculateHeaderHeightWithMaxWidth:tableWidth];
|
||||
//
|
||||
// // 插入到数组第一个
|
||||
// // Insert into array at index 0
|
||||
// [self.comments insertObject:comment atIndex:0];
|
||||
// self.totalCommentCount++;
|
||||
// [self updateTitle];
|
||||
//
|
||||
// // 插入新 section
|
||||
// // Insert new section
|
||||
// [self.tableView insertSections:[NSIndexSet indexSetWithIndex:0]
|
||||
// withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
//
|
||||
// // 滚动到顶部
|
||||
// // Scroll to top
|
||||
// [self.tableView setContentOffset:CGPointZero animated:YES];
|
||||
// }];
|
||||
}
|
||||
@@ -986,7 +987,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
if (!comment)
|
||||
return;
|
||||
|
||||
NSLog(@"[KBAICommentView] 回复评论 %@:%@", comment.commentId, text);
|
||||
NSLog(@"[KBAICommentView] Reply to comment %@: %@", comment.commentId, text);
|
||||
|
||||
NSInteger root = [comment.commentId integerValue];
|
||||
NSNumber *rootId = @(root);
|
||||
@@ -1011,7 +1012,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error || code != 0) {
|
||||
NSLog(@"[KBAICommentView] 回复评论失败:%@", error.localizedDescription ?: @"");
|
||||
NSLog(@"[KBAICommentView] Failed to send reply: %@", error.localizedDescription ?: @"");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1051,7 +1052,7 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
[strongSelf.delegate commentView:strongSelf didUpdateTotalCommentCount:strongSelf.totalCommentCount];
|
||||
}
|
||||
|
||||
// 若当前已完整展开,则直接插入新行;否则保持 displayedReplies 为前缀,避免破坏 loadMoreReplies 逻辑
|
||||
// If fully expanded, insert new row directly; otherwise keep displayedReplies as prefix to preserve loadMoreReplies behavior
|
||||
if (wasFullyExpanded) {
|
||||
[comment.displayedReplies addObject:localReply];
|
||||
NSInteger newRowIndex = comment.displayedReplies.count - 1;
|
||||
@@ -1085,31 +1086,31 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
});
|
||||
}];
|
||||
|
||||
// 示例代码:
|
||||
// Example code:
|
||||
// NSInteger parentId = [comment.commentId integerValue];
|
||||
// [self.aiVM replyCommentWithParentId:parentId
|
||||
// content:text
|
||||
// completion:^(KBCommentItem *newItem, NSError *error) {
|
||||
// if (error) {
|
||||
// NSLog(@"[KBAICommentView] 回复评论失败:%@", error.localizedDescription);
|
||||
// NSLog(@"[KBAICommentView] Failed to reply comment: %@", error.localizedDescription);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 转换为 KBAIReplyModel
|
||||
// // Convert to KBAIReplyModel
|
||||
// KBAIReplyModel *newReply = [KBAIReplyModel mj_objectWithKeyValues:[newItem mj_keyValues]];
|
||||
// newReply.cachedCellHeight = [newReply calculateCellHeightWithMaxWidth:tableWidth];
|
||||
//
|
||||
// // 添加到 replies 数组
|
||||
// // Append to replies array
|
||||
// NSMutableArray *newReplies = [NSMutableArray arrayWithArray:comment.replies];
|
||||
// [newReplies addObject:newReply];
|
||||
// comment.replies = newReplies;
|
||||
// comment.totalReplyCount = newReplies.count;
|
||||
//
|
||||
// // 找到该评论的 section
|
||||
// // Find section for this comment
|
||||
// NSInteger section = [self.comments indexOfObject:comment];
|
||||
// if (section == NSNotFound) return;
|
||||
//
|
||||
// // 如果已展开,添加到 displayedReplies 并插入行
|
||||
// // If expanded, append to displayedReplies and insert row
|
||||
// if (comment.isRepliesExpanded) {
|
||||
// NSInteger newRowIndex = comment.displayedReplies.count;
|
||||
// [comment.displayedReplies addObject:newReply];
|
||||
@@ -1118,18 +1119,18 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
// [self.tableView insertRowsAtIndexPaths:@[indexPath]
|
||||
// withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
//
|
||||
// // 刷新 Footer
|
||||
// // Refresh footer
|
||||
// KBAICommentFooterView *footerView = (KBAICommentFooterView *)[self.tableView footerViewForSection:section];
|
||||
// if (footerView) {
|
||||
// [footerView configureWithComment:comment];
|
||||
// }
|
||||
//
|
||||
// // 滚动到新回复
|
||||
// // Scroll to new reply
|
||||
// [self.tableView scrollToRowAtIndexPath:indexPath
|
||||
// atScrollPosition:UITableViewScrollPositionBottom
|
||||
// animated:YES];
|
||||
// } else {
|
||||
// // 未展开,刷新 Footer 显示新的回复数
|
||||
// // If not expanded, refresh footer to show updated reply count
|
||||
// KBAICommentFooterView *footerView = (KBAICommentFooterView *)[self.tableView footerViewForSection:section];
|
||||
// if (footerView) {
|
||||
// [footerView configureWithComment:comment];
|
||||
|
||||
@@ -108,8 +108,10 @@
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:13],
|
||||
NSForegroundColorAttributeName : [UIColor whiteColor]
|
||||
};
|
||||
NSString *replyText =
|
||||
[NSString stringWithFormat:@" %@ ", KBLocalized(@"Reply")];
|
||||
[attrName appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:@" 回复 "
|
||||
initWithString:replyText
|
||||
attributes:replyAttrs]];
|
||||
|
||||
NSDictionary *toUserAttrs = @{
|
||||
@@ -133,8 +135,9 @@
|
||||
self.timeLabel.text = [reply formattedTime];
|
||||
|
||||
// 点赞
|
||||
NSString *likeText =
|
||||
reply.likeCount > 0 ? [self formatLikeCount:reply.likeCount] : @"赞";
|
||||
NSString *likeText = reply.likeCount > 0
|
||||
? [self formatLikeCount:reply.likeCount]
|
||||
: KBLocalized(@"Like");
|
||||
self.likeButton.textLabel.text = likeText;
|
||||
|
||||
UIImage *likeImage = reply.liked
|
||||
@@ -212,7 +215,7 @@
|
||||
if (!_replyButton) {
|
||||
_replyButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_replyButton.titleLabel.font = [UIFont systemFontOfSize:11];
|
||||
[_replyButton setTitle:@"回复" forState:UIControlStateNormal];
|
||||
[_replyButton setTitle:KBLocalized(@"Reply") forState:UIControlStateNormal];
|
||||
[_replyButton setTitleColor:[UIColor colorWithHex:0x9F9F9F] forState:UIControlStateNormal];
|
||||
[_replyButton addTarget:self
|
||||
action:@selector(replyButtonTapped)
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
|
||||
- (void)setup {
|
||||
_state = KBAiRecordButtonStateNormal;
|
||||
_normalTitle = @"按住说话";
|
||||
_recordingTitle = @"松开结束";
|
||||
_normalTitle = KBLocalized(@"Hold To Speak");
|
||||
_recordingTitle = KBLocalized(@"Release To Finish");
|
||||
_tintColor = [UIColor systemBlueColor];
|
||||
|
||||
// 背景视图
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
- (UILabel *)statusLabel {
|
||||
if (!_statusLabel) {
|
||||
_statusLabel = [[UILabel alloc] init];
|
||||
_statusLabel.text = @"按住按钮开始对话";
|
||||
_statusLabel.text = KBLocalized(@"Hold To Start Talking");
|
||||
_statusLabel.font = [UIFont systemFontOfSize:14];
|
||||
_statusLabel.textColor = [UIColor secondaryLabelColor];
|
||||
_statusLabel.textAlignment = NSTextAlignmentCenter;
|
||||
@@ -310,8 +310,8 @@
|
||||
if (!_recordButton) {
|
||||
_recordButton = [[KBAiRecordButton alloc] init];
|
||||
_recordButton.delegate = self;
|
||||
_recordButton.normalTitle = @"按住说话";
|
||||
_recordButton.recordingTitle = @"松开结束";
|
||||
_recordButton.normalTitle = KBLocalized(@"Hold To Speak");
|
||||
_recordButton.recordingTitle = KBLocalized(@"Release To Finish");
|
||||
_recordButton.normalIconImage = [UIImage imageNamed:@"ai_jianpan_icon"];
|
||||
_recordButton.recordingIconImage = [UIImage imageNamed:@"ai_luyining_icon"];
|
||||
_recordButton.hidden = YES;
|
||||
@@ -340,7 +340,7 @@
|
||||
- (UIButton *)textCenterButton {
|
||||
if (!_textCenterButton) {
|
||||
_textCenterButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_textCenterButton setTitle:@"发送一个消息给她" forState:UIControlStateNormal];
|
||||
[_textCenterButton setTitle:KBLocalized(@"Send A Message To Her") forState:UIControlStateNormal];
|
||||
_textCenterButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
|
||||
[_textCenterButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
_textCenterButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
|
||||
@@ -362,7 +362,7 @@
|
||||
- (UILabel *)voiceCenterLabel {
|
||||
if (!_voiceCenterLabel) {
|
||||
_voiceCenterLabel = [[UILabel alloc] init];
|
||||
_voiceCenterLabel.text = @"按住说话";
|
||||
_voiceCenterLabel.text = KBLocalized(@"Hold To Speak");
|
||||
_voiceCenterLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
|
||||
_voiceCenterLabel.textColor = [UIColor whiteColor];
|
||||
_voiceCenterLabel.textAlignment = NSTextAlignmentCenter;
|
||||
@@ -526,9 +526,9 @@
|
||||
|
||||
- (void)updateCenterTextIfNeeded {
|
||||
if (self.inputState == KBVoiceInputBarStateText) {
|
||||
[self.textCenterButton setTitle:@"发送一个消息给她" forState:UIControlStateNormal];
|
||||
[self.textCenterButton setTitle:KBLocalized(@"Send A Message To Her") forState:UIControlStateNormal];
|
||||
} else if (self.inputState == KBVoiceInputBarStateVoice) {
|
||||
self.voiceCenterLabel.text = @"按住说话";
|
||||
self.voiceCenterLabel.text = KBLocalized(@"Hold To Speak");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -936,7 +936,7 @@ static void KBChatUpdatedDarwinCallback(CFNotificationCenterRef center,
|
||||
- (KBVoiceInputBar *)voiceInputBar {
|
||||
if (!_voiceInputBar) {
|
||||
_voiceInputBar = [[KBVoiceInputBar alloc] init];
|
||||
_voiceInputBar.statusText = @"按住按钮开始对话";
|
||||
_voiceInputBar.statusText = KBLocalized(@"Hold To Start Talking");
|
||||
}
|
||||
return _voiceInputBar;
|
||||
}
|
||||
@@ -1372,7 +1372,7 @@ static void KBChatUpdatedDarwinCallback(CFNotificationCenterRef center,
|
||||
if (cell) {
|
||||
[cell removeLoadingAssistantMessageWithRequestId:requestId];
|
||||
}
|
||||
NSString *message = response.message ?: @"聊天响应为空";
|
||||
NSString *message = response.message ?: KBLocalized(@"Chat response is empty");
|
||||
NSLog(@"[KBAIHomeVC] 聊天响应为空:%@", message);
|
||||
if (message.length > 0) {
|
||||
[KBHUD showError:message];
|
||||
|
||||
@@ -144,7 +144,7 @@ static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidRe
|
||||
// 创建删除按钮
|
||||
if (!self.deleteButton) {
|
||||
self.deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[self.deleteButton setTitle:@"删除此记录" forState:UIControlStateNormal];
|
||||
[self.deleteButton setTitle:KBLocalized(@"Delete This Record") forState:UIControlStateNormal];
|
||||
[self.deleteButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
self.deleteButton.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
self.deleteButton.backgroundColor = [UIColor colorWithRed:244/255.0 green:67/255.0 blue:54/255.0 alpha:1.0]; // #F44336
|
||||
@@ -317,7 +317,7 @@ static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidRe
|
||||
|
||||
if (error) {
|
||||
NSLog(@"[KBAIMessageChatingVC] 删除失败:%@", error.localizedDescription);
|
||||
[KBHUD showError:@"删除失败,请重试"];
|
||||
[KBHUD showError:KBLocalized(@"Delete failed, please try again")];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidRe
|
||||
NSLog(@"[KBAIMessageChatingVC] ✅ 已发送重置通知:companionId=%ld", (long)companionId);
|
||||
|
||||
// 5. 显示成功提示
|
||||
[KBHUD showSuccess:@"已删除"];
|
||||
[KBHUD showSuccess:KBLocalized(@"Deleted")];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ autoShowBusinessError:NO
|
||||
// 解析响应
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey: message}];
|
||||
@@ -356,7 +356,7 @@ autoShowBusinessError:NO
|
||||
} else {
|
||||
NSError *parseError = [NSError errorWithDomain:@"AiVM"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"数据格式错误"}];
|
||||
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid data format")}];
|
||||
if (completion) {
|
||||
completion(nil, parseError);
|
||||
}
|
||||
@@ -398,7 +398,7 @@ autoShowBusinessError:NO
|
||||
// 解析响应
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey: message}];
|
||||
@@ -418,7 +418,7 @@ autoShowBusinessError:NO
|
||||
} else {
|
||||
NSError *parseError = [NSError errorWithDomain:@"AiVM"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"数据格式错误"}];
|
||||
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid data format")}];
|
||||
if (completion) {
|
||||
completion(nil, parseError);
|
||||
}
|
||||
@@ -463,7 +463,7 @@ autoShowBusinessError:NO
|
||||
if (![json isKindOfClass:[NSDictionary class]]) {
|
||||
NSError *parseError = [NSError errorWithDomain:@"AiVM"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey : @"数据格式错误"}];
|
||||
userInfo:@{NSLocalizedDescriptionKey : KBLocalized(@"Invalid data format")}];
|
||||
if (completion) {
|
||||
completion(NO, parseError);
|
||||
}
|
||||
@@ -472,7 +472,7 @@ autoShowBusinessError:NO
|
||||
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey : message}];
|
||||
@@ -498,7 +498,7 @@ autoShowBusinessError:NO
|
||||
if (content.length == 0) {
|
||||
NSError *error = [NSError errorWithDomain:@"AiVM"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"评论内容不能为空"}];
|
||||
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Comment content cannot be empty")}];
|
||||
if (completion) {
|
||||
completion(nil, -1, error);
|
||||
}
|
||||
@@ -535,7 +535,7 @@ autoShowBusinessError:NO
|
||||
NSLog(@"[AiVM] /ai-companion/comment/add response: %@", json);
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey: message}];
|
||||
@@ -596,7 +596,7 @@ autoShowBusinessError:NO
|
||||
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey: message}];
|
||||
@@ -615,7 +615,7 @@ autoShowBusinessError:NO
|
||||
} else {
|
||||
NSError *parseError = [NSError errorWithDomain:@"AiVM"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"数据格式错误"}];
|
||||
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid data format")}];
|
||||
if (completion) {
|
||||
completion(nil, parseError);
|
||||
}
|
||||
@@ -711,7 +711,7 @@ autoShowBusinessError:NO
|
||||
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey: message}];
|
||||
@@ -755,7 +755,7 @@ autoShowBusinessError:NO
|
||||
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey: message}];
|
||||
@@ -838,7 +838,7 @@ autoShowBusinessError:NO
|
||||
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey: message}];
|
||||
@@ -857,7 +857,7 @@ autoShowBusinessError:NO
|
||||
} else {
|
||||
NSError *parseError = [NSError errorWithDomain:@"AiVM"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"数据格式错误"}];
|
||||
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid data format")}];
|
||||
if (completion) {
|
||||
completion(nil, parseError);
|
||||
}
|
||||
@@ -936,7 +936,7 @@ autoShowBusinessError:NO
|
||||
if (![json isKindOfClass:[NSDictionary class]]) {
|
||||
NSError *parseError = [NSError errorWithDomain:@"AiVM"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey : @"数据格式错误"}];
|
||||
userInfo:@{NSLocalizedDescriptionKey : KBLocalized(@"Invalid data format")}];
|
||||
if (completion) {
|
||||
completion(NO, parseError);
|
||||
}
|
||||
@@ -945,7 +945,7 @@ autoShowBusinessError:NO
|
||||
|
||||
NSInteger code = [json[@"code"] integerValue];
|
||||
if (code != 0) {
|
||||
NSString *message = json[@"message"] ?: @"请求失败";
|
||||
NSString *message = json[@"message"] ?: KBLocalized(@"Request failed");
|
||||
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey : message}];
|
||||
|
||||
Reference in New Issue
Block a user