This commit is contained in:
2026-03-09 17:34:08 +08:00
parent c1ace5f53e
commit 0af7428353
55 changed files with 1630 additions and 665 deletions

View File

@@ -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 commentIdKBAICommentModel/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];
//
// #0000000.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];