// // ChatController.m // AIIM // // Created by gan on 2025/4/6. // #import #import #import #import #import #import #import "ChatController.h" #import "FriendController.h" #import "GroupController.h" #import "ChatsStore.h" #import "ChatListStore.h" #import "FriendNetApi.h" #import "FileNetApi.h" #import "GroupNetApi.h" #import "UserNetApi.h" #import "GWebSocket.h" #import "UDManager.h" #import "CryptoAES.h" #import "GDBManager.h" #import "chatpopView.h" #import "config.h" #import "JSGController.h" #import "SDWebImage/SDWebImage.h" #import "ChatMessageModel.h" #import "ChatFileModel.h" #import "AppDelegate.h" #import "HistoryPreloader.h" #import "chatCellView.h" #import "CameraViewController.h" #import "ForwardViewController.h" #import "ChatBatchView.h" #import "ChatQuoteView.h" #import "ChatAtMemberView.h" #import "PopupView.h" #import "MentionTextView.h" #import "TopPopupView.h" #import "OSSManager.h" static const CGFloat kQuoteViewHeight = 46.0f; @interface ChatController() @property (weak, nonatomic) IBOutlet UILabel *titlelb; @property (weak, nonatomic) IBOutlet UITableView *_tableView; @property(nonatomic, strong) MentionTextView *inputView; //@property(nonatomic, strong) UITextView *inputView; @property (weak, nonatomic) IBOutlet UIView *bottonView; @property (weak, nonatomic) IBOutlet UIButton *yuyinctr; @property (weak, nonatomic) IBOutlet UIButton *fasngBt; @property (weak, nonatomic) IBOutlet UIButton *gengduoBt; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *inputViewBottom; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomViewHeight; @property (nonatomic, strong) HistoryPreloader * preloader; //录音 @property(nonatomic, strong) UIButton *AVRecordBt; @property (nonatomic,strong) AVAudioRecorder *recorder; @property (nonatomic,strong) NSString *AudiofilePath; @property (nonatomic,strong) NSString *AudiofileName; @property (nonatomic) NSInteger rcdL; @property (strong, nonatomic) NSTimer *heatBeat; @property (nonatomic,strong) AVPlayer *player; @property (nonatomic) CGFloat keyboardHeight; @property (nonatomic) BOOL isfriend; @property (nonatomic) BOOL keybarShow; @property (nonatomic) BOOL canloadhistory; @property (nonatomic) BOOL canloadhistoryMore; @property (nonatomic) CGFloat offset; @property (nonatomic,strong) NSString *username; @property (nonatomic,strong) NSString *useravatar; @property (nonatomic,strong) UITextView *textV; @property (nonatomic,strong) chatpopView *popView; @property (nonatomic,strong) UIView *markView; @property (nonatomic, strong) ChatBatchView * batchView; @property (nonatomic, strong) ChatQuoteView * quoteView; @property (nonatomic, assign) BOOL isQuoteMessage; @property (strong, nonatomic) NSTimer *timer; @property (nonatomic, strong) NSDictionary * groupInfo; @property (nonatomic,strong) NSMutableArray *messageArray; @property (nonatomic, strong) NSMutableArray * forwordMsgArray; @property (nonatomic, strong) NSMutableArray * atSomeoneArray; @property (nonatomic, assign) BOOL isBatchMode; @property (nonatomic, assign) BOOL showLoading; @end @implementation ChatController - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } -(void)viewDidLoad{ [super viewDidLoad]; [self.navigationController setNavigationBarHidden:YES animated:NO]; [self._tableView registerClass:chatCellView.class forCellReuseIdentifier:@"chatCellView"]; self._tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self._tableView.backgroundColor = [UIColor clearColor]; self._tableView.delegate=self; self._tableView.dataSource = self; _isfriend=true; CGFloat safeBottom = [UIDevice safeDistanceBottom]; UIView *temp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 60+safeBottom)]; temp.backgroundColor = UIColor.blackColor; [_bottonView insertSubview:temp atIndex:0]; //输入框 _inputView = [[MentionTextView alloc] initWithFrame:CGRectMake(54, 10, self.view.frame.size.width - 180, 40)]; _inputView.backgroundColor = globalColor(GCTypeDark2); _inputView.layer.cornerRadius = 4.0; _inputView.textColor = [UIColor blackColor]; _inputView.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; [_bottonView addSubview:_inputView]; _inputView.delegate = self; // 设置代理 _inputView.scrollEnabled = NO; // 禁止滚动,使内容自适应高度 [_inputView setup]; //删除@用户名 weakSelf(self); _inputView.mentionDeleteHandler = ^(NSString * _Nonnull deletedMention, NSUInteger index) { // NSLog(@"第%ld---%@",index,deletedMention); // NSLog(@"weakself.atSomeoneArray:%@",weakself.atSomeoneArray); if ([deletedMention isEqualToString:@"@所有人"]) { return; } [weakself removeAtList:index]; }; [_inputView mas_makeConstraints:^(MASConstraintMaker *make) { // make.height.mas_equalTo(40); make.left.equalTo(self.yuyinctr.mas_right).mas_offset(10); make.right.equalTo(self.gengduoBt.mas_left).mas_offset(-10); make.bottom.mas_offset(-10); make.top.mas_offset(10); }]; //录音按钮 _AVRecordBt = [[UIButton alloc] initWithFrame:CGRectMake(54, 10, self.view.frame.size.width - 180, 40)]; [_bottonView addSubview:_AVRecordBt]; _AVRecordBt.alpha = 0; _AVRecordBt.layer.backgroundColor = globalColor(GCTypeDark2).CGColor; _AVRecordBt.layer.cornerRadius = 4.0; [_AVRecordBt setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [_AVRecordBt setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft]; [_AVRecordBt setTitle:@" 按住 说话" forState:UIControlStateNormal]; [_AVRecordBt addTarget:self action:@selector(longTarget) forControlEvents:UIControlEventTouchDown]; [_AVRecordBt addTarget:self action:@selector(UpInside) forControlEvents:UIControlEventTouchUpInside]; [self.bottonView addSubview:self.quoteView]; [self.quoteView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(_inputView.mas_left); make.size.mas_equalTo(CGSizeMake(SCREEN_WIDTH-180, 30)); make.top.mas_equalTo(self.inputView.mas_bottom).offset(8); }]; // 注册键盘显示通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; // 注册键盘隐藏通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; //nkonNewMessageNote [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(othersChatMessageAlert:) name:nkonNewMessageNote object:nil]; [self inidatastate]; _textV=[[UITextView alloc] init]; _markView=[[UIView alloc] init]; [self.view addSubview:_markView]; NSArray *nibs = [[NSBundle mainBundle] loadNibNamed:@"chatpopView" owner:self options:nil]; _popView = [nibs objectAtIndex:0]; [self.view addSubview:_popView]; _popView.delegate= self; [self initpopbottonView]; [self setupPreloader]; NSDictionary *userinfo = [UDManager.shareInstance getDDManager:dkuserinfo]; NSLog(@"viewDidLoad userinfo:%@",userinfo); self.userId = userinfo[@"id"]; self.username = userinfo[@"name"]; self.useravatar = userinfo[@"avatar"]; ChatsStore.shareInstance.delegate = self; ChatsStore.shareInstance.chatId = self.chatId; ChatsStore.shareInstance.userid =self.userId; ChatListStore.shareInstance.chatId = self.chatId; [ChatsStore.shareInstance getchatReadTime:self.chatId]; [OSSManager sharedManager].delegate = self; _showLoading = YES; NSString *type=@""; if(self.type==0){ type=@"0"; [ChatsStore.shareInstance reloadData:self.chatId type:self.type]; } else if(self.type==1){ type=@"1"; // [ChatsStore.shareInstance reloadQunData:@"1871105598206210050" type:self.type]; [ChatsStore.shareInstance getGroupUserList:self.chatId]; [self getGroupInfo]; } _canloadhistory=true; NSDictionary *chatMsg=@{ @"chatId":self.chatId, @"name":self.titlename?:@"", @"avatar":self.avatar?:@"", @"type":type }; // NSLog(@"self.chatId:%@",self.chatId); [ChatListStore.shareInstance chatDidOpen:chatMsg]; [GWebSocket.shareInstance chekWebSocket]; } -(void)reloadAllData{ [self.messageArray removeAllObjects]; self.msgList = @[]; [__tableView reloadData]; _titlelb.text = self.titlename; ChatsStore.shareInstance.delegate = self; [OSSManager sharedManager].delegate = self; ChatsStore.shareInstance.chatId = self.chatId; ChatsStore.shareInstance.userid =self.userId; ChatListStore.shareInstance.chatId = self.chatId; [ChatsStore.shareInstance getchatReadTime:self.chatId]; NSString *type=@""; if(self.type==0){ type=@"0"; [ChatsStore.shareInstance reloadData:self.chatId type:self.type]; } else if(self.type==1){ type=@"1"; // [ChatsStore.shareInstance reloadQunData:@"1871105598206210050" type:self.type]; [ChatsStore.shareInstance getGroupUserList:self.chatId]; [self getGroupInfo]; } _canloadhistory=true; NSDictionary *chatMsg=@{ @"chatId":self.chatId, @"name":self.titlename?:@"", @"avatar":self.avatar?:@"", @"type":type }; // NSLog(@"self.chatId:%@",self.chatId); [ChatListStore.shareInstance chatDidOpen:chatMsg]; [GWebSocket.shareInstance chekWebSocket]; [self movetoBotton]; } - (void)dealloc { // NSLog(@"dealloc-----:%@",self); [self.preloader stopMonitoring]; [[NSNotificationCenter defaultCenter] removeObserver:self]; ChatsStore.shareInstance.delegate = nil; [OSSManager sharedManager].delegate = nil; ChatsStore.shareInstance.chatId = nil; } -(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; _titlelb.text = self.titlename; [self startTimer]; // NSLog(@"viewDidAppear-----:%@",self); } -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; [self endTimer]; // NSLog(@"viewWillDisappear-----"); } - (ChatBatchView *)batchView{ if (!_batchView) { _batchView = [[ChatBatchView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_X_BTM+64)]; [self.view addSubview:_batchView]; } return _batchView; } - (ChatQuoteView *)quoteView{ if (!_quoteView) { _quoteView = [[ChatQuoteView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH-180, 30)]; _quoteView.hidden = YES; [_quoteView.closeBtn addTarget:nil action:@selector(closeQuoteView) forControlEvents:UIControlEventTouchUpInside]; // [_quoteView.closeBtn jk_addActionHandler:^(NSInteger tag) { // [self closeQuoteView]; // }]; } return _quoteView; } -(NSMutableArray *)messageArray{ if (!_messageArray) { _messageArray = [NSMutableArray array]; } return _messageArray; } -(NSMutableArray *)forwordMsgArray{ if (!_forwordMsgArray) { _forwordMsgArray = [NSMutableArray array]; } return _forwordMsgArray; } -(NSMutableArray *)atSomeoneArray{ if (!_atSomeoneArray) { _atSomeoneArray = [NSMutableArray array]; } return _atSomeoneArray; } -(void)inidatastate{ [FriendNetApi isfriend:self.chatId succ:^(int code, NSDictionary * res) { NSLog(@"isfriend:%@",[res[@"data"] class]); BOOL state = res[@"data"]; if(state){ NSLog(@"isfriend1:"); self.isfriend = true; } else{ NSLog(@"isfriend2:"); self.isfriend=false; } } fail:^(NSError * _Nonnull error) { }]; } -(void)initpopbottonView{ [self hidBottonView]; // UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; // // 将手势添加到主视图上 // [self.view addGestureRecognizer:tap]; UITapGestureRecognizer *tapbotton = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissBotton)]; // 将手势添加到主视图上 [_markView addGestureRecognizer:tapbotton]; _keybarShow=false; } - (IBAction)fanhui:(id)sender { NSLog(@"fanhui-------"); [self dismissViewControllerAnimated:YES completion:nil]; } - (IBAction)rightBt:(id)sender { if (self.type==0) { UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; FriendController *friendctr = [board instantiateViewControllerWithIdentifier:@"FriendController"]; UINavigationController *uiNavC = [[UINavigationController alloc] initWithRootViewController:friendctr]; uiNavC.modalPresentationStyle = UIModalPresentationFullScreen; friendctr.friendMsg = nil; friendctr.friendId = self.chatId; [self presentViewController :uiNavC animated:YES completion:nil]; } else{ UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; GroupController *friendctr = [board instantiateViewControllerWithIdentifier:@"GroupController"]; UINavigationController *uiNavC = [[UINavigationController alloc] initWithRootViewController:friendctr]; uiNavC.modalPresentationStyle = UIModalPresentationFullScreen; friendctr.groupMsg = nil; friendctr.groupId = self.chatId; [self presentViewController :uiNavC animated:YES completion:nil]; } } - (IBAction)yuyinBt:(id)sender { if(_AVRecordBt.alpha==1){ _AVRecordBt.alpha = 0; _inputView.alpha = 1; [_yuyinctr setImage:[UIImage imageNamed:@"yuyin"] forState:UIControlStateNormal]; [self dismissKeyboard]; } else{ _AVRecordBt.alpha = 1; _inputView.alpha = 0; [_yuyinctr setImage:[UIImage imageNamed:@"jianpan"] forState:UIControlStateNormal]; } } - (IBAction)biaoqingBt:(id)sender { } - (IBAction)gengduo:(id)sender { [self showBottonView]; } - (IBAction)fasongBt:(id)sender { NSLog(@"fasongBt:1"); if(_isfriend){ NSLog(@"fasongBt:2"); [self sendtextData]; } else{//提示不是好友 NSLog(@"fasongBt:3"); UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"不是好友关系" preferredStyle:UIAlertControllerStyleAlert]; [self presentViewController:alert animated:NO completion:nil]; NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.5 target:self selector:@selector(dismissAlert:) userInfo:alert repeats:NO]; } //[app showAlert:@"警告" msg:@"不是好友关系" timelate:2]; } - (void)dismissAlert:(NSTimer *)timer { UIAlertController *alert = [timer userInfo]; [alert dismissViewControllerAnimated:YES completion:nil]; alert = nil; } #pragma mark 群信息 - (void)getGroupInfo{ [GroupNetApi getGroupInfo:self.chatId succ:^(int code, NSDictionary * _Nullable result) { // NSLog(@"GroupInfo:----%@",result); self.groupInfo = result[@"data"]; self.titlename = self.groupInfo[@"name"]; self.titlelb.text = self.groupInfo[@"name"]; } fail:^(NSError * _Nonnull error) { NSLog(@"error:%@",error); }]; } #pragma mark ChatsStoreDelegate -(void)getlocalData{ [ChatsStore.shareInstance reloadData:self.chatId type:self.type]; } -(void)ChatsChange:(NSArray *)msgList type:(NSInteger)typpe{ // NSLog(@"msgList:%@",msgList); if([msgList count]==0){ return; } if(self.msgList.count>0){ NSArray *array = msgList.copy; NSMutableArray *marray = [NSMutableArray new]; // [marray addObjectsFromArray:self.msgList]; [marray addObjectsFromArray:array]; NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:marray]; NSMutableArray *uniqueArray = [orderedSet.array mutableCopy]; self.msgList = [ChatsStore.shareInstance arraysort:uniqueArray]; } else{ self.msgList = msgList.copy; NSMutableArray *array = [NSMutableArray new]; [array addObjectsFromArray:self.msgList]; NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:array]; NSMutableArray *uniqueArray = [orderedSet.array mutableCopy]; self.msgList = [ChatsStore.shareInstance arraysort:uniqueArray]; } // NSLog(@"self.msgList11:%@",self.msgList); NSMutableArray * tempArray = [NSMutableArray array]; for (NSDictionary * msg in self.msgList) { // NSLog(@"msg:%@",msg); ChatMessageModel *message = [ChatMessageModel modelWithDictionary:msg]; if (message.avatar.length==0 && message.isSender) { message.avatar = self.useravatar; }else if (message.avatar.length==0 && !message.isSender) { message.avatar = self.avatar; } if ([message.chatId isEqualToString:self.chatId]) { [tempArray addObject:message]; } } // NSLog(@"----222---:coun-------:%lu",(unsigned long)tempArray.count); NSMutableArray * indexPathArray = [NSMutableArray array]; BOOL isHistoryRecord = NO; if (self.messageArray.count == 0) { [self.messageArray removeAllObjects]; [self.messageArray addObjectsFromArray:tempArray]; // NSLog(@"----222---:count ==%lu",(unsigned long)self.messageArray.count); //禁用隐式动画 加载历史消息 [CATransaction begin]; [CATransaction setDisableActions:YES]; [self._tableView reloadData]; NSIndexPath *lastRowIndexPath = [NSIndexPath indexPathForRow:([self._tableView numberOfRowsInSection:0] - 1) inSection:0]; [self._tableView scrollToRowAtIndexPath:lastRowIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; [CATransaction commit]; [self.preloader startMonitoring]; [self faSongYidu]; _canloadhistory = true; return; }else{ for (ChatMessageModel *message in tempArray) { BOOL isContain = NO; // NSLog(@"----333---:%ld",(long)message.localtime); for (ChatMessageModel * localMessage in self.messageArray) { if (localMessage.localtime==message.localtime) { isContain = YES; if (![message.url isEqualToString:localMessage.url] || ![message.readStatus isEqualToString:localMessage.readStatus]||localMessage.messageType!=message.messageType) { [localMessage exchangeModelWithModel:message]; // NSLog(@"----11---:%@",message.content); dispatch_async(dispatch_get_main_queue(), ^{ [CATransaction begin]; [CATransaction setDisableActions:YES]; NSIndexPath *reloadIndexPath = [NSIndexPath indexPathForRow:[self.messageArray indexOfObject:localMessage] inSection:0]; [self._tableView beginUpdates]; [self._tableView reloadRowsAtIndexPaths:@[reloadIndexPath] withRowAnimation:UITableViewRowAnimationNone]; [self._tableView endUpdates]; [CATransaction commit]; }); }else{ [localMessage exchangeModelWithModel:message]; // NSLog(@"----222---:%@",message.content); } } else{ // NSLog(@"1122211------"); } } if (!isContain) { // NSLog(@"!isContain"); ChatMessageModel *lastObj = self.messageArray.lastObject; if (lastObj.timestamp > message.timestamp) { //插入历史消息 for (ChatMessageModel * localMessage in self.messageArray) { if(localMessage.timestamp>message.timestamp){ NSInteger index = [self.messageArray indexOfObject:localMessage]; // NSLog(@"插入历史消息1------:%@",message.content); // NSLog(@"index:%ld",(long)index); [self.messageArray insertObject:message atIndex:index]; NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:index inSection:0]; [indexPathArray addObject:newIndexPath]; break; } } }else{ // NSLog(@"插入历史消息2------:%@",message.content); isHistoryRecord = NO; [self.messageArray addObject:message]; NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:self.messageArray.count-1 inSection:0]; [indexPathArray addObject:newIndexPath]; } } else{ // NSLog(@"插入历史消息6------:%@",message.content); } } } if (indexPathArray.count == 0) { if(msgList.count>0){ _canloadhistory = true; } else{ _canloadhistory = false; } return; } // NSLog(@"----222444---:count ==%lu",(unsigned long)self.messageArray.count); if (isHistoryRecord) { // 执行插入操作(禁用动画) for (NSIndexPath * index in indexPathArray) { if (index.row>=self.messageArray.count) { return; } } [CATransaction begin]; [CATransaction setDisableActions:YES]; [self._tableView beginUpdates]; [self._tableView insertRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; [self._tableView endUpdates]; [CATransaction commit]; [self.preloader resetScrollState]; if(msgList.count>0){ _canloadhistory = true; } else{ _canloadhistory = false; } }else{ [CATransaction begin]; [CATransaction setDisableActions:YES]; [self._tableView beginUpdates]; [self._tableView insertRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; [self._tableView endUpdates]; [CATransaction commit]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //插入新消息时,判断是否在底部附近,在底部附近则滚动至底部,不在底部则不打断用户浏览 CGFloat visibleHeight = self._tableView.bounds.size.height - self._tableView.contentInset.top - self._tableView.contentInset.bottom; CGFloat yOffset = self._tableView.contentOffset.y; CGFloat threshold = MAX(20, visibleHeight * 0.8); // 距离底部20点或20%可见高度 // NSLog(@"threshold:%f,%f",threshold,self._tableView.contentSize.height - yOffset - visibleHeight); BOOL shouldScrollToBottom = (self._tableView.contentSize.height - yOffset - visibleHeight) <= threshold; if (shouldScrollToBottom) { [CATransaction begin]; [CATransaction setDisableActions:YES]; NSIndexPath *lastRowIndexPath = [NSIndexPath indexPathForRow:([self._tableView numberOfRowsInSection:0] - 1) inSection:0]; [self._tableView scrollToRowAtIndexPath:lastRowIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; [CATransaction commit]; } }); [self faSongYidu]; if(msgList.count>0){ _canloadhistory = true; } else{ _canloadhistory = false; } } if(self.messageArray.count>20){ _showLoading = false; } else{ _showLoading = true; } } -(void)movetoBotton{ // NSLog(@"movetoBotton------movetoBotton"); if (self.messageArray.count>0) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSIndexPath *lastRowIndexPath = [NSIndexPath indexPathForRow:([self._tableView numberOfRowsInSection:0] - 1) inSection:0]; //NSLog(@"lastRowIndexPath:%ld",(long)lastRowIndexPath.row); [self._tableView scrollToRowAtIndexPath:lastRowIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; }); } } #pragma mark chatpopViewDelegate -(void)actionNote:(NSString *)note{ [self hidBottonView]; if([note isEqualToString:@"1"]){//发送图片 [self showImagePicker:1]; } if([note isEqualToString:@"2"]){//发送视频 [self showImagePicker:2]; } if([note isEqualToString:@"3"]){//发送文件 [self showfilePicker]; } if([note isEqualToString:@"4"]){//语音 [self showWebRtcVidio:4]; } if([note isEqualToString:@"5"]){//视频 [self showWebRtcVidio:5]; } if([note isEqualToString:@"6"]){//拍摄 [self takePhoto]; } } #pragma mark preload -(void)setupPreloader{ //预加载管理器 NSLog(@"setupPreloader"); self.preloader = [[HistoryPreloader alloc] init]; self.preloader.tableView = self._tableView; self.preloader.threshold = 700; weakSelf(self); self.preloader.loadBlock = ^{ if (!weakself.canloadhistory) { return; } [weakself loadhistoryData]; }; self.preloader.toofast = ^{ if (weakself.showLoading) { }else{ weakself.showLoading = YES; // [MBProgressHUD showLoadingWithText:@"數據解密中。。。。" inView:weakself.view hideAfterDelay:2]; } }; } -(void)loadhistoryData{ if(self.messageArray.count>0){ NSLog(@"loadhistoryData-------"); _canloadhistory = false; if(self.type==0){ ChatMessageModel *eldata = self.messageArray[0]; NSInteger time =eldata.timestamp; [ChatsStore.shareInstance loadNextData:self.chatId timestp:time]; } else if(self.type==1){ ChatMessageModel *eldata = self.messageArray[0]; NSInteger time =eldata.timestamp; [ChatsStore.shareInstance loadQunNextData:self.chatId timestp:time]; } } } #pragma mark UITableViewDelegate,UITableViewDataSource -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.messageArray.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ if(self.messageArray.count threshold&&!_canloadhistory) { // _canloadhistory=true; // _offset =offsetY; // return; // } // if(_offset-offsetY>400){ // _canloadhistoryMore=false; // } // // if(_canloadhistory&&offsetY < threshold){ //// NSLog(@"-----1------1"); // if(!_canloadhistoryMore){ //// NSLog(@"-----1------2"); // _ishistory=true; // [self loadhistoryData]; // } // } } -(void)saveFile:(ChatMessageModel *)msgMdl{ NSString *localPath =msgMdl.localurl; if (localPath && [[NSFileManager defaultManager] fileExistsAtPath:localPath]) { NSLog(@"本地路径"); NSString *fileExtension = [[msgMdl.localurl pathExtension] lowercaseString]; if([self isVideoFile:fileExtension]){ NSURL *fileURL = [NSURL fileURLWithPath:localPath]; [self saveVideoToPhotoLibrary:fileURL]; } else{ [self saveFileToLibrary:localPath]; } } else{ [MBProgressHUD showWithText:@"文件尚未加载完成,请稍后重试"]; } } - (BOOL)isVideoFile:(NSString *)fileExtension { NSArray *videoExtensions = @[@"mp4", @"mov", @"m4v", @"avi", @"mkv", @"flv", @"wmv"]; return [videoExtensions containsObject:fileExtension]; } - (void)saveVideoToPhotoLibrary:(NSURL *)videoURL { // 检查 PHPhotoLibrary 的授权状态 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusAuthorized) { // 授权成功,保存视频 [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ // 创建资产更改请求 PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:videoURL]; // 可以设置其他属性,如位置信息等 // [assetChangeRequest setLocation:location]; } completionHandler:^(BOOL success, NSError *error) { if (success) { NSLog(@"视频保存成功"); dispatch_async(dispatch_get_main_queue(), ^{ [self showNot:@"保存到手机成功"]; }); } else { NSLog(@"视频保存失败: %@", error.localizedDescription); } }]; } else { // 授权失败或未授权,处理用户未授权的情况 NSLog(@"请在设置中授权访问相册"); } }]; } -(void)showNot:(NSString *)str{ [MBProgressHUD showWithText:str]; } -(void)saveFileToLibrary:(NSString *)fileUrl{ NSURL *fileURL = [NSURL fileURLWithPath:fileUrl]; UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:fileURL]; [documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES]; } #pragma mark UITextViewDelegate - (void)textViewDidChange:(UITextView *)textView { CGFloat maxHeight = 160; CGFloat maxWidth = self.view.frame.size.width - 190; CGSize newSize = [textView sizeThatFits:CGSizeMake(maxWidth, MAXFLOAT)]; if(newSize.height>maxHeight){ _inputView.scrollEnabled = YES; // 允许滚动,出现滚动条 } else{ _inputView.scrollEnabled = NO; // 禁止滚动,使内容自适应高度 [self movetoBotton]; } CGFloat height = MAX(40, MIN(maxHeight, newSize.height)); self.bottomViewHeight.constant = height+20; } - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { // 计算新文本的长度 NSInteger newLength = textView.text.length - range.length + text.length; NSLog(@"shouldChangeTextInRange---"); // 若新文本长度超出最大长度,则不允许输入 if (newLength > 1000) { [MBProgressHUD showWithText:@"超出最大文本长度,请重新输入"]; if (textView.text.length == 0) { return NO; } // 截取最大长度的文本 NSString *substring = [textView.text substringToIndex:1000]; textView.text = substring; return NO; } if ([text isEqualToString:@"@"] && self.type == 1) { NSLog(@"用户输入了@符号"); // 可以在这里添加你需要执行的代码 [textView resignFirstResponder]; [self showAtMemberView]; } if ([text isEqualToString:@""] && self.type == 1) { // 删除操作 // 处理连续删除特殊字符的情况 if (range.length == 1) { NSRange deleteRange = range; NSString *deletedChar = [textView.text substringWithRange:deleteRange]; // 如果删除的是连字符,尝试删除整个mention if ([deletedChar isEqualToString:@"-"]) { if ([self.inputView deleteMentionAtCursorPosition]) { return NO; } } } NSLog(@"1111111"); // 正常删除处理 if ([self.inputView deleteMentionAtCursorPosition]) { NSLog(@"deleteMentionAtCursorPosition"); return NO; } } return YES; } - (void)keyboardWillShow:(NSNotification *)notification { // 获取键盘的动画持续时间和动画曲线 NSDictionary *userInfo = [notification userInfo]; double duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; // UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue]; // // 获取键盘的高度 CGRect keyboardEndFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; _keyboardHeight = keyboardEndFrame.size.height; NSLog(@"_keyboardHeight:%f",_keyboardHeight); // 根据需要调整视图大小或位置(例如,移动某个视图) // 示例:将一个视图向下移动以适应键盘高度 CGFloat safeBottom = [UIDevice safeDistanceBottom]; CGFloat offsetY = _keyboardHeight - safeBottom; _gengduoBt.alpha = 1; _fasngBt.alpha = 1; _keybarShow=true; [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.inputViewBottom.constant = offsetY; [self.view setNeedsLayout]; [self.view layoutIfNeeded]; } completion:^(BOOL finished) { [self movetoBotton]; }]; } - (void)keyboardWillHide:(NSNotification *)notification { // 获取键盘的动画持续时间和动画曲线 NSDictionary *userInfo = [notification userInfo]; double duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue]; NSLog(@"_keyboardHeight:%f",_keyboardHeight); [UIView animateWithDuration:duration delay:0.0 options:(curve << 16) animations:^{ self.inputViewBottom.constant = 0; [self.view setNeedsLayout]; [self.view layoutIfNeeded]; } completion:^(BOOL finished) { [self movetoBotton]; }]; if(_inputView.text.length>0){ _gengduoBt.alpha = 1; _fasngBt.alpha = 1; } else{ _gengduoBt.alpha = 1; _fasngBt.alpha = 1; } _keybarShow=false; } -(void)dismissKeyboard{ [self.view endEditing:YES]; } -(void)fasongwanwenzi{ CGRect newFrame = _inputView.frame; newFrame.size.height =40; _inputView.scrollEnabled = NO; // 禁止滚动,使内容自适应高度 _inputView.frame =newFrame; CGRect viewFrame = _bottonView.frame; viewFrame.size.height = 62; if (self.isQuoteMessage) { self.quoteView.hidden = YES; CGRect audioBtnFrame = self.yuyinctr.frame; self.yuyinctr.frame = CGRectMake(audioBtnFrame.origin.x, audioBtnFrame.origin.y+kQuoteViewHeight, audioBtnFrame.size.height, audioBtnFrame.size.height); CGRect moreFunctionBtnFrame = self.gengduoBt.frame; self.gengduoBt.frame = CGRectMake(moreFunctionBtnFrame.origin.x, moreFunctionBtnFrame.origin.y+kQuoteViewHeight, moreFunctionBtnFrame.size.width, moreFunctionBtnFrame.size.height); CGRect sendBtnFrame = self.fasngBt.frame; self.fasngBt.frame = CGRectMake(sendBtnFrame.origin.x, sendBtnFrame.origin.y+kQuoteViewHeight, sendBtnFrame.size.width, sendBtnFrame.size.height); } if(_keybarShow){ viewFrame.origin.y =self.view.frame.size.height-_keyboardHeight-viewFrame.size.height; CGRect tframe = self._tableView.frame; tframe.size.height = viewFrame.origin.y-tframe.origin.y; self._tableView.frame = tframe; [self movetoBotton]; } else{ // 恢复视图原始位置或大小 viewFrame.origin.y = self.view.frame.size.height-viewFrame.size.height-34; CGRect tframe = self._tableView.frame; tframe.size.height = viewFrame.origin.y-tframe.origin.y; self._tableView.frame = tframe; [self movetoBotton]; } _bottonView.frame = viewFrame; } #pragma mark 发送数据 -(void)sendtextData{ NSLog(@"sendtextData1"); NSString *msg = _inputView.text; msg = [msg stringByReplacingOccurrencesOfString:@"\r" withString:@""]; msg = [msg stringByReplacingOccurrencesOfString:@"\n" withString:@""]; msg = [msg stringByReplacingOccurrencesOfString:@"\t" withString:@""]; msg = [msg stringByReplacingOccurrencesOfString:@" " withString:@""]; if (msg.length==0) { NSLog(@"空内容"); return; } [self fasongwanwenzi]; NSLog(@"sendtextData2"); NSDictionary * quoteMessage; if (self.isQuoteMessage) { // NSInteger quoteIndex = [self.messageArray indexOfObject:self.quoteView.model]; // NSLog(@"quoteIndex:%ld------------",quoteIndex); quoteMessage = self.quoteView.model.formerMessage; } NSString *content= [CryptoAES.shareInstance encryptStringL:_inputView.text]; // NSLog(@"content:%@",content); NSString *strtime = [self getLocalTime]; NSString *type = [NSString stringWithFormat:@"%ld",(long)self.type]; NSDictionary *Lmsgd=@{ @"messageType":@"0", @"chatId":self.chatId, @"fromId":self.userId, @"fromName":self.username, @"fromAvatar":self.useravatar, @"content":content, @"type":type, @"reSend":[NSNumber numberWithBool:false], @"extend": @{ @"atAll":@"false", @"atUserIds":@[], }, @"localtime":strtime, @"timestamp":strtime, @"mine":@"true", @"id":strtime, }; NSMutableDictionary * tempMsgDict = [NSMutableDictionary dictionaryWithDictionary:Lmsgd]; NSMutableDictionary * tempExtandDict = [NSMutableDictionary dictionaryWithDictionary:Lmsgd[@"extend"]]; if (quoteMessage) { [tempExtandDict setObject:quoteMessage forKey:@"quoteMessage"]; [tempMsgDict setObject:tempExtandDict forKey:@"extend"]; } if (self.atSomeoneArray.count!=0 && self.type == 1) { //@单人或者多人参数插入 NSMutableArray * atUserIdsArray = [NSMutableArray array]; for (NSDictionary * user in self.atSomeoneArray) { [atUserIdsArray addObject:user[@"id"]]; } [tempExtandDict setObject:atUserIdsArray forKey:@"atUserIds"]; [tempMsgDict setObject:tempExtandDict forKey:@"extend"]; } if ([self.inputView.text containsString:@"@所有人"] && self.type == 1 && [self.groupInfo[@"master"] isEqualToString:self.userId]) { [tempExtandDict setObject:@"true" forKey:@"atAll"]; [tempMsgDict setObject:tempExtandDict forKey:@"extend"]; } NSString * tempChatId = self.chatId.mutableCopy; [ChatsStore shareInstance].chatId = tempChatId; [ChatsStore shareInstance].delegate = self; [ChatsStore.shareInstance reciveMsg:tempMsgDict];//预先展示聊天窗信息 // NSLog(@"sendtextData3"); NSDictionary *Smsgd=@{ @"messageType":@"0", @"chatId":self.chatId, @"fromId":self.userId, @"fromName":self.username, @"fromAvatar":self.useravatar, @"content":content, @"type":type, @"reSend":[NSNumber numberWithBool:false], @"extend": @{ @"atAll":@"false", @"atUserIds":@[], }, @"localtime":strtime, @"timestamp":strtime, }; NSMutableDictionary * tempSendMsgDict = [NSMutableDictionary dictionaryWithDictionary:Smsgd]; NSMutableDictionary * tempSendExtandDict = [NSMutableDictionary dictionaryWithDictionary:Smsgd[@"extend"]]; if (quoteMessage) { [tempSendExtandDict setObject:quoteMessage forKey:@"quoteMessage"]; [tempSendMsgDict setObject:tempSendExtandDict forKey:@"extend"]; } if (self.atSomeoneArray.count!=0 && self.type == 1) { //@单人或者多人参数插入 NSMutableArray * atUserIdsArray = [NSMutableArray array]; for (NSDictionary * user in self.atSomeoneArray) { [atUserIdsArray addObject:user[@"id"]]; } [tempSendExtandDict setObject:atUserIdsArray forKey:@"atUserIds"]; [tempSendMsgDict setObject:tempSendExtandDict forKey:@"extend"]; } if ([self.inputView.text containsString:@"@所有人"] && self.type == 1 && [self.groupInfo[@"master"] isEqualToString:self.userId]) { [tempSendExtandDict setObject:@"true" forKey:@"atAll"]; [tempSendMsgDict setObject:tempSendExtandDict forKey:@"extend"]; } NSDictionary *sendInfo = @{ @"code":@"2", @"message":tempSendMsgDict, }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; //NSLog(@"%@", jsonString); // 输出: {"name":"John","age":25} // NSLog(@"----发送文字----"); [GWebSocket.shareInstance sendMsg:jsonString]; if (self.isQuoteMessage) { self.isQuoteMessage = NO; } _inputView.text=@""; [self textViewDidChange:_inputView]; } if(_keybarShow){ _gengduoBt.alpha = 1; _fasngBt.alpha = 1; } else{ _gengduoBt.alpha = 1; _fasngBt.alpha = 1; } } -(void)faSongYidu{ if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) { // 应用已经解锁并且在前台 NSLog(@"应用已经解锁并且在前台viewWillDisappear-----1111"); } else{ return; } NSString *strtime = [self getLocalTime]; NSString *type = [NSString stringWithFormat:@"%ld",(long)self.type]; NSDictionary *dic =@{ @"chatId":self.chatId, @"userId":self.userId, @"type":type, @"timestamp":strtime, }; NSDictionary *sendInfo = @{ @"code":SendCode_READ, @"message":dic, }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSLog(@"%@", jsonString); // 输出: {"name":"John","age":25} // NSLog(@"1--------发送已读时间--------2"); [GWebSocket.shareInstance sendMsg:jsonString]; } } #pragma mark 弹框 -(void)showBottonView{ [self dismissKeyboard]; _markView.frame = self.view.frame; CGRect popfram = CGRectMake(0,self.view.frame.size.height-250, self.view.frame.size.width, 250); _popView.frame = popfram; } -(void)hidBottonView{ CGRect popfram = CGRectMake(0,self.view.frame.size.height, self.view.frame.size.width, 250); _popView.frame = popfram; _markView.frame=popfram; _markView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5]; [self movetoBotton]; } -(void)dismissBotton{ [self hidBottonView]; } #pragma mark 定时服务 -(void)startTimer{ if(self.timer==nil){ self.timer = [NSTimer scheduledTimerWithTimeInterval:10.1 target:self selector:@selector(TimerAction) userInfo:nil repeats:YES]; [self.timer setFireDate:[NSDate distantPast]]; [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; } } -(void)endTimer{ [self.timer invalidate]; self.timer = nil; } -(void)TimerAction{ //处理重发事件 // NSLog(@"self.msgList:%@",self.msgList); for(NSDictionary *dis in self.msgList){ NSString *mine = dis[@"mine"]; if(mine.boolValue){ if([dis[@"id"] isEqualToString:dis[@"localtime"]]){ [self resendMsg:dis.copy]; } } } } -(BOOL)canResend:(NSDictionary *)msg{ NSLog(@"canResend:%@",msg); NSString *localtime = msg[@"localtime"]; NSString *messageType = msg[@"messageType"]; if([messageType isEqualToString:MessageType_text]){ for (NSDictionary *item in self.msgList) { NSString *itlocaltime =item[@"localtime"]; if([localtime isEqualToString:itlocaltime]){ NSLog(@"canResend2:%@",item); if(![item[@"id"] isEqualToString:item[@"localtime"]]){ return false; } NSDate *now = [NSDate date]; NSTimeInterval trt = [now timeIntervalSince1970]; NSNumber *tt =msg[@"localtime"]; if((trt-tt.integerValue/1000)>40){ //发送失败 NSLog(@"发送失败-------"); return false; } } } } else{ [self fileUploadState:msg]; return false; } return YES; } -(void)fileUploadState:(NSDictionary *)msg{ NSString *localtime = msg[@"localtime"]; NSString *messageType = msg[@"messageType"]; if([messageType isEqualToString:MessageType_file]||[messageType isEqualToString:MessageType_image]||[messageType isEqualToString:MessageType_video]) { if([OSSManager.sharedManager isuploadTanck:localtime]){ return; } for (NSDictionary *item in self.msgList) { NSString *itlocaltime =item[@"localtime"]; if([localtime isEqualToString:itlocaltime]){ NSLog(@"canResend2:%@",item); if(![item[@"id"] isEqualToString:item[@"localtime"]]){ return; } NSDictionary *extend =item[@"extend"]; NSString *url =extend[@"url"]; if([url isEqualToString:@""]){ NSString *savedPath =extend[@"localurl"]; NSURL * fileUrl = [NSURL fileURLWithPath:savedPath]; ChatFileModel * model = [[ChatFileModel alloc] initWithURL:fileUrl]; model.fileURL = fileUrl; model.filePath = savedPath; [self OSSuploadFile:model thrid:localtime]; NSLog(@"重发文件"); [self FileReUpload:localtime]; } } } } } -(void)FileReUpload:(NSString *)localtime{ [GDBManager.shareInstance selectLocalmsgWithLocaltime:localtime succ:^(NSArray * _Nullable array) { NSLog(@"selectLocalmsgWithLocaltime:%@",array); if(array){ if(array.count>0){ NSDictionary *msg =array[0]; NSString *msgtype = msg[@"messageType"]; if (([msgtype isEqualToString:MessageType_Del]||[msgtype isEqualToString:MessageType_CallBack2])) { return; } NSDictionary *extend=msg[@"extend"]; NSMutableDictionary *mextend = [extend mutableCopy]; [mextend setObject:[NSNumber numberWithInt:0] forKey:@"fileError"]; NSMutableDictionary *mmsg = [msg mutableCopy]; [mmsg setObject:mextend forKey:@"extend"]; [ChatsStore.shareInstance reciveMsg:mmsg]; } } } fail:^(NSString * _Nullable error) { ; }]; } //重发消息 -(void)resendMsg:(NSDictionary *)msg{ if(![self canResend:msg]){ return; } NSMutableDictionary *dic = [msg mutableCopy]; NSString *resend =dic[@"reSend"]; NSLog(@"resend:%@",[resend class]); if (resend.boolValue) { return; } else{ NSString * str = msg[@"messageType"]; if (![str isEqualToString:@"0"]) { return; } [dic setObject:[NSNumber numberWithBool:YES] forKey:@"reSend"]; NSDictionary * dict = dic.copy; [ChatsStore.shareInstance reciveMsg:dict];//预先展示聊天窗信息 [dic setObject:[NSNull null] forKey:@"id"]; } NSDictionary *sendInfo = @{ @"code":@"2", @"message":dic, }; NSError *error; // NSLog(@"resendMsg---------:%@",msg[@"localtime"]); NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; [GWebSocket.shareInstance sendMsg:jsonString]; } } #pragma mark 上传图片 -(void)showImagePicker:(NSInteger)state{ NSLog(@"showImagePicker"); PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; if (status == PHAuthorizationStatusAuthorized) { // 已经授权,可以访问相册 } else { // 未授权,请求授权 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusAuthorized) { // 用户授权了访问相册 // 在这里执行相册相关的操作 } else { // 用户拒绝授权 // 可以提供一些用户指导或提示信息 return; } }]; } PHPickerConfiguration *config = [[PHPickerConfiguration alloc] init]; if(state==1){ config.filter = [PHPickerFilter imagesFilter]; // 可以设置过滤器,例如只选择图片或视频等 } else if(state==2){ config.filter = [PHPickerFilter videosFilter]; // 可以设置过滤器,例如只选择图片或视频等 } config.selectionLimit = 9; // 限制选择数量,设置为1表示只能选择一张图片 config.preferredAssetRepresentationMode = PHPickerConfigurationAssetRepresentationModeCurrent; PHPickerViewController *imagePicker = [[PHPickerViewController alloc] initWithConfiguration:config]; imagePicker.delegate = self; // 设置代理以接收选择结果 [self presentViewController:imagePicker animated:YES completion:nil]; } - (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray *)results { [picker dismissViewControllerAnimated:YES completion:nil]; // 关闭选择器视图控制器 if (results.count == 0) { return; } NSMutableArray * fileArray = [NSMutableArray array]; for (PHPickerResult * result in results) { NSItemProvider *itemProvider = result.itemProvider; NSString *typeIdentifier = result.itemProvider.registeredTypeIdentifiers.firstObject; if ([result.itemProvider canLoadObjectOfClass:[UIImage class]]) { [result.itemProvider loadFileRepresentationForTypeIdentifier:typeIdentifier completionHandler:^(NSURL * _Nullable url, NSError * _Nullable error) { if (error) { NSLog(@"Error loading file: %@", error); return; } NSLog(@"File URL: %@", url); // 这里就是文件的 URL 路径 // 你可以使用这个 URL 进行进一步处理,例如读取文件内容或者将其复制到应用沙盒中的其他位置。 NSString *savedPath = [self saveFileToDocumentsDirectory:url]; if(savedPath.length>0){ NSURL * fileUrl = [NSURL fileURLWithPath:savedPath]; ChatFileModel * model = [[ChatFileModel alloc] initWithURL:fileUrl]; model.fileURL = fileUrl; model.filePath = savedPath; [fileArray addObject:model]; if (fileArray.count==results.count) { dispatch_async(dispatch_get_main_queue(), ^{ [self handleMediaData:fileArray]; }); } } else{ NSLog(@"-----找不到文件------"); } }]; }else{ [result.itemProvider loadFileRepresentationForTypeIdentifier:typeIdentifier completionHandler:^(NSURL * _Nullable url, NSError * _Nullable error) { if (error) { NSLog(@"Error loading file: %@", error); return; } NSLog(@"File URL: %@", url); // 这里就是文件的 URL 路径 // 你可以使用这个 URL 进行进一步处理,例如读取文件内容或者将其复制到应用沙盒中的其他位置。 NSString *savedPath = [self saveFileToDocumentsDirectory:url]; if(savedPath.length>0){ NSURL * fileUrl = [NSURL fileURLWithPath:savedPath]; ChatFileModel * model = [[ChatFileModel alloc] initWithURL:fileUrl]; model.fileURL = fileUrl; model.filePath = savedPath; [fileArray addObject:model]; if (fileArray.count==results.count) { dispatch_async(dispatch_get_main_queue(), ^{ [self handleMediaData:fileArray]; }); } } else{ NSLog(@"-----找不到文件------"); } }]; } } } #pragma mark - 写入方法 - (NSString *)saveImageToSandbox:(UIImage *)image { // 获取沙盒Documents目录 NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; // 生成唯一文件名 NSString *fileName = [NSString stringWithFormat:@"%@.jpg", [[NSUUID UUID] UUIDString]]; NSString *filePath = [documentsPath stringByAppendingPathComponent:fileName]; // 将图片转换为JPEG格式数据 NSData *imageData = UIImageJPEGRepresentation(image, 0.8); // 写入文件 BOOL success = [imageData writeToFile:filePath atomically:YES]; if (success) { NSLog(@"图片保存成功,路径: %@", filePath); return filePath; } else { NSLog(@"图片保存失败"); return nil; } } - (NSString *)saveVideoDataToDocumentsDirectory:(NSData *)videoData { // 1. 生成唯一文件名 NSString *fileName = [NSString stringWithFormat:@"%@.mp4", [[NSUUID UUID] UUIDString]]; // 2. 获取Documents目录路径 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths firstObject]; NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName]; // 3. 写入数据 NSError *writeError; [videoData writeToFile:filePath options:NSDataWritingAtomic error:&writeError]; if (writeError) { NSLog(@"Error writing video data: %@", writeError.localizedDescription); return nil; } return filePath; } - (NSString *)saveFileToDocumentsDirectory:(NSURL *)fromePath { NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:fromePath.lastPathComponent]; // 目标文件路径 NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error = nil; if([[NSFileManager defaultManager] fileExistsAtPath:destinationPath]){ return destinationPath; } else{ BOOL success = [fileManager copyItemAtPath:fromePath.path toPath:destinationPath error:&error]; if (success) { NSLog(@"文件成功复制到本地"); return destinationPath; } else { NSLog(@"文件复制失败: %@", error.localizedDescription); return @""; } } } #pragma mark -文件选择和处理 -(void)showfilePicker{ // 创建文档选择器 NSArray *contentTypes = @[UTTypeItem]; UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:contentTypes asCopy:YES]; documentPicker.allowsMultipleSelection = YES; documentPicker.delegate = self; [self presentViewController:documentPicker animated:YES completion:nil]; } #pragma mark - 文件选择回调 UIDocumentPickerDelegate - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray *)urls { // 用户选择了一个或多个文件,处理这些文件 if (urls.count > 9) { //选择文件最多 9 个 [MBProgressHUD showWithText:@"一次最多上傳 9 個檔案"]; } NSMutableArray * fileArray = [NSMutableArray array]; for (NSURL * url in urls) { if ([urls indexOfObject:url] > 9) { break; } NSLog(@"url:%@",url); NSString *savedPath = [self saveFileToDocumentsDirectory:url]; if(savedPath.length>0){ NSURL * fileUrl = [NSURL fileURLWithPath:savedPath]; ChatFileModel * model = [[ChatFileModel alloc] initWithURL:fileUrl]; model.fileURL = fileUrl; model.filePath = savedPath; [fileArray addObject:model]; } } dispatch_async(dispatch_get_main_queue(), ^{ [self handleMediaData:fileArray]; }); } #pragma mark 批量处理文件上传 - (void)handleMediaData:(NSArray *)mediaArray{ // NSMutableArray * tempArray = [NSMutableArray array]; NSArray *sorArray = [self fileArraysort:mediaArray]; for (ChatFileModel * model in sorArray) { NSString *strtime = [self getLocalTime]; [self uploadFile:[NSString stringWithFormat:@"%@",model.fileURL] fpath:model.filePath state:1 act:1 localtime:strtime]; [self OSSuploadFile:model thrid:strtime]; } } -(void)OSSuploadFile:(ChatFileModel *)model thrid:(NSString *)strtime{ NSString * tempChatId = self.chatId.mutableCopy; [ChatsStore shareInstance].chatId = tempChatId; [ChatsStore shareInstance].delegate = self; // 断点续传 [OSSManager.sharedManager asyncResumableUploadFile:model.fileURL.lastPathComponent localFilePath:model.filePath thrid:strtime]; } -(void)stateChange:(NSDictionary *)changeMsg{ dispatch_main_async_safe(^{ NSString *loacaltime = changeMsg[@"thrid"]; NSString *pcent = changeMsg[@"pcent"]; NSString *state = changeMsg[@"state"]; NSLog(@"uploadProgress: %@",pcent); if([state isEqualToString:@"1"]){ [self Ossupdatajidu:loacaltime uploadProgress:pcent.intValue]; } }) } -(void)resendFile:(ChatMessageModel *)msg{ NSString *strtime = [NSString stringWithFormat:@"%ld",(long)msg.localtime]; NSString *loaclFile = [NSString stringWithFormat:@"%@",msg.localurl]; if(![[NSFileManager defaultManager] fileExistsAtPath:loaclFile]){ [MBProgressHUD showWithText:@"文件不存在,請重新選擇"]; return; } NSURL * fileUrl = [NSURL fileURLWithPath:loaclFile]; ChatFileModel * model = [[ChatFileModel alloc] initWithURL:fileUrl]; model.fileURL = fileUrl; model.filePath = loaclFile; [self OSSuploadFile:model thrid:strtime]; } -(void)uploadFile:(NSString *)url fpath:(NSString *)path state:(NSInteger)state act:(NSInteger)act localtime:(NSString *)localtime{ NSURL *filePath; if([url containsString:@"http"]){ filePath=[NSURL URLWithString:url]; // } else{ NSString *filestr = [[OSSManager sharedManager] fullUploadURLByAppendPath:url]; filePath=[NSURL URLWithString:filestr]; // } NSString *content=@"【文件】"; NSString *messageType=MessageType_file; NSDictionary *extend; if(state==1){//文件类消息 NSString *kzm = filePath.pathExtension; kzm=[kzm lowercaseString]; if([kzm isEqualToString:@"png"]||[kzm isEqualToString:@"jpg"]||[kzm isEqualToString:@"jpeg"]||[kzm isEqualToString:@"bmp"]){ content=@"【图片】"; messageType=MessageType_image; } if([kzm isEqualToString:@"mp4"]||[kzm isEqualToString:@"avi"]||[kzm isEqualToString:@"wmv"]||[kzm isEqualToString:@"mov"]||[kzm isEqualToString:@"mpeg"]){ content=@"【视频】"; messageType=MessageType_video; } } content= [CryptoAES.shareInstance encryptStringL:content]; NSString *type = [NSString stringWithFormat:@"%ld",(long)self.type]; NSDictionary *msgt; NSDictionary *msgd; if(act==1){ extend=@{ @"url":@"", @"fileName":filePath.lastPathComponent, @"localurl":path, @"fileError":[NSNumber numberWithInt:0] }; msgt=@{ @"messageType":messageType, @"chatId":self.chatId, @"fromId":self.userId, @"fromName":self.username, @"fromAvatar":self.useravatar, @"content":content, @"type":type, @"reSend": [NSNumber numberWithBool:false], @"extend": extend, @"localtime":localtime, @"timestamp":localtime, @"mine":[NSNumber numberWithBool:YES], @"id":localtime, }; msgd=@{ @"messageType":messageType, @"chatId":self.chatId, @"fromId":self.userId, @"fromName":self.username, @"fromAvatar":self.useravatar, @"content":content, @"type":type, @"reSend": [NSNumber numberWithBool:false], @"extend": extend, @"localtime":localtime, @"timestamp":localtime, @"mine":[NSNumber numberWithBool:YES], @"id":@"", }; NSString * tempChatId = self.chatId.mutableCopy; [ChatsStore shareInstance].chatId = tempChatId; [ChatsStore shareInstance].delegate = self; [ChatsStore.shareInstance reciveMsg:msgt]; NSDictionary *sendInfo = @{ @"code":@"2", @"message":msgd, }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; // NSLog(@"%@", jsonString); NSLog(@"----发送文件消息----%@",localtime); //self.ismyTurn = YES; //[GWebSocket.shareInstance sendMsg:jsonString]; } [self movetoBotton]; } if(act==2){ if(url){ [self uploadFileSucc:url localtime:localtime]; } else{ } } } -(void)uploadFileSucc:(NSString *)url localtime:(NSString *)localtime{ if(![url containsString:@"http"]){ url = [[OSSManager sharedManager] fullUploadURLByAppendPath:url]; } NSURL *filePath = [NSURL URLWithString:url]; [GDBManager.shareInstance selectLocalmsgWithLocaltime:localtime succ:^(NSArray * _Nullable array) { // NSLog(@"selectLocalmsgWithLocaltime:%@",array); if(array){ if(array.count>0){ NSDictionary *msg =array[0]; NSDictionary *extend=msg[@"extend"]; NSMutableDictionary *mextend = [extend mutableCopy]; [mextend setObject:url forKey:@"url"]; [mextend setObject:filePath.lastPathComponent forKey:@"fileName"]; NSMutableDictionary *mmsg = [msg mutableCopy]; [mmsg setObject:mextend forKey:@"extend"]; [mmsg setObject:@"" forKey:@"id"]; NSDictionary *sendInfo = @{ @"code":@"2", @"message":mmsg, }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; // NSLog(@"%@", jsonString); NSLog(@"----发送文件消息2----%@",localtime); // self.ismyTurn = YES; [GWebSocket.shareInstance sendMsg:jsonString]; } } } } fail:^(NSString * _Nullable error) { ; }]; } -(void)uploadFilefail:(NSString *)localtime{ NSLog(@"uploadFilefail----:%@",localtime); [GDBManager.shareInstance selectLocalmsgWithLocaltime:localtime succ:^(NSArray * _Nullable array) { NSLog(@"selectLocalmsgWithLocaltime:%@",array); if(array){ if(array.count>0){ NSDictionary *msg =array[0]; NSString *msgtype = msg[@"messageType"]; if (([msgtype isEqualToString:MessageType_Del]||[msgtype isEqualToString:MessageType_CallBack2])) { return; } NSString *strtime = [self getLocalTime]; NSDictionary *extend=msg[@"extend"]; NSMutableDictionary *mextend = [extend mutableCopy]; [mextend setObject:@"" forKey:@"url"]; [mextend setObject:@"" forKey:@"fileName"]; [mextend setObject:[NSNumber numberWithInt:1] forKey:@"fileError"]; NSMutableDictionary *mmsg = [msg mutableCopy]; [mmsg setObject:mextend forKey:@"extend"]; [mmsg setObject:strtime forKey:@"timestamp"]; [ChatsStore.shareInstance reciveMsg:mmsg]; NSDictionary *sendInfo = @{ @"code":@"2", @"message":mmsg, }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; // NSLog(@"%@", jsonString); NSLog(@"----发送文件失败消息2----%@",localtime); // self.ismyTurn = YES; //[GWebSocket.shareInstance sendMsg:jsonString]; } } } } fail:^(NSString * _Nullable error) { ; }]; } -(void)Ossupdatajidu:(NSString *)localtime uploadProgress:(NSInteger )Progress{ [self updateProgress:Progress localtime:localtime]; } - (void)updateProgress:(NSInteger )Progress localtime:(NSString *)localtime { for (chatCellView *cell in self._tableView.visibleCells) { ChatMessageModel *message = cell.messageModel; if(message.localtime==localtime.integerValue){ [cell fileUploadProgressDidChanged:Progress localtime:localtime.integerValue]; } } } #pragma mark 录音发送 -(void)longTarget{ NSLog(@"longTarget----------"); _AVRecordBt.layer.backgroundColor = globalColor(GCTypeGreen).CGColor; [_AVRecordBt setTitle:@" 松开 发送" forState:UIControlStateNormal]; NSDate *now = [NSDate date]; NSTimeInterval trt = [now timeIntervalSince1970]; NSInteger time = trt*1000; _AudiofileName = [NSString stringWithFormat:@"%ld.mp4",(long)time]; _AudiofilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:_AudiofileName]; NSError *error = nil; AVAudioSession *audioSession = [AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; //[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]; [audioSession setActive:YES error:nil]; NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init]; [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey]; [recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey]; //采样率 [recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey]; [recordSetting setValue:[NSNumber numberWithInt: AVAudioQualityMedium] forKey:AVEncoderAudioQualityKey]; NSURL *fileURL = [NSURL fileURLWithPath:_AudiofilePath]; _recorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:recordSetting error:&error]; if (error) { NSLog(@"Error creating recorder: %@", error); } else { [_recorder prepareToRecord]; [_recorder record]; } _rcdL=0; self.heatBeat = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(heartbeatAction) userInfo:nil repeats:YES]; [self.heatBeat setFireDate:[NSDate distantPast]]; [[NSRunLoop currentRunLoop] addTimer:_heatBeat forMode:NSRunLoopCommonModes]; } -(void)heartbeatAction{ if(_rcdL==60){ [_recorder stop]; _recorder=nil; return; } _rcdL=_rcdL+1; } -(void)UpInside{ _AVRecordBt.layer.backgroundColor = globalColor(GCTypeDark2).CGColor; [_AVRecordBt setTitle:@" 按住 说话" forState:UIControlStateNormal]; NSLog(@"UpInside----------"); [_recorder stop]; _recorder=nil; NSURL *yuanfileURL = [NSURL fileURLWithPath:_AudiofilePath]; if(_rcdL<2){//语音太短 [[NSFileManager defaultManager] removeItemAtURL:yuanfileURL error:nil]; [self.heatBeat invalidate]; self.heatBeat = nil; [MBProgressHUD showWithText:@"語音太短"]; return; } NSLog(@"_AudiofilePath:%@",_AudiofilePath); NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:yuanfileURL.lastPathComponent]; // 目标文件路径 NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error = nil; BOOL success = [fileManager copyItemAtPath:_AudiofilePath toPath:destinationPath error:&error]; if (success) { [[NSFileManager defaultManager] removeItemAtURL:yuanfileURL error:nil]; NSLog(@"文件成功复制到本地"); } else { [[NSFileManager defaultManager] removeItemAtURL:yuanfileURL error:nil]; NSLog(@"文件复制失败: %@", error.localizedDescription); [MBProgressHUD showWithText:@"語音發送異常請重試"]; return; } NSLog(@"destinationPath:%@",destinationPath); NSURL *fileURL = [NSURL fileURLWithPath:destinationPath]; ChatFileModel * model = [[ChatFileModel alloc] initWithURL:fileURL]; model.fileURL = fileURL; model.filePath = destinationPath; NSString *strtime = [self getLocalTime]; [self sendYuyinMsg:model.fileURL.lastPathComponent filePth:destinationPath localtime:strtime state:0]; [self OSSuploadFile:model thrid:strtime]; [self.heatBeat invalidate]; self.heatBeat = nil; } -(void)sendYuyinMsg:(NSString *)fileName filePth:(NSString *)filePtah localtime:(NSString *)loacaltime state:(NSInteger)index{ NSString *filePath; if([fileName containsString:@"http"]){ filePath=fileName; } else{ filePath = [[OSSManager sharedManager] fullUploadURLByAppendPath:fileName]; } NSString *content=@"【语音】"; NSString *messageType=[NSString stringWithFormat:@"%@",MessageType_voice]; content= [CryptoAES.shareInstance encryptStringL:content]; NSString *type = [NSString stringWithFormat:@"%ld",(long)self.type]; NSString *localId =loacaltime; if(index==1){ localId=@""; } NSDictionary *dic =@{ @"id":localId, @"messageType":messageType, @"chatId":self.chatId, @"fromId":self.userId, @"fromName":self.username, @"fromAvatar":self.useravatar, @"reSend":[NSNumber numberWithBool:false], @"content":content, @"type":type, @"localtime":loacaltime, @"timestamp":loacaltime, @"mine":[NSNumber numberWithBool:YES], @"extend":@{ @"url":@"", @"time":[NSString stringWithFormat:@"%ld",self->_rcdL], @"localurl":filePtah } }; if(index==0){ [ChatsStore.shareInstance reciveMsg:dic]; } NSDictionary *sendInfo = @{ @"code":@"2", @"message":dic, }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSLog(@"%@", jsonString); // 输出: {"name":"John","age":25} NSLog(@"----发送语音----"); if(index==1){ [GWebSocket.shareInstance sendMsg:jsonString]; } } } -(void)showWebRtcVidio:(NSInteger)state{ if(self.type==1){ [MBProgressHUD showWithText:@"群聊暂时不支持该功能"]; return; } BOOL audioOnly=YES; if(state==4){ audioOnly = YES; } else{ audioOnly = NO; } [[AppDelegate sharedInstance] startJSCall:self.chatId room:@"" isCaller:YES audioOnly:audioOnly]; } #pragma mark take photo or video - (void)takePhoto{ // 检查设备是否支持相机 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { CameraViewController *cameraVC = [[CameraViewController alloc] init]; cameraVC.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:cameraVC animated:YES completion:nil]; weakSelf(self); cameraVC.takePhotoFinishBlock = ^(UIImage * _Nonnull image) { // 保存图片到本地 NSString *savedPath = [self saveImageToSandbox:image]; dispatch_async(dispatch_get_main_queue(), ^{ // 4. 更新UI或处理保存结果 if (savedPath) { NSURL * fileUrl = [NSURL fileURLWithPath:savedPath]; NSString *strtime = [self getLocalTime]; //展示自己发的本地图片 [self uploadFile:[NSString stringWithFormat:@"%@",fileUrl] fpath:savedPath state:1 act:1 localtime:strtime]; [FileNetApi uploadWithFilePath:fileUrl thrid:strtime progress:^(NSString *_Nullable thrid,NSProgress * _Nullable uploadProgress) { } succ:^(int code,NSString *_Nullable thrid, NSDictionary * _Nullable dis) { NSString *reCode =dis[@"code"]; if(reCode.intValue==200){ NSLog(@"上传成功:%@",dis[@"url"]); [weakself uploadFile:dis[@"url"] fpath:savedPath state:1 act:2 localtime:thrid]; } else{ NSLog(@"上传失败"); } } fail:^(NSString *_Nullable thrid,NSError * _Nonnull error) { NSLog(@"上传失败"); }]; } else { NSLog(@"图片保存失败"); } }); }; cameraVC.takeVideoFinishBlock = ^(NSURL * _Nonnull videoUrl) { ChatFileModel * model = [[ChatFileModel alloc] initWithURL:videoUrl]; // ChatFileModel * model = [[ChatFileModel alloc] initWithName:[FileInfoUtils getFileNameWithURL:videoUrl] size:[FileInfoUtils getFileSizeStringWithURL:videoUrl error:nil] isOversize:[FileInfoUtils isFileGreaterThan100MB:videoUrl error:nil]]; model.fileURL = videoUrl; model.filePath = [videoUrl path]; // [weakself handleMediaData:@[model]]; dispatch_async(dispatch_get_main_queue(), ^{ [weakself handleMediaData:@[model]]; }); }; } else { NSLog(@"设备不支持相机"); [MBProgressHUD showWithText:@"设备不支持相机"]; } } #pragma mark menu Actoin - (void)copyMessageContent:(NSString *)content{ UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; pasteboard.string = content; [MBProgressHUD showWithText:NSLocalizedString(@"cellact-copysuccese", @"")]; } - (void)addFavorites:(NSDictionary *)dict{ NSLog(@"----收藏的消息:%@",dict); NSMutableDictionary * favoritesDict = [dict mutableCopy]; NSString *extend = @""; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:favoritesDict[@"extend"] options:0 error:nil]; if (!jsonData) { NSLog(@"Got an error:"); } else { extend = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; } [favoritesDict setValue:extend forKey:@"extend"]; [UserNetApi addFavorites:favoritesDict succ:^(int code, NSDictionary * _Nullable res) { // NSLog(@"------result:%@",res); NSString *ecode = res[@"code"]; if(ecode.intValue==200){ if ([res jk_hasKey:@"msg"] && ![res[@"msg"] isKindOfClass:NSNull.class]) { [MBProgressHUD showWithText:res[@"msg"]]; } } else{ [MBProgressHUD showWithText:NSLocalizedString(@"AppLock_fail", @"收藏失败")]; } } fail:^(NSError * _Nonnull error) { NSLog(@"error:%@",error); }]; } - (void)deleteMyMsg:(NSDictionary *)dict{ NSMutableDictionary * msgDict = [NSMutableDictionary dictionaryWithDictionary:dict]; [msgDict setValue:@"12" forKey:@"messageType"]; [msgDict setValue:@"删除了一条消息" forKey:@"content"]; [ChatsStore.shareInstance reciveMsg:msgDict]; [ChatListStore.shareInstance reciveMsg:msgDict]; // [self cutDataSource:@[dict]]; // [ChatsStore.shareInstance deleteMyLocalMsg:dict]; } //转发 - (void)forwardMsg:(NSArray *)msgArray isMultiple:(BOOL)isMultiple{ // [MBProgressHUD showWithText:@"功能待完善"]; // return; ForwardViewController * forwordVc = [[ForwardViewController alloc] init]; forwordVc.fromChatId = self.chatId; forwordVc.isMultiple = isMultiple; forwordVc.msgArray = msgArray; forwordVc.userName = self.username; forwordVc.userAvatar = self.useravatar; UINavigationController * navi = [[UINavigationController alloc] initWithRootViewController:forwordVc]; navi.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:navi animated:YES completion:nil]; } - (void)batchProcess{ self.isBatchMode = YES; [UIView animateWithDuration:0.5 animations:^{ self.batchView.frame = CGRectMake(0, SCREEN_HEIGHT-SCREEN_X_BTM-64, SCREEN_WIDTH, SCREEN_X_BTM+64); }]; weakSelf(self); __weak typeof(self.batchView) weakView = self.batchView; self.batchView.indexOfBatchClicked = ^(NSInteger index) { weakself.isBatchMode = NO; if (index == 0) {//关闭 }else if (index == 1) { //合并 if (weakself.forwordMsgArray.count == 0) { [MBProgressHUD showWithText:@"请选择转发的消息"]; return; } NSMutableArray * tempForwardArray = weakself.forwordMsgArray.mutableCopy; [weakself forwardMsg:tempForwardArray isMultiple:YES]; [weakself.forwordMsgArray removeAllObjects]; }else if (index == 2) { //逐条 if (weakself.forwordMsgArray.count == 0) { [MBProgressHUD showWithText:@"请选择转发的消息"]; return; } NSMutableArray * tempForwardArray = weakself.forwordMsgArray.mutableCopy; [weakself forwardMsg:tempForwardArray isMultiple:NO]; [weakself.forwordMsgArray removeAllObjects]; }else if (index == 3) { //删除 if (weakself.forwordMsgArray.count == 0) { [MBProgressHUD showWithText:@"请选择删除的消息"]; return; } NSMutableArray * tempForwardArray = weakself.forwordMsgArray.mutableCopy; for (NSDictionary * msg in tempForwardArray) { [weakself deleteMyMsg:msg]; } [weakself.forwordMsgArray removeAllObjects]; } [UIView animateWithDuration:0.5 animations:^{ weakView.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_X_BTM+64); }]; [weakself.forwordMsgArray removeAllObjects]; [weakself._tableView reloadData]; }; [self._tableView reloadData]; } - (void)messageCallback:(NSDictionary *)dict{ // [MBProgressHUD showWithText:@"功能待完善"]; // return; NSMutableDictionary * msgDict = [NSMutableDictionary dictionaryWithDictionary:dict]; NSDate *now = [NSDate date]; NSTimeInterval trt = [now timeIntervalSince1970]; NSInteger time = trt*1000; [msgDict setValue:@"11" forKey:@"messageType"]; [msgDict setValue:@"撤回了一条消息" forKey:@"content"]; [msgDict setValue:[NSString stringWithFormat:@"%ld",time] forKey:@"id"]; // self.msgList = [ChatsStore.shareInstance replaydisData:[msgDict copy] inarray:self.msgList]; [ChatsStore.shareInstance reciveMsg:[msgDict copy]];//预先展示聊天窗信息 [ChatListStore.shareInstance reciveMsg:msgDict]; NSLog(@"撤回---:%@",msgDict); NSDictionary *sendInfo = @{ @"code":@"2", @"message":msgDict, }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error]; if (!jsonData) { NSLog(@"Got an error: %@", error); } else { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; //NSLog(@"%@", jsonString); // 输出: {"name":"John","age":25} NSLog(@"----撤回消息----"); [GWebSocket.shareInstance sendMsg:jsonString]; } [self ifisfileMsg:dict]; } //撤回文件消息,同时取消上传 -(void)ifisfileMsg:(NSDictionary *)msg{ NSString *messageType = msg[@"messageType"]; if ([messageType isEqualToString:MessageType_file]||[messageType isEqualToString:MessageType_video]||[messageType isEqualToString:MessageType_image]) { NSString *lcotime = msg[@"localtime"]; [FileNetApi stopUploadTanck:lcotime]; } } - (void)quoteMessage:(ChatMessageModel *)message{ if (self.isQuoteMessage) { self.quoteView.model = message; [self.inputView becomeFirstResponder]; return; } self.isQuoteMessage = YES; self.quoteView.model = message; self.quoteView.hidden = NO; CGRect buttonViewFrame = self.bottonView.frame; self.bottonView.frame = CGRectMake(buttonViewFrame.origin.x, buttonViewFrame.origin.y-kQuoteViewHeight, buttonViewFrame.size.width, buttonViewFrame.size.height+kQuoteViewHeight); // CGRect inputViewFrame = self.inputView.frame; // self.inputView.frame = CGRectMake(inputViewFrame.origin.x, inputViewFrame.origin.y-kQuoteViewHeight, inputViewFrame.size.width, inputViewFrame.size.height); CGRect audioBtnFrame = self.yuyinctr.frame; self.yuyinctr.frame = CGRectMake(audioBtnFrame.origin.x, audioBtnFrame.origin.y-kQuoteViewHeight, audioBtnFrame.size.height, audioBtnFrame.size.height); CGRect moreFunctionBtnFrame = self.gengduoBt.frame; self.gengduoBt.frame = CGRectMake(moreFunctionBtnFrame.origin.x, moreFunctionBtnFrame.origin.y-kQuoteViewHeight, moreFunctionBtnFrame.size.width, moreFunctionBtnFrame.size.height); CGRect sendBtnFrame = self.fasngBt.frame; self.fasngBt.frame = CGRectMake(sendBtnFrame.origin.x, sendBtnFrame.origin.y-kQuoteViewHeight, sendBtnFrame.size.width, sendBtnFrame.size.height); [self.inputView becomeFirstResponder]; } - (void)closeQuoteView{ self.isQuoteMessage = NO; self.quoteView.hidden = YES; CGRect buttonViewFrame = self.bottonView.frame; self.bottonView.frame = CGRectMake(buttonViewFrame.origin.x, buttonViewFrame.origin.y+kQuoteViewHeight, buttonViewFrame.size.width, buttonViewFrame.size.height-kQuoteViewHeight); self.inputView.frame = CGRectMake(54, 10, self.view.frame.size.width - 180, 40); CGRect audioBtnFrame = self.yuyinctr.frame; self.yuyinctr.frame = CGRectMake(audioBtnFrame.origin.x, audioBtnFrame.origin.y+kQuoteViewHeight, audioBtnFrame.size.height, audioBtnFrame.size.height); CGRect moreFunctionBtnFrame = self.gengduoBt.frame; self.gengduoBt.frame = CGRectMake(moreFunctionBtnFrame.origin.x, moreFunctionBtnFrame.origin.y+kQuoteViewHeight, moreFunctionBtnFrame.size.width, moreFunctionBtnFrame.size.height); CGRect sendBtnFrame = self.fasngBt.frame; self.fasngBt.frame = CGRectMake(sendBtnFrame.origin.x, sendBtnFrame.origin.y+kQuoteViewHeight, sendBtnFrame.size.width, sendBtnFrame.size.height); CGRect tframe = self._tableView.frame; tframe.size.height = self.bottonView.frame.origin.y-tframe.origin.y; self._tableView.frame = tframe; [self movetoBotton]; } - (void)cutDataSource:(NSArray *)msgArray{ NSMutableArray * indexPathArray = [NSMutableArray array]; NSMutableArray * tempArray = [NSMutableArray arrayWithArray:self.messageArray]; for (NSDictionary * msg in msgArray) { for (ChatMessageModel * message in tempArray) { if ([message.formerMessage[@"id"] isEqualToString:msg[@"id"]]) { NSInteger index = [tempArray indexOfObject:message]; [self.messageArray removeObjectAtIndex:index]; NSIndexPath *deleteIndexPath = [NSIndexPath indexPathForRow:index inSection:0]; [indexPathArray addObject:deleteIndexPath]; } } } [CATransaction begin]; [CATransaction setDisableActions:YES]; [self._tableView beginUpdates]; [self._tableView deleteRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationAutomatic]; [self._tableView endUpdates]; [CATransaction commit]; } #pragma mark @相关 - (void)showAtMemberView{ ChatAtMemberView * atView = [[ChatAtMemberView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-200)]; atView.memberArray = [ChatsStore shareInstance].groupUserList; if (self.groupInfo && [self.groupInfo[@"master"] isEqualToString:self.userId]) { atView.isGroupMaster = YES; }else{ atView.isGroupMaster = NO; } //[atView jk_setRoundedCorners:UIRectCornerTopLeft|UIRectCornerTopRight radius:10.f]; PopupView * popup = [[PopupView alloc] init]; popup.customView = atView; popup.position = PopupPositionBottom; popup.animationType = PopupAnimationTypeFromBottom; // 从下往上动画 popup.dismissOnBackgroundTap = YES; // 点击背景关闭 popup.containerType = PopupContainerTypeWindow; // 添加到window [popup showInView:self.view]; weakSelf(self); atView.closeAtViewBlock = ^{ [popup dismiss]; }; atView.atMembersBlock = ^(NSArray * _Nonnull selectedArray) { [popup dismiss]; for (int i = 0; i < selectedArray.count; i++) { NSDictionary * member = selectedArray[i]; [weakself.inputView insertText:[NSString stringWithFormat:@"@%@ ",member[@"name"]]]; } [weakself.atSomeoneArray addObjectsFromArray:selectedArray]; [weakself.inputView becomeFirstResponder]; }; atView.atSingleMemberBlock = ^(NSDictionary * _Nonnull member) { [popup dismiss]; [weakself.inputView insertText:[NSString stringWithFormat:@"@%@ ",member[@"name"]]]; [weakself.atSomeoneArray addObject:member]; [weakself.inputView becomeFirstResponder]; }; atView.atEveryoneBlock = ^{ [popup dismiss]; [weakself.inputView insertText:@"@所有人 "]; [weakself.inputView becomeFirstResponder]; }; } -(void)removeAtList:(NSInteger)index{ if(self.atSomeoneArray.count>index){ [self.atSomeoneArray removeObjectAtIndex:index]; [self textViewDidChange:_inputView]; } } #pragma mark 文件大小排序 -(NSArray *_Nullable)fileArraysort:(NSArray *_Nullable)array{ NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(ChatFileModel *obj1, ChatFileModel *obj2) { if(obj1.bySize0){ ChatMessageModel *lastObj = self.messageArray.lastObject; NSDate *now = [NSDate date]; NSTimeInterval trt = [now timeIntervalSince1970]; NSInteger time = trt*1000; if(time