Files
keyboard/keyBoard/Class/AiTalk/VC/KBAIMessageChatingVC.m
2026-01-28 19:31:27 +08:00

289 lines
10 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// KBAIMessageChatingVC.m
// keyBoard
//
// Created by Mac on 2026/1/28.
//
#import "KBAIMessageChatingVC.h"
#import "AiVM.h"
#import "KBChattedCompanionModel.h"
#import "KBHUD.h"
#import "KBAIChatMessageCacheManager.h"
#import <Masonry/Masonry.h>
/// 聊天会话被重置的通知
static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidResetNotification";
@interface KBAIMessageChatingVC ()
@property (nonatomic, strong) AiVM *viewModel;
@property (nonatomic, strong) NSMutableArray<KBChattedCompanionModel *> *chattedList;
/// 删除按钮
@property (nonatomic, strong) UIButton *deleteButton;
/// 当前长按的 indexPath
@property (nonatomic, strong) NSIndexPath *longPressIndexPath;
@end
@implementation KBAIMessageChatingVC
#pragma mark - Lifecycle
- (void)viewDidLoad {
self.listType = 1; // Chatting
[super viewDidLoad];
// 添加长按手势
[self setupLongPressGesture];
// 添加点击手势,用于隐藏删除按钮
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
tapGesture.cancelsTouchesInView = NO; // 不影响 cell 的点击
[self.tableView addGestureRecognizer:tapGesture];
}
#pragma mark - 手势处理
- (void)setupLongPressGesture {
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
longPress.minimumPressDuration = 0.5; // 长按0.5秒
[self.tableView addGestureRecognizer:longPress];
}
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateBegan) {
CGPoint point = [gesture locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
if (indexPath) {
// 在手指位置显示删除按钮
[self showDeleteButtonAtPoint:point];
// 在 showDeleteButtonAtPoint 之后再设置,避免被 hideDeleteButton 清空
self.longPressIndexPath = indexPath;
}
}
}
- (void)handleTapGesture:(UITapGestureRecognizer *)gesture {
// 点击其他地方隐藏删除按钮
if (self.deleteButton && !self.deleteButton.hidden) {
CGPoint pointInButton = [gesture locationInView:self.deleteButton];
// 如果点击的不是删除按钮,则隐藏
if (!CGRectContainsPoint(self.deleteButton.bounds, pointInButton)) {
NSLog(@"[KBAIMessageChatingVC] 点击了删除按钮外部,隐藏按钮");
[self hideDeleteButton];
} else {
NSLog(@"[KBAIMessageChatingVC] 点击了删除按钮内部,不隐藏");
}
}
}
- (void)showDeleteButtonAtPoint:(CGPoint)point {
// 隐藏之前的按钮
[self hideDeleteButton];
// 创建删除按钮
if (!self.deleteButton) {
self.deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.deleteButton setTitle:@"删除此记录" 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
self.deleteButton.layer.cornerRadius = 6;
self.deleteButton.layer.masksToBounds = YES;
[self.deleteButton addTarget:self action:@selector(deleteButtonTapped) forControlEvents:UIControlEventTouchUpInside];
// 添加阴影效果
self.deleteButton.layer.shadowColor = [UIColor blackColor].CGColor;
self.deleteButton.layer.shadowOffset = CGSizeMake(0, 2);
self.deleteButton.layer.shadowOpacity = 0.3;
self.deleteButton.layer.shadowRadius = 4;
}
// 添加到父视图(确保在最上层)
[self.view addSubview:self.deleteButton];
// 设置按钮大小和位置
CGSize buttonSize = CGSizeMake(110, 40);
// 将 tableView 的坐标转换为父视图坐标
CGPoint pointInView = [self.tableView convertPoint:point toView:self.view];
// 计算按钮位置,确保不超出屏幕
CGFloat buttonX = pointInView.x - buttonSize.width / 2;
CGFloat buttonY = pointInView.y - buttonSize.height - 10; // 在手指上方10px
// 边界检查
CGFloat margin = 10;
if (buttonX < margin) {
buttonX = margin;
} else if (buttonX + buttonSize.width > self.view.bounds.size.width - margin) {
buttonX = self.view.bounds.size.width - buttonSize.width - margin;
}
if (buttonY < KB_NAV_TOTAL_HEIGHT + margin) {
// 如果上方空间不够,显示在手指下方
buttonY = pointInView.y + 10;
}
[self.deleteButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view).offset(buttonX);
make.top.equalTo(self.view).offset(buttonY);
make.width.mas_equalTo(buttonSize.width);
make.height.mas_equalTo(buttonSize.height);
}];
self.deleteButton.hidden = NO;
// 添加弹出动画
self.deleteButton.transform = CGAffineTransformMakeScale(0.3, 0.3);
self.deleteButton.alpha = 0;
[UIView animateWithDuration:0.2 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.deleteButton.transform = CGAffineTransformIdentity;
self.deleteButton.alpha = 1.0;
} completion:nil];
}
- (void)hideDeleteButton {
if (self.deleteButton) {
[UIView animateWithDuration:0.15 animations:^{
self.deleteButton.alpha = 0;
self.deleteButton.transform = CGAffineTransformMakeScale(0.8, 0.8);
} completion:^(BOOL finished) {
self.deleteButton.hidden = YES;
[self.deleteButton removeFromSuperview];
}];
}
self.longPressIndexPath = nil;
}
- (void)deleteButtonTapped {
if (!self.longPressIndexPath) {
return;
}
// 保存 indexPath因为后面会清空
NSIndexPath *indexPath = self.longPressIndexPath;
// 获取要删除的数据
if (indexPath.row >= self.chattedList.count) {
NSLog(@"[KBAIMessageChatingVC] 错误索引越界row=%ld, count=%ld",
(long)indexPath.row, (long)self.chattedList.count);
[self hideDeleteButton];
return;
}
KBChattedCompanionModel *model = self.chattedList[indexPath.row];
NSInteger companionId = model.companionId;
NSLog(@"[KBAIMessageChatingVC] 开始删除聊天记录companionId=%ld, name=%@",
(long)companionId, model.name);
// 隐藏删除按钮
[self hideDeleteButton];
// 显示加载提示
[KBHUD show];
__weak typeof(self) weakSelf = self;
// 调用清空聊天会话的 API
[self.viewModel resetChatSessionWithCompanionId:companionId
completion:^(KBChatSessionResetResponse * _Nullable response, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
[KBHUD dismiss];
if (error) {
NSLog(@"[KBAIMessageChatingVC] 删除失败:%@", error.localizedDescription);
[KBHUD showError:@"删除失败,请重试"];
return;
}
NSLog(@"[KBAIMessageChatingVC] ✅ API 调用成功,开始清理本地数据");
// 1. 删除本地列表数据
if (indexPath.row < weakSelf.chattedList.count) {
[weakSelf.chattedList removeObjectAtIndex:indexPath.row];
}
if (indexPath.row < weakSelf.dataArray.count) {
[weakSelf.dataArray removeObjectAtIndex:indexPath.row];
}
// 2. 更新 TableView带动画
[weakSelf.tableView deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationLeft];
// 3. ✅ 清除缓存管理器中的聊天记录(关键!)
[[KBAIChatMessageCacheManager shared] clearMessagesForCompanionId:companionId];
NSLog(@"[KBAIMessageChatingVC] ✅ 已清除缓存companionId=%ld", (long)companionId);
// 4. 发送通知,通知其他页面(主页)刷新
[[NSNotificationCenter defaultCenter] postNotificationName:KBChatSessionDidResetNotification
object:nil
userInfo:@{@"companionId": @(companionId)}];
NSLog(@"[KBAIMessageChatingVC] ✅ 已发送重置通知companionId=%ld", (long)companionId);
// 5. 显示成功提示
[KBHUD showSuccess:@"已删除"];
});
}];
}
#pragma mark - 2数据加载
- (void)loadData {
[KBHUD show];
__weak typeof(self) weakSelf = self;
[self.viewModel fetchChattedCompanionsWithCompletion:^(NSArray<KBChattedCompanionModel *> * _Nullable list, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
[KBHUD dismiss];
if (error) {
[KBHUD showError:error.localizedDescription];
return;
}
[weakSelf.chattedList removeAllObjects];
if (list.count > 0) {
[weakSelf.chattedList addObjectsFromArray:list];
}
[weakSelf.dataArray removeAllObjects];
// 转换为通用数据格式
for (KBChattedCompanionModel *model in weakSelf.chattedList) {
NSMutableDictionary *item = [NSMutableDictionary dictionary];
item[@"avatar"] = model.avatarUrl ?: @"";
item[@"name"] = model.name ?: @"";
item[@"content"] = model.shortDesc ?: @"";
item[@"time"] = model.createdAt ?: @"";
item[@"isPinned"] = @NO;
item[@"companionId"] = @(model.companionId);
[weakSelf.dataArray addObject:item];
}
[weakSelf.tableView reloadData];
});
}];
}
#pragma mark - Lazy Load
- (AiVM *)viewModel {
if (!_viewModel) {
_viewModel = [[AiVM alloc] init];
}
return _viewModel;
}
- (NSMutableArray<KBChattedCompanionModel *> *)chattedList {
if (!_chattedList) {
_chattedList = [NSMutableArray array];
}
return _chattedList;
}
@end