From 7b02207537d35bfa1714bf8beafc921f717d100a Mon Sep 17 00:00:00 2001 From: 单军华 Date: Wed, 11 Jul 2018 10:47:42 +0800 Subject: [PATCH] 首次上传 --- screendisplay/Pods/EaseUI/EaseUI/EMUIKit/ViewController/EaseMessageViewController.m | 2171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 2,171 insertions(+), 0 deletions(-) diff --git a/screendisplay/Pods/EaseUI/EaseUI/EMUIKit/ViewController/EaseMessageViewController.m b/screendisplay/Pods/EaseUI/EaseUI/EMUIKit/ViewController/EaseMessageViewController.m new file mode 100755 index 0000000..9385c3e --- /dev/null +++ b/screendisplay/Pods/EaseUI/EaseUI/EMUIKit/ViewController/EaseMessageViewController.m @@ -0,0 +1,2171 @@ +/************************************************************ + * * Hyphenate CONFIDENTIAL + * __________________ + * Copyright (C) 2016 Hyphenate Inc. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of Hyphenate Inc. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from Hyphenate Inc. + */ + +#import "EaseMessageViewController.h" + +#import <Foundation/Foundation.h> +#import <Photos/Photos.h> +#import <AssetsLibrary/AssetsLibrary.h> + +#import "NSDate+Category.h" +#import "EaseUsersListViewController.h" +#import "EaseMessageReadManager.h" +#import "EaseEmotionManager.h" +#import "EaseEmoji.h" +#import "EaseEmotionEscape.h" +#import "EaseCustomMessageCell.h" +#import "UIImage+GIF.h" +#import "EaseLocalDefine.h" +#import "EaseSDKHelper.h" + +#define KHintAdjustY 50 + +#define IOS_VERSION [[UIDevice currentDevice] systemVersion]>=9.0 + +typedef enum : NSUInteger { + EMRequestRecord, + EMCanRecord, + EMCanNotRecord, +} EMRecordResponse; + + +@implementation EaseAtTarget +- (instancetype)initWithUserId:(NSString*)userId andNickname:(NSString*)nickname +{ + if (self = [super init]) { + _userId = [userId copy]; + _nickname = [nickname copy]; + } + return self; +} +@end + +@interface EaseMessageViewController ()<EaseMessageCellDelegate> +{ + UIMenuItem *_copyMenuItem; + UIMenuItem *_deleteMenuItem; + UILongPressGestureRecognizer *_lpgr; + NSMutableArray *_atTargets; + + dispatch_queue_t _messageQueue; + BOOL _isRecording; +} + +@property (strong, nonatomic) id<IMessageModel> playingVoiceModel; +@property (nonatomic) BOOL isKicked; +@property (nonatomic) BOOL isPlayingAudio; +@property (nonatomic, strong) NSMutableArray *atTargets; + +@end + +@implementation EaseMessageViewController + +@synthesize conversation = _conversation; +@synthesize deleteConversationIfNull = _deleteConversationIfNull; +@synthesize messageCountOfPage = _messageCountOfPage; +@synthesize timeCellHeight = _timeCellHeight; +@synthesize messageTimeIntervalTag = _messageTimeIntervalTag; + +- (instancetype)initWithConversationChatter:(NSString *)conversationChatter + conversationType:(EMConversationType)conversationType +{ + if ([conversationChatter length] == 0) { + return nil; + } + + self = [super initWithStyle:UITableViewStylePlain]; + if (self) { + _conversation = [[EMClient sharedClient].chatManager getConversation:conversationChatter type:conversationType createIfNotExist:YES]; + + _messageCountOfPage = 10; + _timeCellHeight = 30; + _deleteConversationIfNull = YES; + _scrollToBottomWhenAppear = YES; + _messsagesSource = [NSMutableArray array]; + + [_conversation markAllMessagesAsRead:nil]; + } + + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.view.backgroundColor = [UIColor colorWithRed:248 / 255.0 green:248 / 255.0 blue:248 / 255.0 alpha:1.0]; + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hideImagePicker) name:@"hideImagePicker" object:nil]; + + //Initialization + CGFloat chatbarHeight = [EaseChatToolbar defaultHeight]; + EMChatToolbarType barType = self.conversation.type == EMConversationTypeChat ? EMChatToolbarTypeChat : EMChatToolbarTypeGroup; + self.chatToolbar = [[EaseChatToolbar alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - chatbarHeight - iPhoneX_BOTTOM_HEIGHT, self.view.frame.size.width, chatbarHeight) type:barType]; + self.chatToolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; + + //Initializa the gesture recognizer + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(keyBoardHidden:)]; + [self.view addGestureRecognizer:tap]; + + _lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; + _lpgr.minimumPressDuration = 0.5; + [self.tableView addGestureRecognizer:_lpgr]; + + _messageQueue = dispatch_queue_create("hyphenate.com", NULL); + + //Register the delegate + [EMCDDeviceManager sharedInstance].delegate = self; + [[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil]; + [[EMClient sharedClient].roomManager addDelegate:self delegateQueue:nil]; + + if (self.conversation.type == EMConversationTypeChatRoom) + { + [self joinChatroom:self.conversation.conversationId]; + } + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didBecomeActive) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + + [[EaseBaseMessageCell appearance] setSendBubbleBackgroundImage:[[UIImage easeImageNamed:@"EaseUIResource.bundle/chat_sender_bg"] stretchableImageWithLeftCapWidth:5 topCapHeight:35]]; + [[EaseBaseMessageCell appearance] setRecvBubbleBackgroundImage:[[UIImage easeImageNamed:@"EaseUIResource.bundle/chat_receiver_bg"] stretchableImageWithLeftCapWidth:35 topCapHeight:35]]; + + [[EaseBaseMessageCell appearance] setSendMessageVoiceAnimationImages:@[[UIImage easeImageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_full"], [UIImage easeImageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_000"], [UIImage easeImageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_001"], [UIImage easeImageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_002"], [UIImage easeImageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_003"]]]; + [[EaseBaseMessageCell appearance] setRecvMessageVoiceAnimationImages:@[[UIImage easeImageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing_full"],[UIImage easeImageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing000"], [UIImage easeImageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing001"], [UIImage easeImageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing002"], [UIImage easeImageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing003"]]]; + + [[EaseBaseMessageCell appearance] setAvatarSize:40.f]; + [[EaseBaseMessageCell appearance] setAvatarCornerRadius:20.f]; + + [[EaseChatBarMoreView appearance] setMoreViewBackgroundColor:[UIColor colorWithRed:240 / 255.0 green:242 / 255.0 blue:247 / 255.0 alpha:1.0]]; + + [self tableViewDidTriggerHeaderRefresh]; + [self setupEmotion]; + + self.tableView.estimatedRowHeight = 0; + self.tableView.estimatedSectionHeaderHeight = 0; + self.tableView.estimatedSectionFooterHeight = 0; +} + +/*! + @method + @brief ������������ + @discussion ������������������������������������������dataSource��������������������������������������������������������� + @result + */ +- (void)setupEmotion +{ + if ([self.dataSource respondsToSelector:@selector(emotionFormessageViewController:)]) { + NSArray* emotionManagers = [self.dataSource emotionFormessageViewController:self]; + [self.faceView setEmotionManagers:emotionManagers]; + } else { + NSMutableArray *emotions = [NSMutableArray array]; + for (NSString *name in [EaseEmoji allEmoji]) { + EaseEmotion *emotion = [[EaseEmotion alloc] initWithName:@"" emotionId:name emotionThumbnail:name emotionOriginal:name emotionOriginalURL:@"" emotionType:EMEmotionDefault]; + [emotions addObject:emotion]; + } + EaseEmotion *emotion = [emotions objectAtIndex:0]; + EaseEmotionManager *manager= [[EaseEmotionManager alloc] initWithType:EMEmotionDefault emotionRow:3 emotionCol:7 emotions:emotions tagImage:[UIImage imageNamed:emotion.emotionId]]; + [self.faceView setEmotionManagers:@[manager]]; + } +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [[EMCDDeviceManager sharedInstance] stopPlaying]; + [EMCDDeviceManager sharedInstance].delegate = nil; + + if (_imagePicker){ + [_imagePicker dismissViewControllerAnimated:NO completion:nil]; + _imagePicker = nil; + } +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + self.isViewDidAppear = YES; + [[EaseSDKHelper shareHelper] setIsShowingimagePicker:NO]; + + if (self.scrollToBottomWhenAppear) { + [self _scrollViewToBottom:NO]; + } + self.scrollToBottomWhenAppear = YES; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + + self.isViewDidAppear = NO; + [[EMCDDeviceManager sharedInstance] disableProximitySensor]; +} + +#pragma mark - chatroom + +- (void)saveChatroom:(EMChatroom *)chatroom +{ + NSString *chatroomName = chatroom.subject ? chatroom.subject : @""; + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + NSString *key = [NSString stringWithFormat:@"OnceJoinedChatrooms_%@", [[EMClient sharedClient] currentUsername]]; + NSMutableDictionary *chatRooms = [NSMutableDictionary dictionaryWithDictionary:[ud objectForKey:key]]; + if (![chatRooms objectForKey:chatroom.chatroomId]) + { + [chatRooms setObject:chatroomName forKey:chatroom.chatroomId]; + [ud setObject:chatRooms forKey:key]; + [ud synchronize]; + } +} + +/*! + @method + @brief ��������������� + @discussion + @result + */ +- (void)joinChatroom:(NSString *)chatroomId +{ + __weak typeof(self) weakSelf = self; + [self showHudInView:self.view hint:NSEaseLocalizedString(@"chatroom.joining",@"Joining the chatroom")]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + EMError *error = nil; + EMChatroom *chatroom = [[EMClient sharedClient].roomManager joinChatroom:chatroomId error:&error]; + dispatch_async(dispatch_get_main_queue(), ^{ + if (weakSelf) { + EaseMessageViewController *strongSelf = weakSelf; + [strongSelf hideHud]; + if (error != nil) { + [strongSelf showHint:[NSString stringWithFormat:NSEaseLocalizedString(@"chatroom.joinFailed",@"join chatroom \'%@\' failed"), chatroomId]]; + } else { + strongSelf.isJoinedChatroom = YES; + [strongSelf saveChatroom:chatroom]; + } + } else { + if (!error || (error.code == EMErrorChatroomAlreadyJoined)) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + EMError *leaveError; + [[EMClient sharedClient].roomManager leaveChatroom:chatroomId error:&leaveError]; + [[EMClient sharedClient].chatManager deleteConversation:chatroomId isDeleteMessages:YES completion:nil]; + }); + } + } + }); + }); +} + +#pragma mark - EMChatManagerChatroomDelegate + +- (void)didReceiveUserJoinedChatroom:(EMChatroom *)aChatroom + username:(NSString *)aUsername +{ + CGRect frame = self.chatToolbar.frame; + [self showHint:[NSString stringWithFormat:NSEaseLocalizedString(@"chatroom.join", @"\'%@\'join chatroom\'%@\'"), aUsername, aChatroom.chatroomId] yOffset:-frame.size.height + KHintAdjustY]; +} + +- (void)didReceiveUserLeavedChatroom:(EMChatroom *)aChatroom + username:(NSString *)aUsername +{ + CGRect frame = self.chatToolbar.frame; + [self showHint:[NSString stringWithFormat:NSEaseLocalizedString(@"chatroom.leave.hint", @"\'%@\'leave chatroom\'%@\'"), aUsername, aChatroom.chatroomId] yOffset:-frame.size.height + KHintAdjustY]; +} + +- (void)didReceiveKickedFromChatroom:(EMChatroom *)aChatroom + reason:(EMChatroomBeKickedReason)aReason +{ + if ([_conversation.conversationId isEqualToString:aChatroom.chatroomId]) + { + _isKicked = YES; + CGRect frame = self.chatToolbar.frame; + [self showHint:[NSString stringWithFormat:NSEaseLocalizedString(@"chatroom.remove", @"be removed from chatroom\'%@\'"), aChatroom.chatroomId] yOffset:-frame.size.height + KHintAdjustY]; + [self.navigationController popToViewController:self animated:NO]; + [self.navigationController popViewControllerAnimated:YES]; + } +} + +#pragma mark - getter + +- (UIImagePickerController *)imagePicker +{ + if (_imagePicker == nil) { + _imagePicker = [[UIImagePickerController alloc] init]; + _imagePicker.modalPresentationStyle= UIModalPresentationOverFullScreen; + _imagePicker.delegate = self; + } + + return _imagePicker; +} + +- (NSMutableArray*)atTargets +{ + if (!_atTargets) { + _atTargets = [NSMutableArray array]; + } + return _atTargets; +} + +#pragma mark - setter + +- (void)setIsViewDidAppear:(BOOL)isViewDidAppear +{ + _isViewDidAppear =isViewDidAppear; + if (_isViewDidAppear) + { + NSMutableArray *unreadMessages = [NSMutableArray array]; + for (EMMessage *message in self.messsagesSource) + { + if ([self shouldSendHasReadAckForMessage:message read:NO]) + { + [unreadMessages addObject:message]; + } + } + if ([unreadMessages count]) + { + [self _sendHasReadResponseForMessages:unreadMessages isRead:YES]; + } + + [_conversation markAllMessagesAsRead:nil]; + } +} + +- (void)setChatToolbar:(EaseChatToolbar *)chatToolbar +{ + [_chatToolbar removeFromSuperview]; + + _chatToolbar = chatToolbar; + if (_chatToolbar) { + [self.view addSubview:_chatToolbar]; + } + + CGRect tableFrame = self.tableView.frame; + tableFrame.size.height = self.view.frame.size.height - _chatToolbar.frame.size.height - iPhoneX_BOTTOM_HEIGHT; + self.tableView.frame = tableFrame; + if ([chatToolbar isKindOfClass:[EaseChatToolbar class]]) { + [(EaseChatToolbar *)self.chatToolbar setDelegate:self]; + self.chatBarMoreView = (EaseChatBarMoreView*)[(EaseChatToolbar *)self.chatToolbar moreView]; + self.faceView = (EaseFaceView*)[(EaseChatToolbar *)self.chatToolbar faceView]; + self.recordView = (EaseRecordView*)[(EaseChatToolbar *)self.chatToolbar recordView]; + } +} + +- (void)setDataSource:(id<EaseMessageViewControllerDataSource>)dataSource +{ + _dataSource = dataSource; + + [self setupEmotion]; +} + +- (void)setDelegate:(id<EaseMessageViewControllerDelegate>)delegate +{ + _delegate = delegate; +} + +#pragma mark - private helper + +/*! + @method + @brief tableView��������������� + @discussion + @result + */ +- (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:animated]; + } +} + +/*! + @method + @brief ������������������������������ + @discussion + @param aCompletion ������������ + @result + */ +- (void)_canRecordCompletion:(void(^)(EMRecordResponse))aCompletion +{ + AVAuthorizationStatus videoAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]; + if (videoAuthStatus == AVAuthorizationStatusNotDetermined) { + [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { + if (aCompletion) { + aCompletion(granted ? EMCanRecord : EMRequestRecord); + } + }]; + } + else if(videoAuthStatus == AVAuthorizationStatusRestricted || videoAuthStatus == AVAuthorizationStatusDenied) { + aCompletion(EMCanNotRecord); + } + else{ + aCompletion(EMCanRecord); + } +} + +- (void)showMenuViewController:(UIView *)showInView + andIndexPath:(NSIndexPath *)indexPath + messageType:(EMMessageBodyType)messageType +{ + if (_menuController == nil) { + _menuController = [UIMenuController sharedMenuController]; + } + + if (_deleteMenuItem == nil) { + _deleteMenuItem = [[UIMenuItem alloc] initWithTitle:NSEaseLocalizedString(@"delete", @"Delete") action:@selector(deleteMenuAction:)]; + } + + if (_copyMenuItem == nil) { + _copyMenuItem = [[UIMenuItem alloc] initWithTitle:NSEaseLocalizedString(@"copy", @"Copy") action:@selector(copyMenuAction:)]; + } + + if (messageType == EMMessageBodyTypeText) { + [_menuController setMenuItems:@[_copyMenuItem, _deleteMenuItem]]; + } else { + [_menuController setMenuItems:@[_deleteMenuItem]]; + } + [_menuController setTargetRect:showInView.frame inView:showInView.superview]; + [_menuController setMenuVisible:YES animated:YES]; +} + +- (void)_stopAudioPlayingWithChangeCategory:(BOOL)isChange +{ + //��������������������������������� + [[EMCDDeviceManager sharedInstance] stopPlaying]; + [[EMCDDeviceManager sharedInstance] disableProximitySensor]; + [EMCDDeviceManager sharedInstance].delegate = nil; + + // MessageModel *playingModel = [self.EaseMessageReadManager 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]; + // }); + // } +} + +/*! + @method + @brief mov���������������������MP4������ + @discussion + @param movUrl mov������������ + @result MP4������������������ + */ +- (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; +} + +/*! + @method + @brief ��������������������������������������������������� + @discussion + @result + */ +- (EMChatType)_messageTypeFromConversationType +{ + EMChatType type = EMChatTypeChat; + switch (self.conversation.type) { + case EMConversationTypeChat: + type = EMChatTypeChat; + break; + case EMConversationTypeGroupChat: + type = EMChatTypeGroupChat; + break; + case EMConversationTypeChatRoom: + type = EMChatTypeChatRoom; + break; + default: + break; + } + return type; +} + +- (void)_customDownloadMessageFile:(EMMessage *)aMessage +{ + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedString(@"message.autoTransfer", @"Please customize the transfer attachment method") delegate:nil cancelButtonTitle:NSLocalizedString(@"sure", @"OK") otherButtonTitles:nil, nil]; + [alertView show]; + }); +} + +/*! + @method + @brief ������������������ + @discussion + @param message ������������������������ + @result + */ +- (void)_downloadMessageAttachments:(EMMessage *)message +{ + __weak typeof(self) weakSelf = self; + void (^completion)(EMMessage *aMessage, EMError *error) = ^(EMMessage *aMessage, EMError *error) { + if (!error) + { + [weakSelf _reloadTableViewDataWithMessage:message]; + } + else + { + [weakSelf showHint:NSEaseLocalizedString(@"message.thumImageFail", @"thumbnail for failure!")]; + } + }; + + BOOL isCustomDownload = !([EMClient sharedClient].options.isAutoTransferMessageAttachments); + BOOL isAutoDownloadThumbnail = ([EMClient sharedClient].options.isAutoDownloadThumbnail); + EMMessageBody *messageBody = message.body; + if ([messageBody type] == EMMessageBodyTypeImage) { + EMImageMessageBody *imageBody = (EMImageMessageBody *)messageBody; + if (imageBody.thumbnailDownloadStatus > EMDownloadStatusSuccessed) + { + //download the message thumbnail + if (isCustomDownload) { + [self _customDownloadMessageFile:message]; + } else { + if (isAutoDownloadThumbnail) { + [[[EMClient sharedClient] chatManager] downloadMessageThumbnail:message progress:nil completion:completion]; + } + } + } + } + else if ([messageBody type] == EMMessageBodyTypeVideo) + { + EMVideoMessageBody *videoBody = (EMVideoMessageBody *)messageBody; + if (videoBody.thumbnailDownloadStatus > EMDownloadStatusSuccessed) + { + //download the message thumbnail + if (isCustomDownload) { + [self _customDownloadMessageFile:message]; + } else { + if (isAutoDownloadThumbnail) { + [[[EMClient sharedClient] chatManager] downloadMessageThumbnail:message progress:nil completion:completion]; + } + } + } + } + else if ([messageBody type] == EMMessageBodyTypeVoice) + { + EMVoiceMessageBody *voiceBody = (EMVoiceMessageBody*)messageBody; + if (voiceBody.downloadStatus > EMDownloadStatusSuccessed) + { + //download the message attachment + if (isCustomDownload) { + [self _customDownloadMessageFile:message]; + } else { + if (isAutoDownloadThumbnail) { + [[EMClient sharedClient].chatManager downloadMessageAttachment:message progress:nil completion:^(EMMessage *message, EMError *error) { + if (!error) { + [weakSelf _reloadTableViewDataWithMessage:message]; + } + else { + [weakSelf showHint:NSEaseLocalizedString(@"message.voiceFail", @"voice for failure!")]; + } + }]; + } + } + } + } +} + +/*! + @method + @brief ������������������������������������������ + @discussion + @param message ������������������ + @param read ������������������ + @result + */ +- (BOOL)shouldSendHasReadAckForMessage:(EMMessage *)message + read:(BOOL)read +{ + if (message.chatType != EMChatTypeChat || message.isReadAcked || message.direction == EMMessageDirectionSend || ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) || !self.isViewDidAppear) + { + return NO; + } + + EMMessageBody *body = message.body; + if (((body.type == EMMessageBodyTypeVideo) || + (body.type == EMMessageBodyTypeVoice) || + (body.type == EMMessageBodyTypeImage)) && + !read) + { + return NO; + } + else + { + return YES; + } +} + +/*! + @method + @brief ������������������������������������ + @discussion + @param messages ������������������������������������ + @param isRead ������������ + @result + */ +- (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 = YES; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:shouldSendHasReadAckForMessage:read:)]) { + isSend = [_dataSource messageViewController:self + shouldSendHasReadAckForMessage:message read:isRead]; + } + else{ + 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)_shouldMarkMessageAsRead +{ + BOOL isMark = YES; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewControllerShouldMarkMessagesAsRead:)]) { + isMark = [_dataSource messageViewControllerShouldMarkMessagesAsRead:self]; + } + else{ + if (([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) || !self.isViewDidAppear) + { + isMark = NO; + } + } + + return isMark; +} + +/*! + @method + @brief ��������������������������� + @discussion + @param model ������model + @result + */ +- (void)_locationMessageCellSelected:(id<IMessageModel>)model +{ + _scrollToBottomWhenAppear = NO; + + EaseLocationViewController *locationController = [[EaseLocationViewController alloc] initWithLocation:CLLocationCoordinate2DMake(model.latitude, model.longitude)]; + [self.navigationController pushViewController:locationController animated:YES]; +} + +/*! + @method + @brief ��������������������������� + @discussion + @param model ������model + @result + */ +- (void)_videoMessageCellSelected:(id<IMessageModel>)model +{ + _scrollToBottomWhenAppear = NO; + + EMVideoMessageBody *videoBody = (EMVideoMessageBody*)model.message.body; + + NSString *localPath = [model.fileLocalPath length] > 0 ? model.fileLocalPath : videoBody.localPath; + if ([localPath length] == 0) { + [self showHint:NSEaseLocalizedString(@"message.videoFail", @"video for failure!")]; + return; + } + + dispatch_block_t block = ^{ + //send the acknowledgement + [self _sendHasReadResponseForMessages:@[model.message] + isRead:YES]; + + NSURL *videoURL = [NSURL fileURLWithPath:localPath]; + MPMoviePlayerViewController *moviePlayerController = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL]; + [moviePlayerController.moviePlayer prepareToPlay]; + moviePlayerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile; + [self presentMoviePlayerViewControllerAnimated:moviePlayerController]; + }; + + BOOL isCustomDownload = !([EMClient sharedClient].options.isAutoTransferMessageAttachments); + __weak typeof(self) weakSelf = self; + void (^completion)(EMMessage *aMessage, EMError *error) = ^(EMMessage *aMessage, EMError *error) { + if (!error) + { + [weakSelf _reloadTableViewDataWithMessage:aMessage]; + } + else + { + [weakSelf showHint:NSEaseLocalizedString(@"message.thumImageFail", @"thumbnail for failure!")]; + } + }; + + if (videoBody.thumbnailDownloadStatus == EMDownloadStatusFailed || ![[NSFileManager defaultManager] fileExistsAtPath:videoBody.thumbnailLocalPath]) { + [self showHint:@"begin downloading thumbnail image, click later"]; + if (isCustomDownload) { + [self _customDownloadMessageFile:model.message]; + } else { + [[EMClient sharedClient].chatManager downloadMessageThumbnail:model.message progress:nil completion:completion]; + } + return; + } + + if (videoBody.downloadStatus == EMDownloadStatusSuccessed && [[NSFileManager defaultManager] fileExistsAtPath:localPath]) + { + block(); + return; + } + + [self showHudInView:self.view hint:NSEaseLocalizedString(@"message.downloadingVideo", @"downloading video...")]; + if (isCustomDownload) { + [self _customDownloadMessageFile:model.message]; + } else { + [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:^(EMMessage *message, EMError *error) { + [weakSelf hideHud]; + if (!error) { + block(); + }else{ + [weakSelf showHint:NSEaseLocalizedString(@"message.videoFail", @"video for failure!")]; + } + }]; + } +} + +/*! + @method + @brief ��������������������������� + @discussion + @param model ������model + @result + */ +- (void)_imageMessageCellSelected:(id<IMessageModel>)model +{ + __weak EaseMessageViewController *weakSelf = self; + EMImageMessageBody *imageBody = (EMImageMessageBody*)[model.message body]; + + BOOL isCustomDownload = !([EMClient sharedClient].options.isAutoTransferMessageAttachments); + if ([imageBody type] == EMMessageBodyTypeImage) { + if (imageBody.thumbnailDownloadStatus == EMDownloadStatusSuccessed) { + if (imageBody.downloadStatus == EMDownloadStatusSuccessed) + { + //send the acknowledgement + [weakSelf _sendHasReadResponseForMessages:@[model.message] isRead:YES]; + NSString *localPath = model.message == nil ? model.fileLocalPath : [imageBody localPath]; + if (localPath && localPath.length > 0) { + UIImage *image = [UIImage imageWithContentsOfFile:localPath]; + if (image) { + [[EaseMessageReadManager defaultManager] showBrowserWithImages:@[image]]; + return; + } + } + } + + [weakSelf showHudInView:weakSelf.view hint:NSEaseLocalizedString(@"message.downloadingImage", @"downloading a image...")]; + + void (^completion)(EMMessage *aMessage, EMError *error) = ^(EMMessage *aMessage, EMError *error) { + [weakSelf hideHud]; + if (!error) { + //send the acknowledgement + [weakSelf _sendHasReadResponseForMessages:@[model.message] isRead:YES]; + NSString *localPath = aMessage == nil ? model.fileLocalPath : [(EMImageMessageBody*)aMessage.body localPath]; + if (localPath && localPath.length > 0) { + UIImage *image = [UIImage imageWithContentsOfFile:localPath]; +// weakSelf.isScrollToBottom = NO; + if (image) + { + [[EaseMessageReadManager defaultManager] showBrowserWithImages:@[image]]; + } + else + { + NSLog(@"Read %@ failed!", localPath); + } + return ; + } + } + [weakSelf showHint:NSEaseLocalizedString(@"message.imageFail", @"image for failure!")]; + }; + + if (isCustomDownload) { + [self _customDownloadMessageFile:model.message]; + } else { + [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:completion]; + } + }else{ + //get the message thumbnail + if (isCustomDownload) { + [self _customDownloadMessageFile:model.message]; + } else { + [[EMClient sharedClient].chatManager downloadMessageThumbnail:model.message progress:nil completion:^(EMMessage *message, EMError *error) { + if (!error) { + [weakSelf _reloadTableViewDataWithMessage:model.message]; + }else{ + [weakSelf showHint:NSEaseLocalizedString(@"message.thumImageFail", @"thumbnail for failure!")]; + } + }]; + } + } + } +} + +/*! + @method + @brief ��������������������������� + @discussion + @param model ������model + @result + */ +- (void)_audioMessageCellSelected:(id<IMessageModel>)model +{ + _scrollToBottomWhenAppear = NO; + EMVoiceMessageBody *body = (EMVoiceMessageBody*)model.message.body; + EMDownloadStatus downloadStatus = [body downloadStatus]; + if (downloadStatus == EMDownloadStatusDownloading) { + [self showHint:NSEaseLocalizedString(@"message.downloadingAudio", @"downloading voice, click later")]; + return; + } + else if (downloadStatus == EMDownloadStatusFailed || downloadStatus == EMDownloadStatusPending) + { + [self showHint:NSEaseLocalizedString(@"message.downloadingAudio", @"downloading voice, click later")]; + BOOL isCustomDownload = !([EMClient sharedClient].options.isAutoTransferMessageAttachments); + if (isCustomDownload) { + [self _customDownloadMessageFile:model.message]; + } else { + [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:nil]; + } + + return; + } + + // play the audio + if (model.bodyType == EMMessageBodyTypeVoice) { + //send the acknowledgement + [self _sendHasReadResponseForMessages:@[model.message] isRead:YES]; + __weak EaseMessageViewController *weakSelf = self; + BOOL isPrepare = [[EaseMessageReadManager defaultManager] prepareMessageAudioModel:model updateViewCompletion:^(EaseMessageModel *prevAudioModel, EaseMessageModel *currentAudioModel) { + if (prevAudioModel || currentAudioModel) { + [weakSelf.tableView reloadData]; + } + }]; + + if (isPrepare) { + _isPlayingAudio = YES; + __weak EaseMessageViewController *weakSelf = self; + [[EMCDDeviceManager sharedInstance] enableProximitySensor]; + [[EMCDDeviceManager sharedInstance] asyncPlayingWithPath:model.fileLocalPath completion:^(NSError *error) { + [[EaseMessageReadManager defaultManager] stopMessageAudioModel]; + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.tableView reloadData]; + weakSelf.isPlayingAudio = NO; + [[EMCDDeviceManager sharedInstance] disableProximitySensor]; + }); + }]; + } + else{ + _isPlayingAudio = NO; + } + } +} + +#pragma mark - pivate data + +/*! + @method + @brief ������������������ + @discussion + @param messageId ���������������ID + @param count ������������ + @param isAppend ���������dataArray������������ + @result + */ +- (void)_loadMessagesBefore:(NSString*)messageId + count:(NSInteger)count + append:(BOOL)isAppend +{ + __weak typeof(self) weakSelf = self; + void (^refresh)(NSArray *messages) = ^(NSArray *messages) { + dispatch_async(_messageQueue, ^{ + //Format the message + NSArray *formattedMessages = [weakSelf formatMessages:messages]; + + //Refresh the page + dispatch_async(dispatch_get_main_queue(), ^{ + EaseMessageViewController *strongSelf = weakSelf; + if (strongSelf) { + NSInteger scrollToIndex = 0; + if (isAppend) { + [strongSelf.messsagesSource insertObjects:messages atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [messages count])]]; + + //Combine the message + id object = [strongSelf.dataArray firstObject]; + if ([object isKindOfClass:[NSString class]]) { + NSString *timestamp = object; + [formattedMessages enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id model, NSUInteger idx, BOOL *stop) { + if ([model isKindOfClass:[NSString class]] && [timestamp isEqualToString:model]) { + [strongSelf.dataArray removeObjectAtIndex:0]; + *stop = YES; + } + }]; + } + scrollToIndex = [strongSelf.dataArray count]; + [strongSelf.dataArray insertObjects:formattedMessages atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [formattedMessages count])]]; + } + else { + [strongSelf.messsagesSource removeAllObjects]; + [strongSelf.messsagesSource addObjectsFromArray:messages]; + + [strongSelf.dataArray removeAllObjects]; + [strongSelf.dataArray addObjectsFromArray:formattedMessages]; + } + + EMMessage *latest = [strongSelf.messsagesSource lastObject]; + strongSelf.messageTimeIntervalTag = latest.timestamp; + + [strongSelf.tableView reloadData]; + + [strongSelf.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[self.dataArray count] - scrollToIndex - 1 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; + } + }); + + //re-download all messages that are not successfully downloaded + for (EMMessage *message in messages) + { + [weakSelf _downloadMessageAttachments:message]; + } + + //send the read acknoledgement + [weakSelf _sendHasReadResponseForMessages:messages + isRead:NO]; + }); + }; + + [self.conversation loadMessagesStartFromId:messageId count:(int)count searchDirection:EMMessageSearchDirectionUp completion:^(NSArray *aMessages, EMError *aError) { + if (!aError && [aMessages count]) { + refresh(aMessages); + } + }]; +} + +#pragma mark - GestureRecognizer + +-(void)keyBoardHidden:(UITapGestureRecognizer *)tapRecognizer +{ + if (tapRecognizer.state == UIGestureRecognizerStateEnded) { + [self.chatToolbar endEditing:YES]; + } +} + +- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer +{ + if (recognizer.state == UIGestureRecognizerStateBegan && [self.dataArray count] > 0) + { + CGPoint location = [recognizer locationInView:self.tableView]; + NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:location]; + BOOL canLongPress = NO; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:canLongPressRowAtIndexPath:)]) { + canLongPress = [_dataSource messageViewController:self + canLongPressRowAtIndexPath:indexPath]; + } + + if (!canLongPress) { + return; + } + + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:didLongPressRowAtIndexPath:)]) { + [_dataSource messageViewController:self + didLongPressRowAtIndexPath:indexPath]; + } + else{ + id object = [self.dataArray objectAtIndex:indexPath.row]; + if (![object isKindOfClass:[NSString class]]) { + EaseMessageCell *cell = (EaseMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + [cell becomeFirstResponder]; + _menuIndexPath = indexPath; + [self showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.model.bodyType]; + } + } + } +} + +#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 the number of rows in the section. + return [self.dataArray count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + id object = [self.dataArray objectAtIndex:indexPath.row]; + + //time cell + if ([object isKindOfClass:[NSString class]]) { + NSString *TimeCellIdentifier = [EaseMessageTimeCell cellIdentifier]; + EaseMessageTimeCell *timeCell = (EaseMessageTimeCell *)[tableView dequeueReusableCellWithIdentifier:TimeCellIdentifier]; + + if (timeCell == nil) { + timeCell = [[EaseMessageTimeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TimeCellIdentifier]; + timeCell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + timeCell.title = object; + return timeCell; + } + else{ + id<IMessageModel> model = object; + if (_delegate && [_delegate respondsToSelector:@selector(messageViewController:cellForMessageModel:)]) { + UITableViewCell *cell = [_delegate messageViewController:tableView cellForMessageModel:model]; + if (cell) { + if ([cell isKindOfClass:[EaseMessageCell class]]) { + EaseMessageCell *emcell= (EaseMessageCell*)cell; + if (emcell.delegate == nil) { + emcell.delegate = self; + } + } + return cell; + } + } + + if (_dataSource && [_dataSource respondsToSelector:@selector(isEmotionMessageFormessageViewController:messageModel:)]) { + BOOL flag = [_dataSource isEmotionMessageFormessageViewController:self messageModel:model]; + if (flag) { + NSString *CellIdentifier = [EaseCustomMessageCell cellIdentifierWithModel:model]; + //send cell + EaseCustomMessageCell *sendCell = (EaseCustomMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + + // Configure the cell... + if (sendCell == nil) { + sendCell = [[EaseCustomMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model]; + sendCell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + if (_dataSource && [_dataSource respondsToSelector:@selector(emotionURLFormessageViewController:messageModel:)]) { + EaseEmotion *emotion = [_dataSource emotionURLFormessageViewController:self messageModel:model]; + if (emotion) { + model.image = [UIImage sd_animatedGIFNamed:emotion.emotionOriginal]; + model.fileURLPath = emotion.emotionOriginalURL; + } + } + sendCell.model = model; + sendCell.delegate = self; + return sendCell; + } + } + + NSString *CellIdentifier = [EaseMessageCell cellIdentifierWithModel:model]; + + EaseBaseMessageCell *sendCell = (EaseBaseMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + + // Configure the cell... + if (sendCell == nil) { + sendCell = [[EaseBaseMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model]; + sendCell.selectionStyle = UITableViewCellSelectionStyleNone; + sendCell.delegate = self; + } + + sendCell.model = model; + return sendCell; + } +} + +#pragma mark - Table view delegate + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + id object = [self.dataArray objectAtIndex:indexPath.row]; + if ([object isKindOfClass:[NSString class]]) { + return self.timeCellHeight; + } + else{ + id<IMessageModel> model = object; + if (_delegate && [_delegate respondsToSelector:@selector(messageViewController:heightForMessageModel:withCellWidth:)]) { + CGFloat height = [_delegate messageViewController:self heightForMessageModel:model withCellWidth:tableView.frame.size.width]; + if (height) { + return height; + } + } + + if (_dataSource && [_dataSource respondsToSelector:@selector(isEmotionMessageFormessageViewController:messageModel:)]) { + BOOL flag = [_dataSource isEmotionMessageFormessageViewController:self messageModel:model]; + if (flag) { + return [EaseCustomMessageCell cellHeightWithModel:model]; + } + } + + return [EaseBaseMessageCell cellHeightWithModel:model]; + } +} + +#pragma mark - UIImagePickerControllerDelegate + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + NSString *mediaType = info[UIImagePickerControllerMediaType]; + if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) { + NSURL *videoURL = info[UIImagePickerControllerMediaURL]; + // 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); + } + } + [self sendVideoMessageWithURL:mp4]; + + }else{ + + NSURL *url = info[UIImagePickerControllerReferenceURL]; + if (url == nil) { + UIImage *orgImage = info[UIImagePickerControllerOriginalImage]; + [self sendImageMessage:orgImage]; + } else { + if ([[UIDevice currentDevice].systemVersion doubleValue] >= 9.0f) { + PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil]; + [result enumerateObjectsUsingBlock:^(PHAsset *asset , NSUInteger idx, BOOL *stop){ + if (asset) { + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *data, NSString *uti, UIImageOrientation orientation, NSDictionary *dic){ + if (data != nil) { + [self sendImageMessageWithData:data]; + } else { + [self showHint:NSEaseLocalizedString(@"message.smallerImage", @"The image size is too large, please choose another one")]; + } + }]; + } + }]; + } else { + ALAssetsLibrary *alasset = [[ALAssetsLibrary alloc] init]; + [alasset assetForURL:url resultBlock:^(ALAsset *asset) { + if (asset) { + ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; + Byte* buffer = (Byte*)malloc((size_t)[assetRepresentation size]); + NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:(NSUInteger)[assetRepresentation size] error:nil]; + NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; + [self sendImageMessageWithData:fileData]; + } + } failureBlock:NULL]; + } + } + } + + [picker dismissViewControllerAnimated:YES completion:nil]; + + self.isViewDidAppear = YES; + [[EaseSDKHelper shareHelper] setIsShowingimagePicker:NO]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + [self.imagePicker dismissViewControllerAnimated:YES completion:nil]; + + self.isViewDidAppear = YES; + [[EaseSDKHelper shareHelper] setIsShowingimagePicker:NO]; +} + +#pragma mark - EaseMessageCellDelegate + +- (void)messageCellSelected:(id<IMessageModel>)model +{ + if (_delegate && [_delegate respondsToSelector:@selector(messageViewController:didSelectMessageModel:)]) { + BOOL flag = [_delegate messageViewController:self didSelectMessageModel:model]; + if (flag) { + [self _sendHasReadResponseForMessages:@[model.message] isRead:YES]; + return; + } + } + + switch (model.bodyType) { + case EMMessageBodyTypeImage: + { + _scrollToBottomWhenAppear = NO; + [self _imageMessageCellSelected:model]; + } + break; + case EMMessageBodyTypeLocation: + { + [self _locationMessageCellSelected:model]; + } + break; + case EMMessageBodyTypeVoice: + { + [self _audioMessageCellSelected:model]; + } + break; + case EMMessageBodyTypeVideo: + { + [self _videoMessageCellSelected:model]; + + } + break; + case EMMessageBodyTypeFile: + { + _scrollToBottomWhenAppear = NO; + [self showHint:@"Custom implementation!"]; + } + break; + default: + break; + } +} + +- (void)statusButtonSelcted:(id<IMessageModel>)model withMessageCell:(EaseMessageCell*)messageCell +{ + if ((model.messageStatus != EMMessageStatusFailed) && (model.messageStatus != EMMessageStatusPending)) + { + return; + } + + __weak typeof(self) weakself = self; + [[[EMClient sharedClient] chatManager] resendMessage:model.message progress:nil completion:^(EMMessage *message, EMError *error) { + if (!error) { + [weakself _refreshAfterSentMessage:message]; + } + else { + [weakself.tableView reloadData]; + } + }]; + + [self.tableView reloadData]; +} + +- (void)avatarViewSelcted:(id<IMessageModel>)model +{ + if (_delegate && [_delegate respondsToSelector:@selector(messageViewController:didSelectAvatarMessageModel:)]) { + [_delegate messageViewController:self didSelectAvatarMessageModel:model]; + + return; + } + + _scrollToBottomWhenAppear = NO; +} + +#pragma mark - EMChatToolbarDelegate + +- (void)chatToolbarDidChangeFrameToHeight:(CGFloat)toHeight +{ + [UIView animateWithDuration:0.3 animations:^{ + CGRect rect = self.tableView.frame; + rect.origin.y = 0; + rect.size.height = self.view.frame.size.height - toHeight - iPhoneX_BOTTOM_HEIGHT; + self.tableView.frame = rect; + }]; + + [self _scrollViewToBottom:NO]; +} + +- (void)inputTextViewWillBeginEditing:(EaseTextView *)inputTextView +{ + if (_menuController == nil) { + _menuController = [UIMenuController sharedMenuController]; + } + [_menuController setMenuItems:nil]; +} + +- (void)didSendText:(NSString *)text +{ + if (text && text.length > 0) { + [self sendTextMessage:text]; + [self.atTargets removeAllObjects]; + } +} + +- (BOOL)didInputAtInLocation:(NSUInteger)location +{ + if ([self.delegate respondsToSelector:@selector(messageViewController:selectAtTarget:)] && self.conversation.type == EMConversationTypeGroupChat) { + location += 1; + __weak typeof(self) weakSelf = self; + [self.delegate messageViewController:self selectAtTarget:^(EaseAtTarget *target) { + __strong EaseMessageViewController *strongSelf = weakSelf; + if (strongSelf && target) { + if ([target.userId length] || [target.nickname length]) { + [strongSelf.atTargets addObject:target]; + NSString *insertStr = [NSString stringWithFormat:@"%@ ", target.nickname ? target.nickname : target.userId]; + EaseChatToolbar *toolbar = (EaseChatToolbar*)strongSelf.chatToolbar; + NSMutableString *originStr = [toolbar.inputTextView.text mutableCopy]; + NSUInteger insertLocation = location > originStr.length ? originStr.length : location; + [originStr insertString:insertStr atIndex:insertLocation]; + toolbar.inputTextView.text = originStr; + toolbar.inputTextView.selectedRange = NSMakeRange(insertLocation + insertStr.length, 0); + [toolbar.inputTextView becomeFirstResponder]; + } + } + else if (strongSelf) { + EaseChatToolbar *toolbar = (EaseChatToolbar*)strongSelf.chatToolbar; + [toolbar.inputTextView becomeFirstResponder]; + } + }]; + EaseChatToolbar *toolbar = (EaseChatToolbar*)self.chatToolbar; + toolbar.inputTextView.text = [NSString stringWithFormat:@"%@@", toolbar.inputTextView.text]; + [toolbar.inputTextView resignFirstResponder]; + return YES; + } + else { + return NO; + } +} + +- (BOOL)didDeleteCharacterFromLocation:(NSUInteger)location +{ + EaseChatToolbar *toolbar = (EaseChatToolbar*)self.chatToolbar; + if ([toolbar.inputTextView.text length] == location + 1) { + //delete last character + NSString *inputText = toolbar.inputTextView.text; + NSRange range = [inputText rangeOfString:@"@" options:NSBackwardsSearch]; + if (range.location != NSNotFound) { + if (location - range.location > 1) { + NSString *sub = [inputText substringWithRange:NSMakeRange(range.location + 1, location - range.location - 1)]; + for (EaseAtTarget *target in self.atTargets) { + if ([sub isEqualToString:target.userId] || [sub isEqualToString:target.nickname]) { + inputText = range.location > 0 ? [inputText substringToIndex:range.location] : @""; + toolbar.inputTextView.text = inputText; + toolbar.inputTextView.selectedRange = NSMakeRange(inputText.length, 0); + [self.atTargets removeObject:target]; + return YES; + } + } + } + } + } + return NO; +} + +- (void)didSendText:(NSString *)text withExt:(NSDictionary*)ext +{ + if ([ext objectForKey:EASEUI_EMOTION_DEFAULT_EXT]) { + EaseEmotion *emotion = [ext objectForKey:EASEUI_EMOTION_DEFAULT_EXT]; + if (self.dataSource && [self.dataSource respondsToSelector:@selector(emotionExtFormessageViewController:easeEmotion:)]) { + NSDictionary *ext = [self.dataSource emotionExtFormessageViewController:self easeEmotion:emotion]; + [self sendTextMessage:emotion.emotionTitle withExt:ext]; + } else { + [self sendTextMessage:emotion.emotionTitle withExt:@{MESSAGE_ATTR_EXPRESSION_ID:emotion.emotionId,MESSAGE_ATTR_IS_BIG_EXPRESSION:@(YES)}]; + } + return; + } + if (text && text.length > 0) { + [self sendTextMessage:text withExt:ext]; + } +} + +- (void)didStartRecordingVoiceAction:(UIView *)recordView +{ + if ([self.delegate respondsToSelector:@selector(messageViewController:didSelectRecordView:withEvenType:)]) { + [self.delegate messageViewController:self didSelectRecordView:recordView withEvenType:EaseRecordViewTypeTouchDown]; + } else { + if ([self.recordView isKindOfClass:[EaseRecordView class]]) { + [(EaseRecordView *)self.recordView recordButtonTouchDown]; + } + } + + [self _canRecordCompletion:^(EMRecordResponse recordResponse) { + switch (recordResponse) { + case EMRequestRecord: + + break; + case EMCanRecord: + { + _isRecording = YES; + EaseRecordView *tmpView = (EaseRecordView *)recordView; + tmpView.center = self.view.center; + [self.view addSubview:tmpView]; + [self.view bringSubviewToFront:recordView]; + int x = arc4random() % 100000; + NSTimeInterval time = [[NSDate date] timeIntervalSince1970]; + NSString *fileName = [NSString stringWithFormat:@"%d%d",(int)time,x]; + + [[EMCDDeviceManager sharedInstance] asyncStartRecordingWithFileName:fileName completion:^(NSError *error) + { + if (error) { + NSLog(@"%@",NSEaseLocalizedString(@"message.startRecordFail", @"failure to start recording")); + _isRecording = NO; + } + }]; + + } + break; + case EMCanNotRecord: + { + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"prompt", @"Prompt") message:NSLocalizedString(@"record.failToPermission", @"No recording permission") delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; + [alertView show]; + } + break; + default: + break; + } + }]; +} + + +- (void)didCancelRecordingVoiceAction:(UIView *)recordView +{ + if(_isRecording) { + [[EMCDDeviceManager sharedInstance] cancelCurrentRecording]; + if ([self.delegate respondsToSelector:@selector(messageViewController:didSelectRecordView:withEvenType:)]) { + [self.delegate messageViewController:self didSelectRecordView:recordView withEvenType:EaseRecordViewTypeTouchUpOutside]; + } else { + if ([self.recordView isKindOfClass:[EaseRecordView class]]) { + [(EaseRecordView *)self.recordView recordButtonTouchUpOutside]; + } + [self.recordView removeFromSuperview]; + } + + _isRecording = NO; + } +} + +- (void)didFinishRecoingVoiceAction:(UIView *)recordView +{ + if (_isRecording) { + if ([self.delegate respondsToSelector:@selector(messageViewController:didSelectRecordView:withEvenType:)]) { + [self.delegate messageViewController:self didSelectRecordView:recordView withEvenType:EaseRecordViewTypeTouchUpInside]; + } else { + if ([self.recordView isKindOfClass:[EaseRecordView class]]) { + [(EaseRecordView *)self.recordView recordButtonTouchUpInside]; + } + [self.recordView removeFromSuperview]; + } + __weak typeof(self) weakSelf = self; + [[EMCDDeviceManager sharedInstance] asyncStopRecordingWithCompletion:^(NSString *recordPath, NSInteger aDuration, NSError *error) { + if (!error) { + [weakSelf sendVoiceMessageWithLocalPath:recordPath duration:aDuration]; + } + else { + [weakSelf showHudInView:self.view hint:error.domain]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [weakSelf hideHud]; + }); + } + }]; + _isRecording = NO; + } +} + +- (void)didDragInsideAction:(UIView *)recordView +{ + if ([self.delegate respondsToSelector:@selector(messageViewController:didSelectRecordView:withEvenType:)]) { + [self.delegate messageViewController:self didSelectRecordView:recordView withEvenType:EaseRecordViewTypeDragInside]; + } else { + if ([self.recordView isKindOfClass:[EaseRecordView class]]) { + [(EaseRecordView *)self.recordView recordButtonDragInside]; + } + } +} + +- (void)didDragOutsideAction:(UIView *)recordView +{ + if ([self.delegate respondsToSelector:@selector(messageViewController:didSelectRecordView:withEvenType:)]) { + [self.delegate messageViewController:self didSelectRecordView:recordView withEvenType:EaseRecordViewTypeDragOutside]; + } else { + if ([self.recordView isKindOfClass:[EaseRecordView class]]) { + [(EaseRecordView *)self.recordView recordButtonDragOutside]; + } + } +} + +#pragma mark - EaseChatBarMoreViewDelegate + +- (void)moreView:(EaseChatBarMoreView *)moreView didItemInMoreViewAtIndex:(NSInteger)index +{ + if ([self.delegate respondsToSelector:@selector(messageViewController:didSelectMoreView:AtIndex:)]) { + [self.delegate messageViewController:self didSelectMoreView:moreView AtIndex:index]; + return; + } +} + +- (void)moreViewPhotoAction:(EaseChatBarMoreView *)moreView +{ + // Hide the keyboard + [self.chatToolbar endEditing:YES]; + + // Pop image picker + self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + self.imagePicker.mediaTypes = @[(NSString *)kUTTypeImage]; + [self presentViewController:self.imagePicker animated:YES completion:NULL]; + + self.isViewDidAppear = NO; + [[EaseSDKHelper shareHelper] setIsShowingimagePicker:YES]; +} + +- (void)moreViewTakePicAction:(EaseChatBarMoreView *)moreView +{ + // Hide the keyboard + [self.chatToolbar endEditing:YES]; + +#if TARGET_IPHONE_SIMULATOR + [self showHint:NSEaseLocalizedString(@"message.simulatorNotSupportCamera", @"simulator does not support taking picture")]; +#elif TARGET_OS_IPHONE + self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; + self.imagePicker.mediaTypes = @[(NSString *)kUTTypeImage,(NSString *)kUTTypeMovie]; + [self presentViewController:self.imagePicker animated:YES completion:NULL]; + + self.isViewDidAppear = NO; + [[EaseSDKHelper shareHelper] setIsShowingimagePicker:YES]; +#endif +} + +- (void)moreViewLocationAction:(EaseChatBarMoreView *)moreView +{ + // Hide the keyboard + [self.chatToolbar endEditing:YES]; + + EaseLocationViewController *locationController = [[EaseLocationViewController alloc] init]; + locationController.delegate = self; + [self.navigationController pushViewController:locationController animated:YES]; +} + +- (void)moreViewAudioCallAction:(EaseChatBarMoreView *)moreView +{ + // Hide the keyboard + [self.chatToolbar endEditing:YES]; + + [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_CALL object:@{@"chatter":self.conversation.conversationId, @"type":[NSNumber numberWithInt:0]}]; +} + +- (void)moreViewVideoCallAction:(EaseChatBarMoreView *)moreView +{ + // Hide the keyboard + [self.chatToolbar endEditing:YES]; + + [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_CALL object:@{@"chatter":self.conversation.conversationId, @"type":[NSNumber numberWithInt:1]}]; +} + +#pragma mark - EMLocationViewDelegate + +-(void)sendLocationLatitude:(double)latitude + longitude:(double)longitude + andAddress:(NSString *)address +{ + [self sendLocationMessageLatitude:latitude longitude:longitude andAddress:address]; +} + +#pragma mark - Hyphenate + +#pragma mark - EMChatManagerDelegate + +- (void)didReceiveMessages:(NSArray *)aMessages +{ + for (EMMessage *message in aMessages) { + if ([self.conversation.conversationId isEqualToString:message.conversationId]) { + [self addMessageToDataSource:message progress:nil]; + + [self _sendHasReadResponseForMessages:@[message] + isRead:NO]; + + if ([self _shouldMarkMessageAsRead]) + { + [self.conversation markMessageAsReadWithId:message.messageId error:nil]; + } + } + } +} + +- (void)didReceiveCmdMessages:(NSArray *)aCmdMessages +{ + for (EMMessage *message in aCmdMessages) { + if ([self.conversation.conversationId isEqualToString:message.conversationId]) { + [self showHint:NSEaseLocalizedString(@"receiveCmd", @"receive cmd message")]; + break; + } + } +} + +- (void)didReceiveHasDeliveredAcks:(NSArray *)aMessages +{ + for(EMMessage *message in aMessages){ + [self _updateMessageStatus:message]; + } +} + +- (void)didReceiveHasReadAcks:(NSArray *)aMessages +{ + for (EMMessage *message in aMessages) { + if (![self.conversation.conversationId isEqualToString:message.conversationId]){ + continue; + } + + __block id<IMessageModel> model = nil; + __block BOOL isHave = NO; + [self.dataArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) + { + if ([obj conformsToProtocol:@protocol(IMessageModel)]) + { + model = (id<IMessageModel>)obj; + if ([model.messageId isEqualToString:message.messageId]) + { + model.message.isReadAcked = YES; + isHave = YES; + *stop = YES; + } + } + }]; + + if(!isHave){ + return; + } + + if (_delegate && [_delegate respondsToSelector:@selector(messageViewController:didReceiveHasReadAckForModel:)]) { + [_delegate messageViewController:self didReceiveHasReadAckForModel:model]; + } + else{ + [self.tableView reloadData]; + } + } +} + +- (void)didMessageStatusChanged:(EMMessage *)aMessage + error:(EMError *)aError; +{ + [self _updateMessageStatus:aMessage]; +} + +- (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{ + + } +} + +#pragma mark - EMCDDeviceManagerProximitySensorDelegate + +- (void)proximitySensorChanged:(BOOL)isCloseToUser +{ + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + if (isCloseToUser) + { + [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; + } else { + [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]; + if (self.playingVoiceModel == nil) { + [[EMCDDeviceManager sharedInstance] disableProximitySensor]; + } + } + [audioSession setActive:YES error:nil]; +} + +#pragma mark - action + +- (void)copyMenuAction:(id)sender +{ + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + if (self.menuIndexPath && self.menuIndexPath.row > 0) { + id<IMessageModel> model = [self.dataArray objectAtIndex:self.menuIndexPath.row]; + pasteboard.string = model.text; + } + + self.menuIndexPath = nil; +} + +- (void)deleteMenuAction:(id)sender +{ + if (self.menuIndexPath && self.menuIndexPath.row > 0) { + id<IMessageModel> model = [self.dataArray objectAtIndex:self.menuIndexPath.row]; + NSMutableIndexSet *indexs = [NSMutableIndexSet indexSetWithIndex:self.menuIndexPath.row]; + NSMutableArray *indexPaths = [NSMutableArray arrayWithObjects:self.menuIndexPath, nil]; + + [self.conversation deleteMessageWithId:model.message.messageId error:nil]; + [self.messsagesSource removeObject:model.message]; + + if (self.menuIndexPath.row - 1 >= 0) { + id nextMessage = nil; + id prevMessage = [self.dataArray objectAtIndex:(self.menuIndexPath.row - 1)]; + if (self.menuIndexPath.row + 1 < [self.dataArray count]) { + nextMessage = [self.dataArray objectAtIndex:(self.menuIndexPath.row + 1)]; + } + if ((!nextMessage || [nextMessage isKindOfClass:[NSString class]]) && [prevMessage isKindOfClass:[NSString class]]) { + [indexs addIndex:self.menuIndexPath.row - 1]; + [indexPaths addObject:[NSIndexPath indexPathForRow:(self.menuIndexPath.row - 1) inSection:0]]; + } + } + + [self.dataArray removeObjectsAtIndexes:indexs]; + [self.tableView beginUpdates]; + [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade]; + [self.tableView endUpdates]; + } + + self.menuIndexPath = nil; +} + +#pragma mark - public + +- (NSArray *)formatMessages:(NSArray *)messages +{ + NSMutableArray *formattedArray = [[NSMutableArray alloc] init]; + if ([messages count] == 0) { + return formattedArray; + } + + for (EMMessage *message in messages) { + //Calculate time interval + CGFloat interval = (self.messageTimeIntervalTag - message.timestamp) / 1000; + if (self.messageTimeIntervalTag < 0 || interval > 60 || interval < -60) { + NSDate *messageDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:(NSTimeInterval)message.timestamp]; + NSString *timeStr = @""; + + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:stringForDate:)]) { + timeStr = [_dataSource messageViewController:self stringForDate:messageDate]; + } + else{ + timeStr = [messageDate formattedTime]; + } + [formattedArray addObject:timeStr]; + self.messageTimeIntervalTag = message.timestamp; + } + + //Construct message model + id<IMessageModel> model = nil; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:modelForMessage:)]) { + model = [_dataSource messageViewController:self modelForMessage:message]; + } + else{ + model = [[EaseMessageModel alloc] initWithMessage:message]; + model.avatarImage = [UIImage easeImageNamed:@"EaseUIResource.bundle/user"]; + model.failImageName = @"imageDownloadFail"; + } + + if (model) { + [formattedArray addObject:model]; + } + } + + return formattedArray; +} + +-(void)addMessageToDataSource:(EMMessage *)message + progress:(id)progress +{ + [self.messsagesSource addObject:message]; + + __weak EaseMessageViewController *weakSelf = self; + dispatch_async(_messageQueue, ^{ + NSArray *messages = [weakSelf formatMessages:@[message]]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.dataArray addObjectsFromArray:messages]; + [weakSelf.tableView reloadData]; + [weakSelf.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[weakSelf.dataArray count] - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; + }); + }); +} + +#pragma mark - public +- (void)tableViewDidTriggerHeaderRefresh +{ + self.messageTimeIntervalTag = -1; + NSString *messageId = nil; + if ([self.messsagesSource count] > 0) { + messageId = [(EMMessage *)self.messsagesSource.firstObject messageId]; + } + else { + messageId = nil; + } + [self _loadMessagesBefore:messageId count:self.messageCountOfPage append:YES]; + + [self tableViewDidFinishTriggerHeader:YES reload:YES]; +} + +#pragma mark - send message + +- (void)_refreshAfterSentMessage:(EMMessage*)aMessage +{ + if ([self.messsagesSource count] && [EMClient sharedClient].options.sortMessageByServerTime) { + NSString *msgId = aMessage.messageId; + EMMessage *last = self.messsagesSource.lastObject; + if ([last isKindOfClass:[EMMessage class]]) { + + __block NSUInteger index = NSNotFound; + index = NSNotFound; + [self.messsagesSource enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(EMMessage *obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:[EMMessage class]] && [obj.messageId isEqualToString:msgId]) { + index = idx; + *stop = YES; + } + }]; + if (index != NSNotFound) { + [self.messsagesSource removeObjectAtIndex:index]; + [self.messsagesSource addObject:aMessage]; + + //��������������� + self.messageTimeIntervalTag = -1; + NSArray *formattedMessages = [self formatMessages:self.messsagesSource]; + [self.dataArray removeAllObjects]; + [self.dataArray addObjectsFromArray:formattedMessages]; + [self.tableView reloadData]; + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[self.dataArray count] - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO]; + return; + } + } + } + [self.tableView reloadData]; +} + +- (void)_sendMessage:(EMMessage *)message + isNeedUploadFile:(BOOL)isUploadFile +{ + if (self.conversation.type == EMConversationTypeGroupChat){ + message.chatType = EMChatTypeGroupChat; + } + else if (self.conversation.type == EMConversationTypeChatRoom){ + message.chatType = EMChatTypeChatRoom; + } + + __weak typeof(self) weakself = self; + if (!([EMClient sharedClient].options.isAutoTransferMessageAttachments) && isUploadFile) { + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedString(@"message.autoTransfer", @"Please customize the transfer attachment method") delegate:nil cancelButtonTitle:NSLocalizedString(@"sure", @"OK") otherButtonTitles:nil, nil]; + [alertView show]; + } else { + [self addMessageToDataSource:message + progress:nil]; + + [[EMClient sharedClient].chatManager sendMessage:message progress:^(int progress) { + if (weakself.dataSource && [weakself.dataSource respondsToSelector:@selector(messageViewController:updateProgress:messageModel:messageBody:)]) { + [weakself.dataSource messageViewController:weakself updateProgress:progress messageModel:nil messageBody:message.body]; + } + } completion:^(EMMessage *aMessage, EMError *aError) { + if (!aError) { + [weakself _refreshAfterSentMessage:aMessage]; + } + else { + [weakself.tableView reloadData]; + } + }]; + } +} + +- (void)sendTextMessage:(NSString *)text +{ + NSDictionary *ext = nil; + if (self.conversation.type == EMConversationTypeGroupChat) { + NSArray *targets = [self _searchAtTargets:text]; + if ([targets count]) { + __block BOOL atAll = NO; + [targets enumerateObjectsUsingBlock:^(NSString *target, NSUInteger idx, BOOL *stop) { + if ([target compare:kGroupMessageAtAll options:NSCaseInsensitiveSearch] == NSOrderedSame) { + atAll = YES; + *stop = YES; + } + }]; + if (atAll) { + ext = @{kGroupMessageAtList: kGroupMessageAtAll}; + } + else { + ext = @{kGroupMessageAtList: targets}; + } + } + } + [self sendTextMessage:text withExt:ext]; +} + +- (void)sendTextMessage:(NSString *)text withExt:(NSDictionary*)ext +{ + EMMessage *message = [EaseSDKHelper getTextMessage:text to:self.conversation.conversationId messageType:[self _messageTypeFromConversationType] messageExt:ext]; + [self _sendMessage:message isNeedUploadFile:NO]; +} + +- (void)sendLocationMessageLatitude:(double)latitude + longitude:(double)longitude + andAddress:(NSString *)address +{ + EMMessage *message = [EaseSDKHelper getLocationMessageWithLatitude:latitude longitude:longitude address:address to:self.conversation.conversationId messageType:[self _messageTypeFromConversationType] messageExt:nil]; + [self _sendMessage:message isNeedUploadFile:NO]; +} + +- (void)sendImageMessageWithData:(NSData *)imageData +{ + id progress = nil; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:progressDelegateForMessageBodyType:)]) { + progress = [_dataSource messageViewController:self progressDelegateForMessageBodyType:EMMessageBodyTypeImage]; + } + else{ + progress = self; + } + + EMMessage *message = [EaseSDKHelper getImageMessageWithImageData:imageData to:self.conversation.conversationId messageType:[self _messageTypeFromConversationType] messageExt:nil]; + [self _sendMessage:message isNeedUploadFile:YES]; +} + +- (void)sendImageMessage:(UIImage *)image +{ + id progress = nil; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:progressDelegateForMessageBodyType:)]) { + progress = [_dataSource messageViewController:self progressDelegateForMessageBodyType:EMMessageBodyTypeImage]; + } + else{ + progress = self; + } + + EMMessage *message = [EaseSDKHelper getImageMessageWithImage:image to:self.conversation.conversationId messageType:[self _messageTypeFromConversationType] messageExt:nil]; + [self _sendMessage:message isNeedUploadFile:YES]; +} + +- (void)sendVoiceMessageWithLocalPath:(NSString *)localPath + duration:(NSInteger)duration +{ + id progress = nil; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:progressDelegateForMessageBodyType:)]) { + progress = [_dataSource messageViewController:self progressDelegateForMessageBodyType:EMMessageBodyTypeVoice]; + } + else{ + progress = self; + } + + EMMessage *message = [EaseSDKHelper getVoiceMessageWithLocalPath:localPath duration:duration to:self.conversation.conversationId messageType:[self _messageTypeFromConversationType] messageExt:nil]; + [self _sendMessage:message isNeedUploadFile:YES]; +} + +- (void)sendVideoMessageWithURL:(NSURL *)url +{ + id progress = nil; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:progressDelegateForMessageBodyType:)]) { + progress = [_dataSource messageViewController:self progressDelegateForMessageBodyType:EMMessageBodyTypeVideo]; + } + else{ + progress = self; + } + + EMMessage *message = [EaseSDKHelper getVideoMessageWithURL:url to:self.conversation.conversationId messageType:[self _messageTypeFromConversationType] messageExt:nil]; + [self _sendMessage:message isNeedUploadFile:YES]; +} + +- (void)sendFileMessageWith:(EMMessage *)message { + [self _sendMessage:message isNeedUploadFile:YES]; +} + +#pragma mark - notifycation +- (void)didBecomeActive +{ + self.messageTimeIntervalTag = -1; + self.dataArray = [[self formatMessages:self.messsagesSource] mutableCopy]; + [self.tableView reloadData]; + + if (self.isViewDidAppear) + { + NSMutableArray *unreadMessages = [NSMutableArray array]; + for (EMMessage *message in self.messsagesSource) + { + if ([self shouldSendHasReadAckForMessage:message read:NO]) + { + [unreadMessages addObject:message]; + } + } + if ([unreadMessages count]) + { + [self _sendHasReadResponseForMessages:unreadMessages isRead:YES]; + } + + [_conversation markAllMessagesAsRead:nil]; + if (self.dataSource && [self.dataSource respondsToSelector:@selector(messageViewControllerMarkAllMessagesAsRead:)]) { + [self.dataSource messageViewControllerMarkAllMessagesAsRead:self]; + } + } +} + +- (void)hideImagePicker +{ + if (_imagePicker && [EaseSDKHelper shareHelper].isShowingimagePicker) { + [_imagePicker dismissViewControllerAnimated:NO completion:nil]; + } +} + +#pragma mark - private +- (void)_reloadTableViewDataWithMessage:(EMMessage *)message +{ + if ([self.conversation.conversationId isEqualToString:message.conversationId]) + { + for (int i = 0; i < self.dataArray.count; i ++) { + id object = [self.dataArray objectAtIndex:i]; + if ([object isKindOfClass:[EaseMessageModel class]]) { + id<IMessageModel> model = object; + if ([message.messageId isEqualToString:model.messageId]) { + id<IMessageModel> model = nil; + if (self.dataSource && [self.dataSource respondsToSelector:@selector(messageViewController:modelForMessage:)]) { + model = [self.dataSource messageViewController:self modelForMessage:message]; + } + else{ + model = [[EaseMessageModel alloc] initWithMessage:message]; + model.avatarImage = [UIImage easeImageNamed:@"EaseUIResource.bundle/user"]; + model.failImageName = @"imageDownloadFail"; + } + + [self.tableView beginUpdates]; + [self.dataArray replaceObjectAtIndex:i withObject:model]; + [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; + [self.tableView endUpdates]; + break; + } + } + } + } +} + +- (void)_updateMessageStatus:(EMMessage *)aMessage +{ + BOOL isChatting = [aMessage.conversationId isEqualToString:self.conversation.conversationId]; + if (aMessage && isChatting) { + id<IMessageModel> model = nil; + if (_dataSource && [_dataSource respondsToSelector:@selector(messageViewController:modelForMessage:)]) { + model = [_dataSource messageViewController:self modelForMessage:aMessage]; + } + else{ + model = [[EaseMessageModel alloc] initWithMessage:aMessage]; + model.avatarImage = [UIImage easeImageNamed:@"EaseUIResource.bundle/user"]; + model.failImageName = @"imageDownloadFail"; + } + if (model) { + __block NSUInteger index = NSNotFound; + [self.dataArray enumerateObjectsUsingBlock:^(EaseMessageModel *model, NSUInteger idx, BOOL *stop){ + if ([model conformsToProtocol:@protocol(IMessageModel)]) { + if ([aMessage.messageId isEqualToString:model.message.messageId]) + { + index = idx; + *stop = YES; + } + } + }]; + + if (index != NSNotFound) + { + [self.dataArray replaceObjectAtIndex:index withObject:model]; + [self.tableView beginUpdates]; + [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; + [self.tableView endUpdates]; + } + } + } +} + +- (NSArray*)_searchAtTargets:(NSString*)text +{ + NSMutableArray *targets = nil; + if (text.length > 1) { + targets = [NSMutableArray array]; + NSArray *splits = [text componentsSeparatedByString:@"@"]; + if ([splits count]) { + for (NSString *split in splits) { + if (split.length) { + NSString *atALl = NSEaseLocalizedString(@"group.atAll", @"all"); + if (split.length >= atALl.length && [split compare:atALl options:NSCaseInsensitiveSearch range:NSMakeRange(0, atALl.length)] == NSOrderedSame) { + [targets removeAllObjects]; + [targets addObject:kGroupMessageAtAll]; + return targets; + } + for (EaseAtTarget *target in self.atTargets) { + if ([target.userId length]) { + if ([split hasPrefix:target.userId] || (target.nickname && [split hasPrefix:target.nickname])) { + [targets addObject:target.userId]; + [self.atTargets removeObject:target]; + break; + } + } + } + } + } + } + } + return targets; +} + + +@end -- Gitblit v1.8.0