/************************************************************ * * EaseMob CONFIDENTIAL * __________________ * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. * * NOTICE: All information contained herein is, and remains * the property of EaseMob Technologies. * Dissemination of this information or reproduction of this material * is strictly forbidden unless prior written permission is obtained * from EaseMob Technologies. */ #import "ChatViewController.h" #import #import #import #import "SRRefreshView.h" #import "DXChatBarMoreView.h" #import "DXRecordView.h" #import "DXFaceView.h" #import "EMChatViewCell.h" #import "EMChatTimeCell.h" #import "MessageReadManager.h" #import "MessageModelManager.h" #import "UIViewController+HUD.h" #import "WCAlertView.h" #import "NSDate+Category.h" #import "DXChatBarMoreView.h" #import "FKMessageManager.h" #import "EMCDDeviceManager.h" #import "GalleryScrollView.h" #import "FKWindowViewManager.h" #import "FKCustomerEnquiryView.h" #import "EMChatEnquiryBubbleView.h" #define KPageCount 20 #define BACKGROUNDCOLOR UIColorFromRGB(0xeeeeee); NSString *const QueueNameShouqian = @"shouqian"; NSString *const QueueNameShouhou = @"shouhou"; @interface ChatViewController () { UIMenuController *_menuController; UIMenuItem *_copyMenuItem; UIMenuItem *_deleteMenuItem; NSIndexPath *_longPressIndexPath; NSInteger _recordingCount; BOOL _isScrollToBottom; } @property (nonatomic) BOOL isChatGroup; @property (strong, nonatomic) NSString *chatter; @property (strong, nonatomic) SRRefreshView *slimeView; @property (strong, nonatomic) UIImagePickerController *imagePicker; @property (strong, nonatomic) MessageReadManager *messageReadManager;//message阅读的管理者 @property (strong, nonatomic) NSDate *chatTagDate; @property (nonatomic) BOOL isScrollToBottom; @property (nonatomic) BOOL isPlayingAudio; @property (nonatomic, strong) UIScrollView *galleryScrollView; @end @implementation ChatViewController - (instancetype)initWithChatter:(NSString *)chatter isGroup:(BOOL)isGroup { self = [super initWithNibName:nil bundle:nil]; if (self) { _isPlayingAudio = NO; _chatter = chatter; _isChatGroup = isGroup; _isHasMoreMessage = YES; //根据接收者的username获取当前会话的管理者 _conversation = [[EMClient sharedClient].chatManager getConversation:chatter type:isGroup createIfNotExist:YES]; _messageQueue = dispatch_queue_create("easemob.com", NULL); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadMoreMessages) name:HUANXIN_LOGIN_SUCCESS object:nil]; } return self; } - (void)configChatter:(NSString *)chatter isGroup:(BOOL)isGroup { _isPlayingAudio = NO; _chatter = chatter; _isChatGroup = isGroup; //根据接收者的username获取当前会话的管理者 if (chatter.length > 0) { _conversation = [[EMClient sharedClient].chatManager getConversation:chatter type:isGroup createIfNotExist:YES]; } } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = BACKGROUNDCOLOR; if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { self.edgesForExtendedLayout = UIRectEdgeNone; } [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(exitGroup) name:@"ExitGroup" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:@"applicationDidEnterBackground" object:nil]; _isScrollToBottom = NO; [self setupBarButtonItem]; [self.view addSubview:self.tableView]; self.refreshControl.bottomEnabled = NO; [self.view addSubview:self.chatToolBar]; //将self注册为chatToolBar的moreView的代理 if ([self.chatToolBar.moreView isKindOfClass:[DXChatBarMoreView class]]) { [(DXChatBarMoreView *)self.chatToolBar.moreView setDelegate:self]; } [self loadMoreMessages]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(keyBoardHidden)]; [self.view addGestureRecognizer:tap]; [self.view addSubview:self.galleryScrollView]; } - (void)setupBarButtonItem { if (_isChatGroup) { UIButton *detailButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60, 44)]; [detailButton setImage:[UIImage imageNamed:@"group_detail"] forState:UIControlStateNormal]; [detailButton addTarget:self action:@selector(showRoomContact:) forControlEvents:UIControlEventTouchUpInside]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:detailButton]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.navigationItem.title = self.naviTitle; [UIApplication sharedApplication].statusBarHidden = NO; [self.navigationController setNavigationBarHidden:NO animated:NO]; if ([[EMClient sharedClient] isLoggedIn]) { [self checkAndSendExtMessage]; } } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if (self.isChatGroup) { [[FKMessageManager sharedInstance] addEaseMobDelegate:self observerType:FKEaseMobObserverTypeAssistant]; } else { [[FKMessageManager sharedInstance] addEaseMobDelegate:self observerType:FKEaseMobObserverTypeService]; } //通过会话管理者获取已收发消息 [self loadMoreMessages]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 设置当前conversation的所有message为已读 [_conversation markAllMessagesAsRead:nil]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; if (self.isChatGroup) { [[FKMessageManager sharedInstance] removeEaseMobDelegate:self observerType:FKEaseMobObserverTypeAssistant]; } else { [[FKMessageManager sharedInstance] removeEaseMobDelegate:self observerType:FKEaseMobObserverTypeService]; } } - (void)dealloc { _tableView.delegate = nil; _tableView.dataSource = nil; _tableView = nil; _slimeView.delegate = nil; _slimeView = nil; _chatToolBar.delegate = nil; _chatToolBar = nil; [[EMCDDeviceManager sharedInstance] stopPlaying]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - helper - (NSURL *)convert2Mp4:(NSURL *)movUrl { NSURL *mp4Url = nil; AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:movUrl options:nil]; NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset]; if ([compatiblePresets containsObject:AVAssetExportPresetHighestQuality]) { AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetHighestQuality]; NSString *mp4Path = [NSString stringWithFormat:@"%@/%d%d.mp4", [EMCDDeviceManager dataPath], (int)[[NSDate date] timeIntervalSince1970], arc4random() % 100000]; mp4Url = [NSURL fileURLWithPath:mp4Path]; exportSession.outputURL = mp4Url; exportSession.shouldOptimizeForNetworkUse = YES; exportSession.outputFileType = AVFileTypeMPEG4; dispatch_semaphore_t wait = dispatch_semaphore_create(0l); [exportSession exportAsynchronouslyWithCompletionHandler:^{ switch ([exportSession status]) { case AVAssetExportSessionStatusFailed: { NSLog(@"failed, error:%@.", exportSession.error); } break; case AVAssetExportSessionStatusCancelled: { NSLog(@"cancelled."); } break; case AVAssetExportSessionStatusCompleted: { NSLog(@"completed."); } break; default: { NSLog(@"others."); } break; } dispatch_semaphore_signal(wait); }]; long timeout = dispatch_semaphore_wait(wait, DISPATCH_TIME_FOREVER); if (timeout) { NSLog(@"timeout."); } if (wait) { //dispatch_release(wait); wait = nil; } } return mp4Url; } - (void)configHeadPhotoWith:(MessageModel *)model { if (model.isSender) { model.headPhotoURL = [FKUserManager sharedManager].user.headurl; model.nickName = [FKUserManager sharedManager].user.nickName;; } else { if (self.receiverHeadURL) { model.headPhotoURL = self.receiverHeadURL; NSDictionary *agent = model.message.ext[@"weichat"][@"agent"]; if ([agent isKindOfClass:[NSDictionary class]]) { NSString *nickName = agent[@"userNickname"]; if ([nickName isKindOfClass:[NSString class]]) { if ([nickName isEqualToString:@"调度员"]) { model.nickName = self.naviTitle; } else { model.nickName = nickName; } } else { model.nickName = self.naviTitle ? : @"剁剁小秘书"; } } } // else { // model.headPhotoURL = [FKAssistantReform parseHeadPhotoURL:model.message.ext]; // } } } - (void)finishLoadingDataWith:(NSTimeInterval)interval { [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(finishLoadingData) userInfo:nil repeats:NO]; } #pragma mark - getter - (NSMutableArray *)dataSource { if (_dataSource == nil) { _dataSource = [NSMutableArray array]; } return _dataSource; } - (SRRefreshView *)slimeView { if (_slimeView == nil) { _slimeView = [[SRRefreshView alloc] init]; _slimeView.delegate = self; _slimeView.upInset = 0; _slimeView.slimeMissWhenGoingBack = YES; _slimeView.slime.bodyColor = [UIColor grayColor]; _slimeView.slime.skinColor = [UIColor grayColor]; _slimeView.slime.lineWith = 1; _slimeView.slime.shadowBlur = 4; _slimeView.slime.shadowColor = [UIColor grayColor]; } return _slimeView; } - (UITableView *)tableView { if (_tableView == nil) { _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - self.chatToolBar.frame.size.height) style:UITableViewStylePlain]; _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; _tableView.delegate = self; _tableView.dataSource = self; _tableView.backgroundColor = BACKGROUNDCOLOR; _tableView.tableFooterView = [[UIView alloc] init]; _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; lpgr.minimumPressDuration = .5; [_tableView addGestureRecognizer:lpgr]; [self initRefreshControlWithTableView:_tableView]; } return _tableView; } - (DXMessageToolBar *)chatToolBar { if (_chatToolBar == nil) { _chatToolBar = [[DXMessageToolBar alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - [DXMessageToolBar defaultHeight], self.view.frame.size.width, [DXMessageToolBar defaultHeight])]; _chatToolBar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin; _chatToolBar.delegate = self; ChatMoreType type = _isChatGroup == YES ? ChatMoreTypeGroupChat : ChatMoreTypeChat; _chatToolBar.moreView = [[DXChatBarMoreView alloc] initWithFrame:CGRectMake(0, (kVerticalPadding * 2 + kInputTextViewMinHeight), _chatToolBar.frame.size.width, 100) typw:type]; _chatToolBar.moreView.backgroundColor = [UIColor whiteColor]; _chatToolBar.moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; } return _chatToolBar; } - (UIImagePickerController *)imagePicker { if (_imagePicker == nil) { _imagePicker = [[UIImagePickerController alloc] init]; _imagePicker.delegate = self; } return _imagePicker; } - (MessageReadManager *)messageReadManager { if (_messageReadManager == nil) { _messageReadManager = [MessageReadManager defaultManager]; } return _messageReadManager; } - (NSDate *)chatTagDate { if (_chatTagDate == nil) { _chatTagDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:0]; } return _chatTagDate; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataSource.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row < [self.dataSource count]) { id obj = [self.dataSource objectAtIndex:indexPath.row]; if ([obj isKindOfClass:[NSString class]]) { EMChatTimeCell *timeCell = (EMChatTimeCell *)[tableView dequeueReusableCellWithIdentifier:@"MessageCellTime"]; if (timeCell == nil) { timeCell = [[EMChatTimeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MessageCellTime"]; timeCell.backgroundColor = [UIColor clearColor]; timeCell.selectionStyle = UITableViewCellSelectionStyleNone; } timeCell.textLabel.text = (NSString *)obj; return timeCell; } else { MessageModel *model = (MessageModel *)obj; [self configHeadPhotoWith:model]; NSString *cellIdentifier = [EMChatViewCell cellIdentifierForMessageModel:model]; EMChatViewCell *cell = (EMChatViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[EMChatViewCell alloc] initWithMessageModel:model reuseIdentifier:cellIdentifier]; cell.backgroundColor = [UIColor clearColor]; cell.selectionStyle = UITableViewCellSelectionStyleNone; } cell.messageModel = model; if ([cell.bubbleView isKindOfClass:[EMChatEnquiryBubbleView class]]) { WeakSelf(weakSelf); EMChatEnquiryBubbleView *bubbleView = (EMChatEnquiryBubbleView*)cell.bubbleView; bubbleView.enquiryCellCallback = ^() { [weakSelf showEnquiryView:model]; }; } return cell; } } return nil; } #pragma mark - Table view delegate -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSObject *obj = [self.dataSource objectAtIndex:indexPath.row]; if ([obj isKindOfClass:[NSString class]]) { return 40; } else { MessageModel *model = (MessageModel *)obj; return [EMChatViewCell tableView:tableView heightForRowAtIndexPath:indexPath withObject:model]; } } #pragma mark - RefreshControlDelegate - (void)refreshControl:(FKRefreshControl *)refreshControl didEngageRefreshDirection:(RefreshDirection)direction { [self finishLoadingDataWith:0.5]; } #pragma mark - GestureRecognizer // 点击背景隐藏 -(void)keyBoardHidden { [self.chatToolBar endEditing:YES]; } - (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer { if (recognizer.state == UIGestureRecognizerStateBegan && [self.dataSource count] > 0) { CGPoint location = [recognizer locationInView:self.tableView]; NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:location]; id object = [self.dataSource objectAtIndex:indexPath.row]; if ([object isKindOfClass:[MessageModel class]]) { EMChatViewCell *cell = (EMChatViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; [cell becomeFirstResponder]; _longPressIndexPath = indexPath; [self showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.messageModel.type]; } } } #pragma mark - UIResponder actions - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { MessageModel *model = [userInfo objectForKey:KMESSAGEKEY]; UIImageView *imageView = [userInfo objectForKey:KMESSAGE_IMAGEVIEW_KEY]; if ([eventName isEqualToString:kRouterEventTextURLTapEventName]) { [self chatTextCellUrlPressed:[userInfo objectForKey:@"url"]]; } else if ([eventName isEqualToString:kRouterEventAudioBubbleTapEventName]) { [self chatAudioCellBubblePressed:model]; } else if ([eventName isEqualToString:kRouterEventImageBubbleTapEventName]){ [self chatImageCellBubblePressed:model imageView:imageView]; } else if ([eventName isEqualToString:kRouterEventLocationBubbleTapEventName]){ [self chatLocationCellBubblePressed:model]; } else if([eventName isEqualToString:kResendButtonTapEventName]){ EMChatViewCell *resendCell = [userInfo objectForKey:kShouldResendCell]; MessageModel *messageModel = resendCell.messageModel; messageModel.status = EMMessageStatusDelivering; NSIndexPath *indexPath = [self.tableView indexPathForCell:resendCell]; [self.tableView beginUpdates]; [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; [self.tableView endUpdates]; id chatManager = [[EMClient sharedClient] chatManager]; [chatManager sendMessage:messageModel.message progress:nil completion:nil]; } else if ([eventName isEqualToString:kRouterEventChatHeadImageTapEventName]) { // MessageModel *model = userInfo[KMESSAGEKEY]; } else if([eventName isEqualToString:kRouterEventChatCellVideoTapEventName]){ [self chatVideoCellPressed:model]; } } //链接被点击 - (void)chatTextCellUrlPressed:(NSURL *)url { if (url) { [[UIApplication sharedApplication] openURL:url]; } } // 语音的bubble被点击 -(void)chatAudioCellBubblePressed:(MessageModel *)model { EMVoiceMessageBody *body = model.message.body; EMDownloadStatus downloadStatus = [body downloadStatus]; if (downloadStatus == EMDownloadStatusDownloading) { [self showHint:@"正在下载语音,稍后点击"]; return; } else if (downloadStatus == EMDownloadStatusFailed) { [self showHint:@"正在下载语音,稍后点击"]; [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:nil]; return; } // 播放音频 if (body.type == EMMessageBodyTypeVoice) { __weak ChatViewController *weakSelf = self; BOOL isPrepare = [self.messageReadManager prepareMessageAudioModel:model updateViewCompletion:^(MessageModel *prevAudioModel, MessageModel *currentAudioModel) { if (prevAudioModel || currentAudioModel) { [weakSelf.tableView reloadData]; } }]; if (isPrepare) { _isPlayingAudio = YES; // __weak ChatViewController *weakSelf = self; // [[[EaseMob sharedInstance] deviceManager] enableProximitySensor]; // [[EaseMob sharedInstance].chatManager asyncPlayAudio:model.chatVoice completion:^(EMError *error) { // [weakSelf.messageReadManager stopMessageAudioModel]; // // dispatch_async(dispatch_get_main_queue(), ^{ // [weakSelf.tableView reloadData]; // // weakSelf.isPlayingAudio = NO; // [[[EaseMob sharedInstance] deviceManager] disableProximitySensor]; // }); // } onQueue:nil]; } else{ _isPlayingAudio = NO; } } } // 位置的bubble被点击 -(void)chatLocationCellBubblePressed:(MessageModel *)model { _isScrollToBottom = NO; } - (void)chatVideoCellPressed:(MessageModel *)model{ // __weak ChatViewController *weakSelf = self; // id chatManager = [[EaseMob sharedInstance] chatManager]; // [weakSelf showHudInView:weakSelf.view hint:@"正在获取视频..."]; // [chatManager asyncFetchMessage:model.message progress:nil completion:^(EMMessage *aMessage, EMError *error) { // [weakSelf hideHud]; // if (!error) { // NSString *localPath = aMessage == nil ? model.localPath : [[aMessage.messageBodies firstObject] localPath]; // if (localPath && localPath.length > 0) { // [weakSelf playVideoWithVideoPath:localPath]; // } // }else{ // [weakSelf showHint:@"视频获取失败!"]; // } // } onQueue:nil]; } - (void)playVideoWithVideoPath:(NSString *)videoPath { _isScrollToBottom = NO; NSURL *videoURL = [NSURL fileURLWithPath:videoPath]; MPMoviePlayerViewController *moviePlayerController = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL]; [moviePlayerController.moviePlayer prepareToPlay]; moviePlayerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile; [self presentMoviePlayerViewControllerAnimated:moviePlayerController]; } // 图片的bubble被点击 -(void)chatImageCellBubblePressed:(MessageModel *)model imageView:(UIImageView *)imageView { __weak ChatViewController *weakSelf = self; if ([model.messageBody type] == EMMessageBodyTypeImage) { EMImageMessageBody *imageBody = (EMImageMessageBody *)[model.message body]; if (imageBody.thumbnailDownloadStatus == EMDownloadStatusSuccessed) { [weakSelf showHudInView:weakSelf.view hint:@"正在获取大图..."]; [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:^(EMMessage *message, EMError *error) { [weakSelf hideHud]; if (!error) { //send the acknowledgement [weakSelf sendHasReadResponseForMessages:@[model.message] isRead:YES]; NSString *localPath = message == nil ? model.localPath : [(EMImageMessageBody*)message.body localPath]; if (localPath && localPath.length > 0) { UIImage *image = [UIImage imageWithContentsOfFile:localPath]; weakSelf.isScrollToBottom = NO; if (image) { [self tapImage:image imageView:imageView]; } return ; } } [weakSelf showHint:@"大图获取失败!"]; }]; } else { //获取缩略图 [[EMClient sharedClient].chatManager downloadMessageThumbnail:model.message progress:nil completion:^(EMMessage *message, EMError *error) { if (!error) { [weakSelf reloadTableViewDataWithMessage:model.message]; }else{ [weakSelf showHint:@"缩略图获取失败!"]; } }]; } } } #pragma mark - IChatManagerDelegate //-(void)didSendMessage:(EMMessage *)message error:(EMError *)error; //{ // [self.dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) // { // if ([obj isKindOfClass:[MessageModel class]]) // { // MessageModel *model = (MessageModel*)obj; // if ([model.messageId isEqualToString:message.messageId]) // { // model.message.deliveryState = message.deliveryState; // *stop = YES; // } // } // }]; // [self.tableView reloadData]; //} - (void)reloadTableViewDataWithMessage:(EMMessage *)message{ __weak ChatViewController *weakSelf = self; dispatch_async(_messageQueue, ^{ if ([weakSelf.conversation.conversationId isEqualToString:message.conversationId]) { for (int i = 0; i < weakSelf.dataSource.count; i ++) { id object = [weakSelf.dataSource objectAtIndex:i]; if ([object isKindOfClass:[MessageModel class]]) { EMMessage *currMsg = [weakSelf.dataSource objectAtIndex:i]; if ([message.messageId isEqualToString:currMsg.messageId]) { MessageModel *cellModel = [MessageModelManager modelWithMessage:message]; dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf.tableView beginUpdates]; [weakSelf.dataSource replaceObjectAtIndex:i withObject:cellModel]; [weakSelf.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; [weakSelf.tableView endUpdates]; }); break; } } } } }); } - (void)didMessageAttachmentsStatusChanged:(EMMessage *)message error:(EMError *)error{ if (!error) { EMFileMessageBody *fileBody = (EMFileMessageBody*)[message body]; if ([fileBody type] == EMMessageBodyTypeImage) { EMImageMessageBody *imageBody = (EMImageMessageBody *)fileBody; if ([imageBody thumbnailDownloadStatus] == EMDownloadStatusSuccessed) { [self reloadTableViewDataWithMessage:message]; } } else if([fileBody type] == EMMessageBodyTypeVideo){ EMVideoMessageBody *videoBody = (EMVideoMessageBody *)fileBody; if ([videoBody thumbnailDownloadStatus] == EMDownloadStatusSuccessed) { [self reloadTableViewDataWithMessage:message]; } } else if([fileBody type] == EMMessageBodyTypeVoice){ if ([fileBody downloadStatus] == EMDownloadStatusSuccessed) { [self reloadTableViewDataWithMessage:message]; } } } else { } } - (void)didFetchingMessageAttachments:(EMMessage *)message progress:(float)progress{ NSLog(@"didFetchingMessageAttachment: %f", progress); } - (void)messagesDidReceive:(NSArray *)aMessages { for (EMMessage *message in aMessages) { if ([_conversation.conversationId isEqualToString:message.conversationId]) { [self addChatDataToMessage:message]; } } } - (void)messagesDidDeliver:(NSArray *)aMessages { for (EMMessage *message in aMessages) { [self.dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if ([obj isKindOfClass:[MessageModel class]]) { MessageModel *model = (MessageModel*)obj; if ([model.messageId isEqualToString:message.messageId]) { model.status = message.status; model.message.status = message.status; *stop = YES; } } }]; } [self.tableView reloadData]; } - (void)group:(EMGroup *)group didLeave:(EMGroupLeaveReason)reason error:(EMError *)error { if (_isChatGroup && [group.groupId isEqualToString:_chatter]) { [self.navigationController popToViewController:self animated:NO]; [self.navigationController popViewControllerAnimated:NO]; } } - (void)didInterruptionRecordAudio { [_chatToolBar cancelTouchRecord]; // 设置当前conversation的所有message为已读 [_conversation markAllMessagesAsRead:nil]; [self stopAudioPlaying]; } #pragma mark - EMChatBarMoreViewDelegate - (void)moreViewPhotoAction:(DXChatBarMoreView *)moreView { // 隐藏键盘 [self keyBoardHidden]; // 弹出照片选择 self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; self.imagePicker.mediaTypes = @[(NSString *)kUTTypeImage]; [self presentViewController:self.imagePicker animated:YES completion:NULL]; } - (void)moreViewTakePicAction:(DXChatBarMoreView *)moreView { [self keyBoardHidden]; #if TARGET_IPHONE_SIMULATOR [self showHint:@"模拟器不支持拍照"]; #elif TARGET_OS_IPHONE self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; self.imagePicker.mediaTypes = @[(NSString *)kUTTypeImage]; [self presentViewController:self.imagePicker animated:YES completion:NULL]; #endif } - (void)moreViewLocationAction:(DXChatBarMoreView *)moreView { // 隐藏键盘 [self keyBoardHidden]; } - (void)moreViewVideoAction:(DXChatBarMoreView *)moreView{ [self keyBoardHidden]; #if TARGET_IPHONE_SIMULATOR [self showHint:@"模拟器不支持录像"]; #elif TARGET_OS_IPHONE self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; self.imagePicker.mediaTypes = @[(NSString *)kUTTypeMovie]; [self presentViewController:self.imagePicker animated:YES completion:NULL]; #endif } #pragma mark - LocationViewDelegate -(void)sendLocationLatitude:(double)latitude longitude:(double)longitude andAddress:(NSString *)address { } #pragma mark - NavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault]; } #pragma mark - DXMessageToolBarDelegate - (void)didStyleChangeToRecord:(BOOL)changedToRecord { [self beginTouchMessageToolBar]; } - (void)inputTextViewWillBeginEditing:(XHMessageTextView *)messageInputTextView{ [_menuController setMenuItems:nil]; [self beginTouchMessageToolBar]; } - (void)didChangeFrameToHeight:(CGFloat)toHeight { // [self beginTouchMessageToolBar]; [UIView animateWithDuration:0.3 animations:^{ CGRect rect = self.tableView.frame; rect.origin.y = 0; rect.size.height = self.view.frame.size.height - toHeight; self.tableView.frame = rect; }]; [self scrollViewToBottom:YES]; } - (void)didSendText:(NSString *)text { if (text && text.length > 0) { [self sendTextMessage:text]; } } - (void)didSelectedFaceButton:(BOOL)isSelected { [self beginTouchMessageToolBar]; } - (void)didSelectedMoreButton:(BOOL)isSelected { [self beginTouchMessageToolBar]; } - (void)didSelectedMorePhotoButton { [self.navigationController presentViewController:self.imagePicker animated:YES completion:^{ [self.chatToolBar resignFirstResponder]; }]; } - (void)didSelectedMoreCameraButton { [self beginTouchMessageToolBar]; UIImagePickerController *cameraPicker = [[UIImagePickerController alloc] init]; cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera; cameraPicker.delegate = self; [self.navigationController presentViewController:cameraPicker animated:YES completion:^{ [self.chatToolBar resignFirstResponder]; }]; } /** * 按下录音按钮开始录音 */ - (void)didStartRecordingVoiceAction:(UIView *)recordView { [self beginTouchMessageToolBar]; DXRecordView *tmpView = (DXRecordView *)recordView; tmpView.center = self.view.center; [self.view addSubview:tmpView]; [self.view bringSubviewToFront:recordView]; // NSError *error = nil; // [[EaseMob sharedInstance].chatManager startRecordingAudioWithError:&error]; // if (error) { // NSLog(@"开始录音失败"); // } } /** * 手指向上滑动取消录音 */ - (void)didCancelRecordingVoiceAction:(UIView *)recordView { // [[EaseMob sharedInstance].chatManager asyncCancelRecordingAudioWithCompletion:nil onQueue:nil]; } /** * 松开手指完成录音 */ - (void)didFinishRecoingVoiceAction:(UIView *)recordView { // WeakSelf(weakSelf); // [[EaseMob sharedInstance].chatManager // asyncStopRecordingAudioWithCompletion:^(EMChatVoice *aChatVoice, NSError *error){ // if (!error) { // [self sendAudioMessage:aChatVoice]; // }else{ // if (error.code == EMErrorAudioRecordNotStarted) { // [FLProgressHUDHelper showText:@"录音没有开始" inView:weakSelf.view]; // } else { // [FLProgressHUDHelper showText:@"说话时间太短" inView:weakSelf.view]; // } // } // // } onQueue:nil]; } #pragma mark - UIImagePickerControllerDelegate - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { NSString *mediaType = info[UIImagePickerControllerMediaType]; if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) { // NSURL *videoURL = info[UIImagePickerControllerMediaURL]; // [picker dismissViewControllerAnimated:YES completion:nil]; // video url: // file:///private/var/mobile/Applications/B3CDD0B2-2F19-432B-9CFA-158700F4DE8F/tmp/capture-T0x16e39100.tmp.9R8weF/capturedvideo.mp4 // we will convert it to mp4 format // NSURL *mp4 = [self convert2Mp4:videoURL]; // NSFileManager *fileman = [NSFileManager defaultManager]; // if ([fileman fileExistsAtPath:videoURL.path]) { // NSError *error = nil; // [fileman removeItemAtURL:videoURL error:&error]; // if (error) { // NSLog(@"failed to remove file, error:%@.", error); // } // } } else { UIImage *orgImage = info[UIImagePickerControllerOriginalImage]; [picker dismissViewControllerAnimated:YES completion:nil]; [self sendImageMessage:orgImage]; } } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [self.imagePicker dismissViewControllerAnimated:YES completion:nil]; } #pragma mark - MenuItem actions - (void)copyMenuAction:(id)sender { // todo by du. 复制 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; if (_longPressIndexPath.row > 0) { MessageModel *model = [self.dataSource objectAtIndex:_longPressIndexPath.row]; pasteboard.string = model.content; } _longPressIndexPath = nil; } - (void)deleteMenuAction:(id)sender { if (_longPressIndexPath && _longPressIndexPath.row > 0) { MessageModel *model = [self.dataSource objectAtIndex:_longPressIndexPath.row]; NSMutableArray *messages = [NSMutableArray arrayWithObjects:model, nil]; [_conversation deleteMessageWithId:model.message.messageId error:nil]; NSMutableArray *indexPaths = [NSMutableArray arrayWithObjects:_longPressIndexPath, nil];; if (_longPressIndexPath.row - 1 >= 0) { id nextMessage = nil; id prevMessage = [self.dataSource objectAtIndex:(_longPressIndexPath.row - 1)]; if (_longPressIndexPath.row + 1 < [self.dataSource count]) { nextMessage = [self.dataSource objectAtIndex:(_longPressIndexPath.row + 1)]; } if ((!nextMessage || [nextMessage isKindOfClass:[NSString class]]) && [prevMessage isKindOfClass:[NSString class]]) { [messages addObject:prevMessage]; [indexPaths addObject:[NSIndexPath indexPathForRow:(_longPressIndexPath.row - 1) inSection:0]]; } } [self.dataSource removeObjectsInArray:messages]; [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade]; } _longPressIndexPath = nil; } - (void)beginTouchMessageToolBar { } #pragma mark - Method - (void)showEnquiryView:(MessageModel*)model { [self.chatToolBar removeKeyboardEvent]; CGFloat width = 275, height = 400; FKCustomerEnquiryView *view = [FKCustomerEnquiryView new]; view.frame = CGRectMake((UISCREENWIDTH-width)/2, (UISCREENHEIGH-height)/2, width, height); if (self.receiverHeadURL) { [view.headImgView sd_setImageWithURL:[NSURL URLWithString:self.receiverHeadURL]]; } WeakSelf(weakSelf); view.enquirySubmitCallback = ^(NSString *summary, NSString *detail) { if (summary.length > 0) { NSDictionary *weichat = model.message.ext[@"weichat"]; if ([weichat isKindOfClass:[NSDictionary class]]) { NSString *ctrlType = weichat[@"ctrlType"]; NSDictionary *ctrlArgs = weichat[@"ctrlArgs"]; NSString *inviteId; NSString *serviceSessionId; if ([ctrlArgs isKindOfClass:[NSDictionary class]]) { inviteId = [NSString stringWithFormat:@"%@", ctrlArgs[@"inviteId"]]; serviceSessionId = ctrlArgs[@"serviceSessionId"]; } if (ctrlType.length > 0 && inviteId.length > 0 && serviceSessionId.length > 0) { NSDictionary *ext = @{@"weichat": @{@"ctrlType": @"enquiry", @"ctrlArgs": @{@"inviteId": inviteId, @"serviceSessionId": serviceSessionId, @"summary": summary, @"detail": [FLStringHelper replaceNilWithEmpty:detail]}}}; EMMessage *message = [ChatSendHelper sendTextMessageWithString:@"用户已评价" toUsername:weakSelf.conversation.conversationId messageType:NO requireEncryption:NO ext:ext]; [weakSelf addChatDataToMessage:message]; } } } [weakSelf.chatToolBar configKeyboardEvent]; }; [[FKWindowViewManager sharedManager] appendFloatView:view]; [[FKWindowViewManager sharedManager] showFloatView:nil]; } - (void)sendHasReadResponseForMessages:(NSArray*)messages isRead:(BOOL)isRead { NSMutableArray *unreadMessages = [NSMutableArray array]; for (NSInteger i = 0; i < [messages count]; i++) { EMMessage *message = messages[i]; BOOL isSend = [self shouldSendHasReadAckForMessage:message read:isRead]; if (isSend) { [unreadMessages addObject:message]; } } if ([unreadMessages count]) { for (EMMessage *message in unreadMessages) { [[EMClient sharedClient].chatManager sendMessageReadAck:message completion:nil]; } } } - (BOOL)shouldSendHasReadAckForMessage:(EMMessage *)message read:(BOOL)read { NSString *account = [[EMClient sharedClient] currentUsername]; if (message.chatType != EMChatTypeChat || message.isReadAcked || [account isEqualToString:message.from] || ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)) { return NO; } EMMessageBody *body = message.body; if (((body.type == EMMessageBodyTypeVideo) || (body.type == EMMessageBodyTypeVoice) || (body.type == EMMessageBodyTypeImage)) && !read) { return NO; } return YES; } #pragma mark - private - (BOOL)canRecord { __block BOOL bCanRecord = YES; if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending) { dispatch_semaphore_t sema = dispatch_semaphore_create(0); AVAudioSession *audioSession = [AVAudioSession sharedInstance]; if ([audioSession respondsToSelector:@selector(requestRecordPermission:)]) { [audioSession performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) { if (granted) { bCanRecord = YES; } else { bCanRecord = NO; } }]; } dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); } return bCanRecord; } - (void)stopAudioPlaying { //停止音频播放及播放动画 [[EMCDDeviceManager sharedInstance] stopPlaying]; MessageModel *playingModel = [self.messageReadManager stopMessageAudioModel]; NSIndexPath *indexPath = nil; if (playingModel) { indexPath = [NSIndexPath indexPathForRow:[self.dataSource indexOfObject:playingModel] inSection:0]; } if (indexPath) { dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView beginUpdates]; [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; [self.tableView endUpdates]; }); } } - (void)loadMoreMessages { __weak typeof(self) weakSelf = self; EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:self.chatter type:EMConversationTypeChat createIfNotExist:YES]; [conversation loadMessagesStartFromId:nil count:1000 searchDirection:EMMessageSearchDirectionUp completion:^(NSArray *aMessages, EMError *aError) { if ([aMessages count] > 0) { dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.dataSource.array = [weakSelf sortChatSource:aMessages]; [weakSelf.tableView reloadData]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:MAX(0, [weakSelf.dataSource count] - 1) inSection:0]; [weakSelf.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; [weakSelf finishLoadingDataWith:0.5]; }); } }]; } - (NSArray *)sortChatSource:(NSArray *)array { NSMutableArray *resultArray = [[NSMutableArray alloc] init]; if (array && [array count] > 0) { for (EMMessage *message in array) { NSDate *createDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:(NSTimeInterval)message.timestamp]; NSTimeInterval tempDate = [createDate timeIntervalSinceDate:self.chatTagDate]; if (tempDate > 120 || tempDate < -120 || (self.chatTagDate == nil)) { [resultArray addObject:[FLStringHelper dateForMessage:createDate]]; self.chatTagDate = createDate; } MessageModel *model = [MessageModelManager modelWithMessage:message]; if (model) { [resultArray addObject:model]; } } } return resultArray; } -(NSMutableArray *)addChatToMessage:(EMMessage *)message { NSMutableArray *ret = [[NSMutableArray alloc] init]; NSDate *createDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:(NSTimeInterval)message.timestamp]; NSTimeInterval tempDate = [createDate timeIntervalSinceDate:self.chatTagDate]; if (tempDate > 60 || tempDate < -60 || (self.chatTagDate == nil)) { [ret addObject:[createDate formattedTime]]; self.chatTagDate = createDate; } MessageModel *model = [MessageModelManager modelWithMessage:message]; if (model) { [ret addObject:model]; } return ret; } -(void)addChatDataToMessage:(EMMessage *)message { __weak ChatViewController *weakSelf = self; dispatch_async(_messageQueue, ^{ NSArray *messages = [weakSelf addChatToMessage:message]; NSMutableArray *indexPaths = [[NSMutableArray alloc] init]; for (int i = 0; i < messages.count; i++) { NSIndexPath *indexPath = [NSIndexPath indexPathForRow:weakSelf.dataSource.count+i inSection:0]; [indexPaths addObject:indexPath]; } dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf.tableView beginUpdates]; [weakSelf.dataSource addObjectsFromArray:messages]; [weakSelf.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone]; [weakSelf.tableView endUpdates]; [weakSelf.tableView reloadData]; [weakSelf.tableView scrollToRowAtIndexPath:[indexPaths lastObject] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }); }); } - (void)scrollViewToBottom:(BOOL)animated { if (self.tableView.contentSize.height > self.tableView.frame.size.height) { CGPoint offset = CGPointMake(0, self.tableView.contentSize.height - self.tableView.frame.size.height); [self.tableView setContentOffset:offset animated:YES]; } } - (void)showRoomContact:(id)sender { [self.view endEditing:YES]; } - (void)showMenuViewController:(UIView *)showInView andIndexPath:(NSIndexPath *)indexPath messageType:(EMMessageBodyType)messageType { if (_menuController == nil) { _menuController = [UIMenuController sharedMenuController]; } if (_copyMenuItem == nil) { _copyMenuItem = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copyMenuAction:)]; } if (_deleteMenuItem == nil) { _deleteMenuItem = [[UIMenuItem alloc] initWithTitle:@"删除" action:@selector(deleteMenuAction:)]; } if (messageType == EMMessageBodyTypeText) { [_menuController setMenuItems:@[_copyMenuItem, _deleteMenuItem]]; } else{ [_menuController setMenuItems:@[_deleteMenuItem]]; } [_menuController setTargetRect:showInView.frame inView:showInView.superview]; [_menuController setMenuVisible:YES animated:YES]; } - (void)exitGroup { [self.navigationController popToViewController:self animated:NO]; [self.navigationController popViewControllerAnimated:YES]; } - (void)applicationDidEnterBackground { [_chatToolBar cancelTouchRecord]; [_conversation markAllMessagesAsRead:nil]; } #pragma mark - send message - (void)checkAndSendExtMessage { if (self.msgExtData) { EMMessage *message = [ChatSendHelper sendTextMessageWithString:self.msgExtData[EXT_MSG_ORDER_TITLE] toUsername:_conversation.conversationId messageType:NO requireEncryption:NO ext:self.msgExtData]; [self addChatDataToMessage:message]; self.msgExtData = nil; } } -(void)sendTextMessage:(NSString *)textMessage { NSDictionary *extDict = nil; if (self.myNickname) { extDict = @{SendMSGNicknameKey: self.myNickname}; } EMMessage *message = [ChatSendHelper sendTextMessageWithString:textMessage toUsername:_conversation.conversationId messageType:_isChatGroup requireEncryption:NO ext:extDict]; [self addChatDataToMessage:message]; } -(void)sendImageMessage:(UIImage *)imageMessage { EMMessage *tempMessage = [ChatSendHelper sendImageMessageWithImage:imageMessage toUsername:_conversation.conversationId isChatGroup:_isChatGroup requireEncryption:NO]; [self addChatDataToMessage:tempMessage]; } #pragma mark - EMDeviceManagerProximitySensorDelegate - (void)proximitySensorChanged:(BOOL)isCloseToUser{ //如果此时手机靠近面部放在耳朵旁,那么声音将通过听筒输出,并将屏幕变暗(省电啊) if (isCloseToUser)//黑屏 { // 使用耳机播放 // [[EaseMob sharedInstance].deviceManager switchAudioOutputDevice:eAudioOutputDevice_earphone]; } else { // 使用扬声器播放 // [[EaseMob sharedInstance].deviceManager switchAudioOutputDevice:eAudioOutputDevice_speaker]; // if (!_isPlayingAudio) { // [[[EaseMob sharedInstance] deviceManager] disableProximitySensor]; // } } } #pragma mark - Photo GalleryScrollView - (CGSize)photoSize:(NSString *)photoSizeStr { if (!photoSizeStr || photoSizeStr.length == 0) { return CGSizeZero; } NSArray *compoment = [photoSizeStr componentsSeparatedByString:@"x"]; if (compoment.count >= 2) { CGFloat ratio = [compoment[0] floatValue]/[compoment[1] floatValue]; CGFloat width = (CGRectGetWidth([UIScreen mainScreen].bounds) - 2*8); CGFloat height = width/ratio; return CGSizeMake(width, height); } else { return CGSizeZero; } } - (UIScrollView *)galleryScrollView { if (!_galleryScrollView) { _galleryScrollView = [[UIScrollView alloc] initWithFrame:[self galleryContentFrame]]; _galleryScrollView.backgroundColor = [UIColor blackColor]; _galleryScrollView.pagingEnabled = YES; _galleryScrollView.alpha = 0.0; } return _galleryScrollView; } - (CGRect)galleryContentFrame { float height = [UIScreen mainScreen].bounds.size.height; float width = [UIScreen mainScreen].bounds.size.width; return CGRectMake(0, 0, width, height); } - (void)tapImage:(UIImage *)photo imageView:(UIImageView *)imageView { if (!photo) { return; } [self.view bringSubviewToFront:self.galleryScrollView]; self.galleryScrollView.alpha = 1.0; [self.navigationController setNavigationBarHidden:YES animated:YES]; // 添加 [self galleryAddSubImage:photo imageView:imageView]; } - (void)setGalleryScrollViewCallBack:(GalleryScrollView *)scrollView { __weak ChatViewController *weakSelf = self; scrollView.touchCallBack = ^(GalleryScrollView *scrollView, int index) { [weakSelf.navigationController setNavigationBarHidden:NO animated:YES]; [UIView animateWithDuration:0.5 animations:^{ [scrollView resetFrame]; } completion:^(BOOL finished) { weakSelf.galleryScrollView.alpha = 0; }]; }; } - (void)setOriginalFrame:(GalleryScrollView *)sender { [UIView animateWithDuration:0.4 animations:^{ [sender setAnimationRect]; }]; } - (void)galleryAddSubImage:(UIImage *)image imageView:(UIImageView *)imageView { if (!image || !imageView) { return; } for (UIView *view in self.galleryScrollView.subviews) { [view removeFromSuperview]; } CGRect convertRect = [imageView.superview convertRect:imageView.frame toView:self.view]; CGPoint contentOffset = self.galleryScrollView.contentOffset; contentOffset.x = [UIScreen mainScreen].bounds.size.width; self.galleryScrollView.contentOffset = contentOffset; GalleryScrollView *scrollView = [[GalleryScrollView alloc] initWithFrame:(CGRect){contentOffset, self.galleryScrollView.bounds.size}]; [scrollView setContentWithFrame:convertRect initRect:convertRect]; [scrollView setImage:image]; [self.galleryScrollView addSubview:scrollView]; [self setGalleryScrollViewCallBack:scrollView]; [self performSelector:@selector(setOriginalFrame:) withObject:scrollView afterDelay:0.1]; } @end