| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234 |
- /************************************************************
- * * 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+EMGIF.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, EMChatManagerDelegate>
- {
- 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];
- self.navigationController.navigationBar.translucent = NO;
- self.title = conversationChatter;
-
- [_conversation markAllMessagesAsRead:nil];
- }
-
- return self;
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- [[EMClient sharedClient] addDelegate:self delegateQueue:dispatch_get_main_queue()];
-
- 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, 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 imageNamed:@"EaseUIResource.bundle/chat_sender_bg"] stretchableImageWithLeftCapWidth:5 topCapHeight:35]];
- [[EaseBaseMessageCell appearance] setRecvBubbleBackgroundImage:[[UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_bg"] stretchableImageWithLeftCapWidth:35 topCapHeight:35]];
-
- [[EaseBaseMessageCell appearance] setSendMessageVoiceAnimationImages:@[[UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_full"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_000"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_001"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_002"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_003"]]];
- [[EaseBaseMessageCell appearance] setRecvMessageVoiceAnimationImages:@[[UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing_full"],[UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing000"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing001"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing002"], [UIImage imageNamed:@"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];
-
-
- }
- /*!
- @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;
- 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 aComplation 判断结果
- @result
- */
- - (void)_canRecordComplation:(void(^)(EMRecordResponse))aComplation
- {
- AVAuthorizationStatus videoAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
- if (videoAuthStatus == AVAuthorizationStatusNotDetermined) {
- [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
- if (aComplation) {
- aComplation(EMRequestRecord);
- }
- }];
- }
- else if(videoAuthStatus == AVAuthorizationStatusRestricted || videoAuthStatus == AVAuthorizationStatusDenied) {
- aComplation(EMCanNotRecord);
- }
- else{
- aComplation(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;
- }
- /*!
- @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!")];
- }
- };
-
- EMMessageBody *messageBody = message.body;
- if ([messageBody type] == EMMessageBodyTypeImage) {
- EMImageMessageBody *imageBody = (EMImageMessageBody *)messageBody;
- if (imageBody.thumbnailDownloadStatus > EMDownloadStatusSuccessed)
- {
- //download the message thumbnail
- [[[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
- [[[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
- [[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
- {
- NSString *account = [[EMClient sharedClient] currentUsername];
- 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];
- };
-
- __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"];
- [[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...")];
- [[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];
-
- 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...")];
- [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:^(EMMessage *message, EMError *error) {
- [weakSelf hideHud];
- if (!error) {
- //send the acknowledgement
- [weakSelf _sendHasReadResponseForMessages:@[model.message] isRead:YES];
- NSString *localPath = message == nil ? model.fileLocalPath : [(EMImageMessageBody*)message.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!")];
- }];
- }else{
- //get the message thumbnail
- [[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)
- {
- [self showHint:NSEaseLocalizedString(@"message.downloadingAudio", @"downloading voice, click later")];
- [[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;
- 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 _canRecordComplation:^(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)cmdMessagesDidReceive:(NSArray *)aCmdMessages
- {
- for (EMMessage *message in aCmdMessages) {
- if ([self.conversation.conversationId isEqualToString:message.conversationId]) {
- [self showHint:NSEaseLocalizedString(@"receiveCmd", @"receive cmd message")];
- break;
- }
- }
- }
- - (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)messagesDidDeliver:(NSArray *)aMessages
- {
- for(EMMessage *message in aMessages){
- [self _updateMessageStatus:message];
- }
- }
- - (void)didReceiveHasDeliveredAcks:(NSArray *)aMessages
- {
- for(EMMessage *message in aMessages){
- [self _updateMessageStatus:message];
- }
- }
- - (void)messagesDidRead:(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)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)messageStatusDidChange:(EMMessage *)aMessage
- error:(EMError *)aError
- {
- [self _updateMessageStatus:aMessage];
- }
- - (void)didMessageStatusChanged:(EMMessage *)aMessage
- error:(EMError *)aError;
- {
- [self _updateMessageStatus:aMessage];
- }
- - (void)messageAttachmentStatusDidChange:(EMMessage *)aMessage
- error:(EMError *)aError
- {
- if (!ferror) {
- EMFileMessageBody *fileBody = (EMFileMessageBody*)[aMessage body];
- if ([fileBody type] == EMMessageBodyTypeImage) {
- EMImageMessageBody *imageBody = (EMImageMessageBody *)fileBody;
- if ([imageBody thumbnailDownloadStatus] == EMDownloadStatusSuccessed)
- {
- [self _reloadTableViewDataWithMessage:aMessage];
- }
- }else if([fileBody type] == EMMessageBodyTypeVideo){
- EMVideoMessageBody *videoBody = (EMVideoMessageBody *)fileBody;
- if ([videoBody thumbnailDownloadStatus] == EMDownloadStatusSuccessed)
- {
- [self _reloadTableViewDataWithMessage:aMessage];
- }
- }else if([fileBody type] == EMMessageBodyTypeVoice){
- if ([fileBody downloadStatus] == EMDownloadStatusSuccessed)
- {
- [self _reloadTableViewDataWithMessage:aMessage];
- }
- }
-
- }else{
-
- }
- }
- - (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 imageNamed:@"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:YES];
- return;
- }
- }
- }
- [self.tableView reloadData];
- }
- - (void)_sendMessage:(EMMessage *)message
- {
- if (self.conversation.type == EMConversationTypeGroupChat){
- message.chatType = EMChatTypeGroupChat;
- }
- else if (self.conversation.type == EMConversationTypeChatRoom){
- message.chatType = EMChatTypeChatRoom;
- }
-
- [self addMessageToDataSource:message
- progress:nil];
-
- __weak typeof(self) weakself = self;
- [[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 sendTextMessage:text
- to:self.conversation.conversationId
- messageType:[self _messageTypeFromConversationType]
- messageExt:ext];
- [self _sendMessage:message];
- }
- - (void)sendLocationMessageLatitude:(double)latitude
- longitude:(double)longitude
- andAddress:(NSString *)address
- {
- EMMessage *message = [EaseSDKHelper sendLocationMessageWithLatitude:latitude
- longitude:longitude
- address:address
- to:self.conversation.conversationId
- messageType:[self _messageTypeFromConversationType]
- messageExt:nil];
- [self _sendMessage:message];
- }
- - (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 sendImageMessageWithImageData:imageData
- to:self.conversation.conversationId
- messageType:[self _messageTypeFromConversationType]
- messageExt:nil];
- [self _sendMessage:message];
- }
- - (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 sendImageMessageWithImage:image
- to:self.conversation.conversationId
- messageType:[self _messageTypeFromConversationType]
- messageExt:nil];
- [self _sendMessage:message];
- }
- - (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 sendVoiceMessageWithLocalPath:localPath
- duration:duration
- to:self.conversation.conversationId
- messageType:[self _messageTypeFromConversationType]
- messageExt:nil];
- [self _sendMessage:message];
- }
- - (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 sendVideoMessageWithURL:url
- to:self.conversation.conversationId
- messageType:[self _messageTypeFromConversationType]
- messageExt:nil];
- [self _sendMessage:message];
- }
- - (void)sendFileMessageWith:(EMMessage *)message {
- [self _sendMessage:message];
- }
- #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 imageNamed:@"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 imageNamed:@"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
|