/************************************************************
|
* * 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
|