Files
keyboard/keyBoard/Class/AiTalk/VC/KBAIMessageChatingVC.m
2026-01-28 18:15:58 +08:00

238 lines
8.0 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 <Masonry/Masonry.h>
@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.longPressIndexPath = indexPath;
// 在手指位置显示删除按钮
[self showDeleteButtonAtPoint:point];
}
}
}
- (void)handleTapGesture:(UITapGestureRecognizer *)gesture {
// 点击其他地方隐藏删除按钮
if (self.deleteButton && !self.deleteButton.hidden) {
CGPoint point = [gesture locationInView:self.view];
CGPoint buttonPoint = [gesture locationInView:self.deleteButton];
// 如果点击的不是删除按钮,则隐藏
if (!CGRectContainsPoint(self.deleteButton.bounds, buttonPoint)) {
[self hideDeleteButton];
}
}
}
- (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) {
// 隐藏按钮
[self hideDeleteButton];
// 执行删除
[self deleteItemAtIndexPath:self.longPressIndexPath];
}
}
#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 - 删除
- (void)deleteItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row >= self.chattedList.count) {
return;
}
// TODO: 如果有删除聊天记录的接口,在这里调用
// 目前先只做本地删除
if (indexPath.row < self.chattedList.count) {
[self.chattedList removeObjectAtIndex:indexPath.row];
}
if (indexPath.row < self.dataArray.count) {
[self.dataArray removeObjectAtIndex:indexPath.row];
}
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}
#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