No Description

ChatViewController.m 52KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446
  1. /************************************************************
  2. * * EaseMob CONFIDENTIAL
  3. * __________________
  4. * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved.
  5. *
  6. * NOTICE: All information contained herein is, and remains
  7. * the property of EaseMob Technologies.
  8. * Dissemination of this information or reproduction of this material
  9. * is strictly forbidden unless prior written permission is obtained
  10. * from EaseMob Technologies.
  11. */
  12. #import "ChatViewController.h"
  13. #import <MediaPlayer/MediaPlayer.h>
  14. #import <AVFoundation/AVFoundation.h>
  15. #import <MobileCoreServices/MobileCoreServices.h>
  16. #import "SRRefreshView.h"
  17. #import "DXChatBarMoreView.h"
  18. #import "DXRecordView.h"
  19. #import "DXFaceView.h"
  20. #import "EMChatViewCell.h"
  21. #import "EMChatTimeCell.h"
  22. #import "MessageReadManager.h"
  23. #import "MessageModelManager.h"
  24. #import "UIViewController+HUD.h"
  25. #import "WCAlertView.h"
  26. #import "NSDate+Category.h"
  27. #import "DXChatBarMoreView.h"
  28. #import "FKMessageManager.h"
  29. #import "EMCDDeviceManager.h"
  30. #import "GalleryScrollView.h"
  31. #import "FKWindowViewManager.h"
  32. #import "FKCustomerEnquiryView.h"
  33. #import "EMChatEnquiryBubbleView.h"
  34. #define KPageCount 20
  35. #define BACKGROUNDCOLOR UIColorFromRGB(0xeeeeee);
  36. NSString *const QueueNameShouqian = @"shouqian";
  37. NSString *const QueueNameShouhou = @"shouhou";
  38. @interface ChatViewController ()<UITableViewDataSource, UITableViewDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, SRRefreshDelegate, EMChatManagerDelegate, DXChatBarMoreViewDelegate, DXMessageToolBarDelegate, FLNetworkDelegate>
  39. {
  40. UIMenuController *_menuController;
  41. UIMenuItem *_copyMenuItem;
  42. UIMenuItem *_deleteMenuItem;
  43. NSIndexPath *_longPressIndexPath;
  44. NSInteger _recordingCount;
  45. BOOL _isScrollToBottom;
  46. }
  47. @property (nonatomic) BOOL isChatGroup;
  48. @property (strong, nonatomic) NSString *chatter;
  49. @property (strong, nonatomic) SRRefreshView *slimeView;
  50. @property (strong, nonatomic) UIImagePickerController *imagePicker;
  51. @property (strong, nonatomic) MessageReadManager *messageReadManager;//message阅读的管理者
  52. @property (strong, nonatomic) NSDate *chatTagDate;
  53. @property (nonatomic) BOOL isScrollToBottom;
  54. @property (nonatomic) BOOL isPlayingAudio;
  55. @property (nonatomic, strong) UIScrollView *galleryScrollView;
  56. @end
  57. @implementation ChatViewController
  58. - (instancetype)initWithChatter:(NSString *)chatter isGroup:(BOOL)isGroup
  59. {
  60. self = [super initWithNibName:nil bundle:nil];
  61. if (self) {
  62. _isPlayingAudio = NO;
  63. _chatter = chatter;
  64. _isChatGroup = isGroup;
  65. _isHasMoreMessage = YES;
  66. //根据接收者的username获取当前会话的管理者
  67. _conversation = [[EMClient sharedClient].chatManager getConversation:chatter type:isGroup createIfNotExist:YES];
  68. _messageQueue = dispatch_queue_create("easemob.com", NULL);
  69. [[NSNotificationCenter defaultCenter] addObserver:self
  70. selector:@selector(loadMoreMessages)
  71. name:HUANXIN_LOGIN_SUCCESS
  72. object:nil];
  73. }
  74. return self;
  75. }
  76. - (void)configChatter:(NSString *)chatter isGroup:(BOOL)isGroup {
  77. _isPlayingAudio = NO;
  78. _chatter = chatter;
  79. _isChatGroup = isGroup;
  80. //根据接收者的username获取当前会话的管理者
  81. if (chatter.length > 0) {
  82. _conversation = [[EMClient sharedClient].chatManager getConversation:chatter type:isGroup createIfNotExist:YES];
  83. }
  84. }
  85. - (void)viewDidLoad
  86. {
  87. [super viewDidLoad];
  88. // Do any additional setup after loading the view.
  89. self.view.backgroundColor = BACKGROUNDCOLOR;
  90. if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
  91. self.edgesForExtendedLayout = UIRectEdgeNone;
  92. }
  93. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(exitGroup) name:@"ExitGroup" object:nil];
  94. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:@"applicationDidEnterBackground" object:nil];
  95. _isScrollToBottom = NO;
  96. [self setupBarButtonItem];
  97. [self.view addSubview:self.tableView];
  98. self.refreshControl.bottomEnabled = NO;
  99. [self.view addSubview:self.chatToolBar];
  100. //将self注册为chatToolBar的moreView的代理
  101. if ([self.chatToolBar.moreView isKindOfClass:[DXChatBarMoreView class]]) {
  102. [(DXChatBarMoreView *)self.chatToolBar.moreView setDelegate:self];
  103. }
  104. [self loadMoreMessages];
  105. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(keyBoardHidden)];
  106. [self.view addGestureRecognizer:tap];
  107. [self.view addSubview:self.galleryScrollView];
  108. }
  109. - (void)setupBarButtonItem
  110. {
  111. if (_isChatGroup) {
  112. UIButton *detailButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60, 44)];
  113. [detailButton setImage:[UIImage imageNamed:@"group_detail"] forState:UIControlStateNormal];
  114. [detailButton addTarget:self action:@selector(showRoomContact:) forControlEvents:UIControlEventTouchUpInside];
  115. self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:detailButton];
  116. }
  117. }
  118. - (void)didReceiveMemoryWarning
  119. {
  120. [super didReceiveMemoryWarning];
  121. // Dispose of any resources that can be recreated.
  122. }
  123. - (void)viewWillAppear:(BOOL)animated
  124. {
  125. [super viewWillAppear:animated];
  126. self.navigationItem.title = self.naviTitle;
  127. [UIApplication sharedApplication].statusBarHidden = NO;
  128. [self.navigationController setNavigationBarHidden:NO animated:NO];
  129. if ([[EMClient sharedClient] isLoggedIn]) {
  130. [self checkAndSendExtMessage];
  131. }
  132. }
  133. - (void)viewDidAppear:(BOOL)animated {
  134. [super viewDidAppear:animated];
  135. if (self.isChatGroup) {
  136. [[FKMessageManager sharedInstance] addEaseMobDelegate:self
  137. observerType:FKEaseMobObserverTypeAssistant];
  138. } else {
  139. [[FKMessageManager sharedInstance] addEaseMobDelegate:self
  140. observerType:FKEaseMobObserverTypeService];
  141. }
  142. //通过会话管理者获取已收发消息
  143. [self loadMoreMessages];
  144. }
  145. - (void)viewWillDisappear:(BOOL)animated
  146. {
  147. [super viewWillDisappear:animated];
  148. // 设置当前conversation的所有message为已读
  149. [_conversation markAllMessagesAsRead:nil];
  150. }
  151. - (void)viewDidDisappear:(BOOL)animated {
  152. [super viewDidDisappear:animated];
  153. if (self.isChatGroup) {
  154. [[FKMessageManager sharedInstance] removeEaseMobDelegate:self
  155. observerType:FKEaseMobObserverTypeAssistant];
  156. } else {
  157. [[FKMessageManager sharedInstance] removeEaseMobDelegate:self
  158. observerType:FKEaseMobObserverTypeService];
  159. }
  160. }
  161. - (void)dealloc
  162. {
  163. _tableView.delegate = nil;
  164. _tableView.dataSource = nil;
  165. _tableView = nil;
  166. _slimeView.delegate = nil;
  167. _slimeView = nil;
  168. _chatToolBar.delegate = nil;
  169. _chatToolBar = nil;
  170. [[EMCDDeviceManager sharedInstance] stopPlaying];
  171. [[NSNotificationCenter defaultCenter] removeObserver:self];
  172. }
  173. #pragma mark - helper
  174. - (NSURL *)convert2Mp4:(NSURL *)movUrl {
  175. NSURL *mp4Url = nil;
  176. AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:movUrl options:nil];
  177. NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
  178. if ([compatiblePresets containsObject:AVAssetExportPresetHighestQuality]) {
  179. AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset
  180. presetName:AVAssetExportPresetHighestQuality];
  181. NSString *mp4Path = [NSString stringWithFormat:@"%@/%d%d.mp4", [EMCDDeviceManager dataPath], (int)[[NSDate date] timeIntervalSince1970], arc4random() % 100000];
  182. mp4Url = [NSURL fileURLWithPath:mp4Path];
  183. exportSession.outputURL = mp4Url;
  184. exportSession.shouldOptimizeForNetworkUse = YES;
  185. exportSession.outputFileType = AVFileTypeMPEG4;
  186. dispatch_semaphore_t wait = dispatch_semaphore_create(0l);
  187. [exportSession exportAsynchronouslyWithCompletionHandler:^{
  188. switch ([exportSession status]) {
  189. case AVAssetExportSessionStatusFailed: {
  190. NSLog(@"failed, error:%@.", exportSession.error);
  191. } break;
  192. case AVAssetExportSessionStatusCancelled: {
  193. NSLog(@"cancelled.");
  194. } break;
  195. case AVAssetExportSessionStatusCompleted: {
  196. NSLog(@"completed.");
  197. } break;
  198. default: {
  199. NSLog(@"others.");
  200. } break;
  201. }
  202. dispatch_semaphore_signal(wait);
  203. }];
  204. long timeout = dispatch_semaphore_wait(wait, DISPATCH_TIME_FOREVER);
  205. if (timeout) {
  206. NSLog(@"timeout.");
  207. }
  208. if (wait) {
  209. //dispatch_release(wait);
  210. wait = nil;
  211. }
  212. }
  213. return mp4Url;
  214. }
  215. - (void)configHeadPhotoWith:(MessageModel *)model {
  216. if (model.isSender) {
  217. model.headPhotoURL = [FKUserManager sharedManager].user.headurl;
  218. model.nickName = [FKUserManager sharedManager].user.nickName;;
  219. } else {
  220. if (self.receiverHeadURL) {
  221. model.headPhotoURL = self.receiverHeadURL;
  222. NSDictionary *agent = model.message.ext[@"weichat"][@"agent"];
  223. if ([agent isKindOfClass:[NSDictionary class]]) {
  224. NSString *nickName = agent[@"userNickname"];
  225. if ([nickName isKindOfClass:[NSString class]]) {
  226. if ([nickName isEqualToString:@"调度员"]) {
  227. model.nickName = self.naviTitle;
  228. } else {
  229. model.nickName = nickName;
  230. }
  231. } else {
  232. model.nickName = self.naviTitle ? : @"剁剁小秘书";
  233. }
  234. }
  235. }
  236. // else {
  237. // model.headPhotoURL = [FKAssistantReform parseHeadPhotoURL:model.message.ext];
  238. // }
  239. }
  240. }
  241. - (void)finishLoadingDataWith:(NSTimeInterval)interval {
  242. [NSTimer scheduledTimerWithTimeInterval:interval
  243. target:self
  244. selector:@selector(finishLoadingData)
  245. userInfo:nil
  246. repeats:NO];
  247. }
  248. #pragma mark - getter
  249. - (NSMutableArray *)dataSource
  250. {
  251. if (_dataSource == nil) {
  252. _dataSource = [NSMutableArray array];
  253. }
  254. return _dataSource;
  255. }
  256. - (SRRefreshView *)slimeView
  257. {
  258. if (_slimeView == nil) {
  259. _slimeView = [[SRRefreshView alloc] init];
  260. _slimeView.delegate = self;
  261. _slimeView.upInset = 0;
  262. _slimeView.slimeMissWhenGoingBack = YES;
  263. _slimeView.slime.bodyColor = [UIColor grayColor];
  264. _slimeView.slime.skinColor = [UIColor grayColor];
  265. _slimeView.slime.lineWith = 1;
  266. _slimeView.slime.shadowBlur = 4;
  267. _slimeView.slime.shadowColor = [UIColor grayColor];
  268. }
  269. return _slimeView;
  270. }
  271. - (UITableView *)tableView
  272. {
  273. if (_tableView == nil) {
  274. _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - self.chatToolBar.frame.size.height) style:UITableViewStylePlain];
  275. _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
  276. _tableView.delegate = self;
  277. _tableView.dataSource = self;
  278. _tableView.backgroundColor = BACKGROUNDCOLOR;
  279. _tableView.tableFooterView = [[UIView alloc] init];
  280. _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  281. UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
  282. lpgr.minimumPressDuration = .5;
  283. [_tableView addGestureRecognizer:lpgr];
  284. [self initRefreshControlWithTableView:_tableView];
  285. }
  286. return _tableView;
  287. }
  288. - (DXMessageToolBar *)chatToolBar
  289. {
  290. if (_chatToolBar == nil) {
  291. _chatToolBar = [[DXMessageToolBar alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - [DXMessageToolBar defaultHeight], self.view.frame.size.width, [DXMessageToolBar defaultHeight])];
  292. _chatToolBar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
  293. _chatToolBar.delegate = self;
  294. ChatMoreType type = _isChatGroup == YES ? ChatMoreTypeGroupChat : ChatMoreTypeChat;
  295. _chatToolBar.moreView = [[DXChatBarMoreView alloc] initWithFrame:CGRectMake(0, (kVerticalPadding * 2 + kInputTextViewMinHeight), _chatToolBar.frame.size.width, 100) typw:type];
  296. _chatToolBar.moreView.backgroundColor = [UIColor whiteColor];
  297. _chatToolBar.moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
  298. }
  299. return _chatToolBar;
  300. }
  301. - (UIImagePickerController *)imagePicker
  302. {
  303. if (_imagePicker == nil) {
  304. _imagePicker = [[UIImagePickerController alloc] init];
  305. _imagePicker.delegate = self;
  306. }
  307. return _imagePicker;
  308. }
  309. - (MessageReadManager *)messageReadManager
  310. {
  311. if (_messageReadManager == nil) {
  312. _messageReadManager = [MessageReadManager defaultManager];
  313. }
  314. return _messageReadManager;
  315. }
  316. - (NSDate *)chatTagDate
  317. {
  318. if (_chatTagDate == nil) {
  319. _chatTagDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:0];
  320. }
  321. return _chatTagDate;
  322. }
  323. #pragma mark - Table view data source
  324. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  325. {
  326. // Return the number of sections.
  327. return 1;
  328. }
  329. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  330. {
  331. return self.dataSource.count;
  332. }
  333. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  334. {
  335. if (indexPath.row < [self.dataSource count]) {
  336. id obj = [self.dataSource objectAtIndex:indexPath.row];
  337. if ([obj isKindOfClass:[NSString class]]) {
  338. EMChatTimeCell *timeCell = (EMChatTimeCell *)[tableView dequeueReusableCellWithIdentifier:@"MessageCellTime"];
  339. if (timeCell == nil) {
  340. timeCell = [[EMChatTimeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MessageCellTime"];
  341. timeCell.backgroundColor = [UIColor clearColor];
  342. timeCell.selectionStyle = UITableViewCellSelectionStyleNone;
  343. }
  344. timeCell.textLabel.text = (NSString *)obj;
  345. return timeCell;
  346. } else {
  347. MessageModel *model = (MessageModel *)obj;
  348. [self configHeadPhotoWith:model];
  349. NSString *cellIdentifier = [EMChatViewCell cellIdentifierForMessageModel:model];
  350. EMChatViewCell *cell = (EMChatViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  351. if (cell == nil) {
  352. cell = [[EMChatViewCell alloc] initWithMessageModel:model reuseIdentifier:cellIdentifier];
  353. cell.backgroundColor = [UIColor clearColor];
  354. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  355. }
  356. cell.messageModel = model;
  357. if ([cell.bubbleView isKindOfClass:[EMChatEnquiryBubbleView class]]) {
  358. WeakSelf(weakSelf);
  359. EMChatEnquiryBubbleView *bubbleView = (EMChatEnquiryBubbleView*)cell.bubbleView;
  360. bubbleView.enquiryCellCallback = ^() {
  361. [weakSelf showEnquiryView:model];
  362. };
  363. }
  364. return cell;
  365. }
  366. }
  367. return nil;
  368. }
  369. #pragma mark - Table view delegate
  370. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
  371. {
  372. NSObject *obj = [self.dataSource objectAtIndex:indexPath.row];
  373. if ([obj isKindOfClass:[NSString class]]) {
  374. return 40;
  375. } else {
  376. MessageModel *model = (MessageModel *)obj;
  377. return [EMChatViewCell tableView:tableView
  378. heightForRowAtIndexPath:indexPath
  379. withObject:model];
  380. }
  381. }
  382. #pragma mark - RefreshControlDelegate
  383. - (void)refreshControl:(FKRefreshControl *)refreshControl didEngageRefreshDirection:(RefreshDirection)direction
  384. {
  385. [self finishLoadingDataWith:0.5];
  386. }
  387. #pragma mark - GestureRecognizer
  388. // 点击背景隐藏
  389. -(void)keyBoardHidden
  390. {
  391. [self.chatToolBar endEditing:YES];
  392. }
  393. - (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer
  394. {
  395. if (recognizer.state == UIGestureRecognizerStateBegan && [self.dataSource count] > 0) {
  396. CGPoint location = [recognizer locationInView:self.tableView];
  397. NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:location];
  398. id object = [self.dataSource objectAtIndex:indexPath.row];
  399. if ([object isKindOfClass:[MessageModel class]]) {
  400. EMChatViewCell *cell = (EMChatViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
  401. [cell becomeFirstResponder];
  402. _longPressIndexPath = indexPath;
  403. [self showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.messageModel.type];
  404. }
  405. }
  406. }
  407. #pragma mark - UIResponder actions
  408. - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo
  409. {
  410. MessageModel *model = [userInfo objectForKey:KMESSAGEKEY];
  411. UIImageView *imageView = [userInfo objectForKey:KMESSAGE_IMAGEVIEW_KEY];
  412. if ([eventName isEqualToString:kRouterEventTextURLTapEventName]) {
  413. [self chatTextCellUrlPressed:[userInfo objectForKey:@"url"]];
  414. }
  415. else if ([eventName isEqualToString:kRouterEventAudioBubbleTapEventName]) {
  416. [self chatAudioCellBubblePressed:model];
  417. }
  418. else if ([eventName isEqualToString:kRouterEventImageBubbleTapEventName]){
  419. [self chatImageCellBubblePressed:model imageView:imageView];
  420. }
  421. else if ([eventName isEqualToString:kRouterEventLocationBubbleTapEventName]){
  422. [self chatLocationCellBubblePressed:model];
  423. }
  424. else if([eventName isEqualToString:kResendButtonTapEventName]){
  425. EMChatViewCell *resendCell = [userInfo objectForKey:kShouldResendCell];
  426. MessageModel *messageModel = resendCell.messageModel;
  427. messageModel.status = EMMessageStatusDelivering;
  428. NSIndexPath *indexPath = [self.tableView indexPathForCell:resendCell];
  429. [self.tableView beginUpdates];
  430. [self.tableView reloadRowsAtIndexPaths:@[indexPath]
  431. withRowAnimation:UITableViewRowAnimationNone];
  432. [self.tableView endUpdates];
  433. id<IEMChatManager> chatManager = [[EMClient sharedClient] chatManager];
  434. [chatManager sendMessage:messageModel.message progress:nil completion:nil];
  435. } else if ([eventName isEqualToString:kRouterEventChatHeadImageTapEventName]) {
  436. // MessageModel *model = userInfo[KMESSAGEKEY];
  437. } else if([eventName isEqualToString:kRouterEventChatCellVideoTapEventName]){
  438. [self chatVideoCellPressed:model];
  439. }
  440. }
  441. //链接被点击
  442. - (void)chatTextCellUrlPressed:(NSURL *)url
  443. {
  444. if (url) {
  445. [[UIApplication sharedApplication] openURL:url];
  446. }
  447. }
  448. // 语音的bubble被点击
  449. -(void)chatAudioCellBubblePressed:(MessageModel *)model
  450. {
  451. EMVoiceMessageBody *body = model.message.body;
  452. EMDownloadStatus downloadStatus = [body downloadStatus];
  453. if (downloadStatus == EMDownloadStatusDownloading) {
  454. [self showHint:@"正在下载语音,稍后点击"];
  455. return;
  456. }
  457. else if (downloadStatus == EMDownloadStatusFailed)
  458. {
  459. [self showHint:@"正在下载语音,稍后点击"];
  460. [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:nil];
  461. return;
  462. }
  463. // 播放音频
  464. if (body.type == EMMessageBodyTypeVoice) {
  465. __weak ChatViewController *weakSelf = self;
  466. BOOL isPrepare = [self.messageReadManager prepareMessageAudioModel:model updateViewCompletion:^(MessageModel *prevAudioModel, MessageModel *currentAudioModel) {
  467. if (prevAudioModel || currentAudioModel) {
  468. [weakSelf.tableView reloadData];
  469. }
  470. }];
  471. if (isPrepare) {
  472. _isPlayingAudio = YES;
  473. // __weak ChatViewController *weakSelf = self;
  474. // [[[EaseMob sharedInstance] deviceManager] enableProximitySensor];
  475. // [[EaseMob sharedInstance].chatManager asyncPlayAudio:model.chatVoice completion:^(EMError *error) {
  476. // [weakSelf.messageReadManager stopMessageAudioModel];
  477. //
  478. // dispatch_async(dispatch_get_main_queue(), ^{
  479. // [weakSelf.tableView reloadData];
  480. //
  481. // weakSelf.isPlayingAudio = NO;
  482. // [[[EaseMob sharedInstance] deviceManager] disableProximitySensor];
  483. // });
  484. // } onQueue:nil];
  485. }
  486. else{
  487. _isPlayingAudio = NO;
  488. }
  489. }
  490. }
  491. // 位置的bubble被点击
  492. -(void)chatLocationCellBubblePressed:(MessageModel *)model
  493. {
  494. _isScrollToBottom = NO;
  495. }
  496. - (void)chatVideoCellPressed:(MessageModel *)model{
  497. // __weak ChatViewController *weakSelf = self;
  498. // id <IChatManager> chatManager = [[EaseMob sharedInstance] chatManager];
  499. // [weakSelf showHudInView:weakSelf.view hint:@"正在获取视频..."];
  500. // [chatManager asyncFetchMessage:model.message progress:nil completion:^(EMMessage *aMessage, EMError *error) {
  501. // [weakSelf hideHud];
  502. // if (!error) {
  503. // NSString *localPath = aMessage == nil ? model.localPath : [[aMessage.messageBodies firstObject] localPath];
  504. // if (localPath && localPath.length > 0) {
  505. // [weakSelf playVideoWithVideoPath:localPath];
  506. // }
  507. // }else{
  508. // [weakSelf showHint:@"视频获取失败!"];
  509. // }
  510. // } onQueue:nil];
  511. }
  512. - (void)playVideoWithVideoPath:(NSString *)videoPath
  513. {
  514. _isScrollToBottom = NO;
  515. NSURL *videoURL = [NSURL fileURLWithPath:videoPath];
  516. MPMoviePlayerViewController *moviePlayerController = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL];
  517. [moviePlayerController.moviePlayer prepareToPlay];
  518. moviePlayerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
  519. [self presentMoviePlayerViewControllerAnimated:moviePlayerController];
  520. }
  521. // 图片的bubble被点击
  522. -(void)chatImageCellBubblePressed:(MessageModel *)model imageView:(UIImageView *)imageView
  523. {
  524. __weak ChatViewController *weakSelf = self;
  525. if ([model.messageBody type] == EMMessageBodyTypeImage) {
  526. EMImageMessageBody *imageBody = (EMImageMessageBody *)[model.message body];
  527. if (imageBody.thumbnailDownloadStatus == EMDownloadStatusSuccessed) {
  528. [weakSelf showHudInView:weakSelf.view hint:@"正在获取大图..."];
  529. [[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:^(EMMessage *message, EMError *error) {
  530. [weakSelf hideHud];
  531. if (!error) {
  532. //send the acknowledgement
  533. [weakSelf sendHasReadResponseForMessages:@[model.message] isRead:YES];
  534. NSString *localPath = message == nil ? model.localPath : [(EMImageMessageBody*)message.body localPath];
  535. if (localPath && localPath.length > 0) {
  536. UIImage *image = [UIImage imageWithContentsOfFile:localPath];
  537. weakSelf.isScrollToBottom = NO;
  538. if (image) {
  539. [self tapImage:image imageView:imageView];
  540. }
  541. return ;
  542. }
  543. }
  544. [weakSelf showHint:@"大图获取失败!"];
  545. }];
  546. } else {
  547. //获取缩略图
  548. [[EMClient sharedClient].chatManager downloadMessageThumbnail:model.message progress:nil completion:^(EMMessage *message, EMError *error) {
  549. if (!error) {
  550. [weakSelf reloadTableViewDataWithMessage:model.message];
  551. }else{
  552. [weakSelf showHint:@"缩略图获取失败!"];
  553. }
  554. }];
  555. }
  556. }
  557. }
  558. #pragma mark - IChatManagerDelegate
  559. //-(void)didSendMessage:(EMMessage *)message error:(EMError *)error;
  560. //{
  561. // [self.dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
  562. // {
  563. // if ([obj isKindOfClass:[MessageModel class]])
  564. // {
  565. // MessageModel *model = (MessageModel*)obj;
  566. // if ([model.messageId isEqualToString:message.messageId])
  567. // {
  568. // model.message.deliveryState = message.deliveryState;
  569. // *stop = YES;
  570. // }
  571. // }
  572. // }];
  573. // [self.tableView reloadData];
  574. //}
  575. - (void)reloadTableViewDataWithMessage:(EMMessage *)message{
  576. __weak ChatViewController *weakSelf = self;
  577. dispatch_async(_messageQueue, ^{
  578. if ([weakSelf.conversation.conversationId isEqualToString:message.conversationId])
  579. {
  580. for (int i = 0; i < weakSelf.dataSource.count; i ++) {
  581. id object = [weakSelf.dataSource objectAtIndex:i];
  582. if ([object isKindOfClass:[MessageModel class]]) {
  583. EMMessage *currMsg = [weakSelf.dataSource objectAtIndex:i];
  584. if ([message.messageId isEqualToString:currMsg.messageId]) {
  585. MessageModel *cellModel = [MessageModelManager modelWithMessage:message];
  586. dispatch_async(dispatch_get_main_queue(), ^{
  587. [weakSelf.tableView beginUpdates];
  588. [weakSelf.dataSource replaceObjectAtIndex:i withObject:cellModel];
  589. [weakSelf.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
  590. [weakSelf.tableView endUpdates];
  591. });
  592. break;
  593. }
  594. }
  595. }
  596. }
  597. });
  598. }
  599. - (void)didMessageAttachmentsStatusChanged:(EMMessage *)message error:(EMError *)error{
  600. if (!error) {
  601. EMFileMessageBody *fileBody = (EMFileMessageBody*)[message body];
  602. if ([fileBody type] == EMMessageBodyTypeImage) {
  603. EMImageMessageBody *imageBody = (EMImageMessageBody *)fileBody;
  604. if ([imageBody thumbnailDownloadStatus] == EMDownloadStatusSuccessed) {
  605. [self reloadTableViewDataWithMessage:message];
  606. }
  607. } else if([fileBody type] == EMMessageBodyTypeVideo){
  608. EMVideoMessageBody *videoBody = (EMVideoMessageBody *)fileBody;
  609. if ([videoBody thumbnailDownloadStatus] == EMDownloadStatusSuccessed) {
  610. [self reloadTableViewDataWithMessage:message];
  611. }
  612. } else if([fileBody type] == EMMessageBodyTypeVoice){
  613. if ([fileBody downloadStatus] == EMDownloadStatusSuccessed) {
  614. [self reloadTableViewDataWithMessage:message];
  615. }
  616. }
  617. } else {
  618. }
  619. }
  620. - (void)didFetchingMessageAttachments:(EMMessage *)message progress:(float)progress{
  621. NSLog(@"didFetchingMessageAttachment: %f", progress);
  622. }
  623. - (void)messagesDidReceive:(NSArray *)aMessages
  624. {
  625. for (EMMessage *message in aMessages) {
  626. if ([_conversation.conversationId isEqualToString:message.conversationId]) {
  627. [self addChatDataToMessage:message];
  628. }
  629. }
  630. }
  631. - (void)messagesDidDeliver:(NSArray *)aMessages {
  632. for (EMMessage *message in aMessages) {
  633. [self.dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
  634. {
  635. if ([obj isKindOfClass:[MessageModel class]])
  636. {
  637. MessageModel *model = (MessageModel*)obj;
  638. if ([model.messageId isEqualToString:message.messageId])
  639. {
  640. model.status = message.status;
  641. model.message.status = message.status;
  642. *stop = YES;
  643. }
  644. }
  645. }];
  646. }
  647. [self.tableView reloadData];
  648. }
  649. - (void)group:(EMGroup *)group didLeave:(EMGroupLeaveReason)reason error:(EMError *)error
  650. {
  651. if (_isChatGroup && [group.groupId isEqualToString:_chatter]) {
  652. [self.navigationController popToViewController:self animated:NO];
  653. [self.navigationController popViewControllerAnimated:NO];
  654. }
  655. }
  656. - (void)didInterruptionRecordAudio
  657. {
  658. [_chatToolBar cancelTouchRecord];
  659. // 设置当前conversation的所有message为已读
  660. [_conversation markAllMessagesAsRead:nil];
  661. [self stopAudioPlaying];
  662. }
  663. #pragma mark - EMChatBarMoreViewDelegate
  664. - (void)moreViewPhotoAction:(DXChatBarMoreView *)moreView
  665. {
  666. // 隐藏键盘
  667. [self keyBoardHidden];
  668. // 弹出照片选择
  669. self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
  670. self.imagePicker.mediaTypes = @[(NSString *)kUTTypeImage];
  671. [self presentViewController:self.imagePicker animated:YES completion:NULL];
  672. }
  673. - (void)moreViewTakePicAction:(DXChatBarMoreView *)moreView
  674. {
  675. [self keyBoardHidden];
  676. #if TARGET_IPHONE_SIMULATOR
  677. [self showHint:@"模拟器不支持拍照"];
  678. #elif TARGET_OS_IPHONE
  679. self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
  680. self.imagePicker.mediaTypes = @[(NSString *)kUTTypeImage];
  681. [self presentViewController:self.imagePicker animated:YES completion:NULL];
  682. #endif
  683. }
  684. - (void)moreViewLocationAction:(DXChatBarMoreView *)moreView
  685. {
  686. // 隐藏键盘
  687. [self keyBoardHidden];
  688. }
  689. - (void)moreViewVideoAction:(DXChatBarMoreView *)moreView{
  690. [self keyBoardHidden];
  691. #if TARGET_IPHONE_SIMULATOR
  692. [self showHint:@"模拟器不支持录像"];
  693. #elif TARGET_OS_IPHONE
  694. self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
  695. self.imagePicker.mediaTypes = @[(NSString *)kUTTypeMovie];
  696. [self presentViewController:self.imagePicker animated:YES completion:NULL];
  697. #endif
  698. }
  699. #pragma mark - LocationViewDelegate
  700. -(void)sendLocationLatitude:(double)latitude longitude:(double)longitude andAddress:(NSString *)address
  701. {
  702. }
  703. #pragma mark - NavigationControllerDelegate
  704. - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
  705. [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
  706. }
  707. #pragma mark - DXMessageToolBarDelegate
  708. - (void)didStyleChangeToRecord:(BOOL)changedToRecord {
  709. [self beginTouchMessageToolBar];
  710. }
  711. - (void)inputTextViewWillBeginEditing:(XHMessageTextView *)messageInputTextView{
  712. [_menuController setMenuItems:nil];
  713. [self beginTouchMessageToolBar];
  714. }
  715. - (void)didChangeFrameToHeight:(CGFloat)toHeight
  716. {
  717. // [self beginTouchMessageToolBar];
  718. [UIView animateWithDuration:0.3 animations:^{
  719. CGRect rect = self.tableView.frame;
  720. rect.origin.y = 0;
  721. rect.size.height = self.view.frame.size.height - toHeight;
  722. self.tableView.frame = rect;
  723. }];
  724. [self scrollViewToBottom:YES];
  725. }
  726. - (void)didSendText:(NSString *)text
  727. {
  728. if (text && text.length > 0) {
  729. [self sendTextMessage:text];
  730. }
  731. }
  732. - (void)didSelectedFaceButton:(BOOL)isSelected {
  733. [self beginTouchMessageToolBar];
  734. }
  735. - (void)didSelectedMoreButton:(BOOL)isSelected {
  736. [self beginTouchMessageToolBar];
  737. }
  738. - (void)didSelectedMorePhotoButton {
  739. [self.navigationController presentViewController:self.imagePicker
  740. animated:YES
  741. completion:^{
  742. [self.chatToolBar resignFirstResponder];
  743. }];
  744. }
  745. - (void)didSelectedMoreCameraButton {
  746. [self beginTouchMessageToolBar];
  747. UIImagePickerController *cameraPicker = [[UIImagePickerController alloc] init];
  748. cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
  749. cameraPicker.delegate = self;
  750. [self.navigationController presentViewController:cameraPicker
  751. animated:YES
  752. completion:^{
  753. [self.chatToolBar resignFirstResponder];
  754. }];
  755. }
  756. /**
  757. * 按下录音按钮开始录音
  758. */
  759. - (void)didStartRecordingVoiceAction:(UIView *)recordView
  760. {
  761. [self beginTouchMessageToolBar];
  762. DXRecordView *tmpView = (DXRecordView *)recordView;
  763. tmpView.center = self.view.center;
  764. [self.view addSubview:tmpView];
  765. [self.view bringSubviewToFront:recordView];
  766. // NSError *error = nil;
  767. // [[EaseMob sharedInstance].chatManager startRecordingAudioWithError:&error];
  768. // if (error) {
  769. // NSLog(@"开始录音失败");
  770. // }
  771. }
  772. /**
  773. * 手指向上滑动取消录音
  774. */
  775. - (void)didCancelRecordingVoiceAction:(UIView *)recordView
  776. {
  777. // [[EaseMob sharedInstance].chatManager asyncCancelRecordingAudioWithCompletion:nil onQueue:nil];
  778. }
  779. /**
  780. * 松开手指完成录音
  781. */
  782. - (void)didFinishRecoingVoiceAction:(UIView *)recordView
  783. {
  784. // WeakSelf(weakSelf);
  785. // [[EaseMob sharedInstance].chatManager
  786. // asyncStopRecordingAudioWithCompletion:^(EMChatVoice *aChatVoice, NSError *error){
  787. // if (!error) {
  788. // [self sendAudioMessage:aChatVoice];
  789. // }else{
  790. // if (error.code == EMErrorAudioRecordNotStarted) {
  791. // [FLProgressHUDHelper showText:@"录音没有开始" inView:weakSelf.view];
  792. // } else {
  793. // [FLProgressHUDHelper showText:@"说话时间太短" inView:weakSelf.view];
  794. // }
  795. // }
  796. //
  797. // } onQueue:nil];
  798. }
  799. #pragma mark - UIImagePickerControllerDelegate
  800. - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
  801. {
  802. NSString *mediaType = info[UIImagePickerControllerMediaType];
  803. if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {
  804. // NSURL *videoURL = info[UIImagePickerControllerMediaURL];
  805. // [picker dismissViewControllerAnimated:YES completion:nil];
  806. // video url:
  807. // file:///private/var/mobile/Applications/B3CDD0B2-2F19-432B-9CFA-158700F4DE8F/tmp/capture-T0x16e39100.tmp.9R8weF/capturedvideo.mp4
  808. // we will convert it to mp4 format
  809. // NSURL *mp4 = [self convert2Mp4:videoURL];
  810. // NSFileManager *fileman = [NSFileManager defaultManager];
  811. // if ([fileman fileExistsAtPath:videoURL.path]) {
  812. // NSError *error = nil;
  813. // [fileman removeItemAtURL:videoURL error:&error];
  814. // if (error) {
  815. // NSLog(@"failed to remove file, error:%@.", error);
  816. // }
  817. // }
  818. } else {
  819. UIImage *orgImage = info[UIImagePickerControllerOriginalImage];
  820. [picker dismissViewControllerAnimated:YES completion:nil];
  821. [self sendImageMessage:orgImage];
  822. }
  823. }
  824. - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
  825. {
  826. [self.imagePicker dismissViewControllerAnimated:YES completion:nil];
  827. }
  828. #pragma mark - MenuItem actions
  829. - (void)copyMenuAction:(id)sender
  830. {
  831. // todo by du. 复制
  832. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  833. if (_longPressIndexPath.row > 0) {
  834. MessageModel *model = [self.dataSource objectAtIndex:_longPressIndexPath.row];
  835. pasteboard.string = model.content;
  836. }
  837. _longPressIndexPath = nil;
  838. }
  839. - (void)deleteMenuAction:(id)sender
  840. {
  841. if (_longPressIndexPath && _longPressIndexPath.row > 0) {
  842. MessageModel *model = [self.dataSource objectAtIndex:_longPressIndexPath.row];
  843. NSMutableArray *messages = [NSMutableArray arrayWithObjects:model, nil];
  844. [_conversation deleteMessageWithId:model.message.messageId error:nil];
  845. NSMutableArray *indexPaths = [NSMutableArray arrayWithObjects:_longPressIndexPath, nil];;
  846. if (_longPressIndexPath.row - 1 >= 0) {
  847. id nextMessage = nil;
  848. id prevMessage = [self.dataSource objectAtIndex:(_longPressIndexPath.row - 1)];
  849. if (_longPressIndexPath.row + 1 < [self.dataSource count]) {
  850. nextMessage = [self.dataSource objectAtIndex:(_longPressIndexPath.row + 1)];
  851. }
  852. if ((!nextMessage || [nextMessage isKindOfClass:[NSString class]]) && [prevMessage isKindOfClass:[NSString class]]) {
  853. [messages addObject:prevMessage];
  854. [indexPaths addObject:[NSIndexPath indexPathForRow:(_longPressIndexPath.row - 1) inSection:0]];
  855. }
  856. }
  857. [self.dataSource removeObjectsInArray:messages];
  858. [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
  859. }
  860. _longPressIndexPath = nil;
  861. }
  862. - (void)beginTouchMessageToolBar {
  863. }
  864. #pragma mark - Method
  865. - (void)showEnquiryView:(MessageModel*)model {
  866. [self.chatToolBar removeKeyboardEvent];
  867. CGFloat width = 275, height = 400;
  868. FKCustomerEnquiryView *view = [FKCustomerEnquiryView new];
  869. view.frame = CGRectMake((UISCREENWIDTH-width)/2, (UISCREENHEIGH-height)/2, width, height);
  870. if (self.receiverHeadURL) {
  871. [view.headImgView sd_setImageWithURL:[NSURL URLWithString:self.receiverHeadURL]];
  872. }
  873. WeakSelf(weakSelf);
  874. view.enquirySubmitCallback = ^(NSString *summary, NSString *detail) {
  875. if (summary.length > 0) {
  876. NSDictionary *weichat = model.message.ext[@"weichat"];
  877. if ([weichat isKindOfClass:[NSDictionary class]]) {
  878. NSString *ctrlType = weichat[@"ctrlType"];
  879. NSDictionary *ctrlArgs = weichat[@"ctrlArgs"];
  880. NSString *inviteId;
  881. NSString *serviceSessionId;
  882. if ([ctrlArgs isKindOfClass:[NSDictionary class]]) {
  883. inviteId = [NSString stringWithFormat:@"%@", ctrlArgs[@"inviteId"]];
  884. serviceSessionId = ctrlArgs[@"serviceSessionId"];
  885. }
  886. if (ctrlType.length > 0 && inviteId.length > 0 && serviceSessionId.length > 0) {
  887. NSDictionary *ext = @{@"weichat": @{@"ctrlType": @"enquiry",
  888. @"ctrlArgs": @{@"inviteId": inviteId,
  889. @"serviceSessionId": serviceSessionId,
  890. @"summary": summary,
  891. @"detail": [FLStringHelper replaceNilWithEmpty:detail]}}};
  892. EMMessage *message = [ChatSendHelper sendTextMessageWithString:@"用户已评价"
  893. toUsername:weakSelf.conversation.conversationId
  894. messageType:NO
  895. requireEncryption:NO
  896. ext:ext];
  897. [weakSelf addChatDataToMessage:message];
  898. }
  899. }
  900. }
  901. [weakSelf.chatToolBar configKeyboardEvent];
  902. };
  903. [[FKWindowViewManager sharedManager] appendFloatView:view];
  904. [[FKWindowViewManager sharedManager] showFloatView:nil];
  905. }
  906. - (void)sendHasReadResponseForMessages:(NSArray*)messages
  907. isRead:(BOOL)isRead
  908. {
  909. NSMutableArray *unreadMessages = [NSMutableArray array];
  910. for (NSInteger i = 0; i < [messages count]; i++)
  911. {
  912. EMMessage *message = messages[i];
  913. BOOL isSend = [self shouldSendHasReadAckForMessage:message
  914. read:isRead];
  915. if (isSend) {
  916. [unreadMessages addObject:message];
  917. }
  918. }
  919. if ([unreadMessages count]) {
  920. for (EMMessage *message in unreadMessages) {
  921. [[EMClient sharedClient].chatManager sendMessageReadAck:message completion:nil];
  922. }
  923. }
  924. }
  925. - (BOOL)shouldSendHasReadAckForMessage:(EMMessage *)message
  926. read:(BOOL)read {
  927. NSString *account = [[EMClient sharedClient] currentUsername];
  928. if (message.chatType != EMChatTypeChat || message.isReadAcked || [account isEqualToString:message.from] || ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)) {
  929. return NO;
  930. }
  931. EMMessageBody *body = message.body;
  932. if (((body.type == EMMessageBodyTypeVideo) ||
  933. (body.type == EMMessageBodyTypeVoice) ||
  934. (body.type == EMMessageBodyTypeImage)) &&
  935. !read) {
  936. return NO;
  937. }
  938. return YES;
  939. }
  940. #pragma mark - private
  941. - (BOOL)canRecord
  942. {
  943. __block BOOL bCanRecord = YES;
  944. if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)
  945. {
  946. dispatch_semaphore_t sema = dispatch_semaphore_create(0);
  947. AVAudioSession *audioSession = [AVAudioSession sharedInstance];
  948. if ([audioSession respondsToSelector:@selector(requestRecordPermission:)]) {
  949. [audioSession performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
  950. if (granted) {
  951. bCanRecord = YES;
  952. } else {
  953. bCanRecord = NO;
  954. }
  955. }];
  956. }
  957. dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
  958. }
  959. return bCanRecord;
  960. }
  961. - (void)stopAudioPlaying
  962. {
  963. //停止音频播放及播放动画
  964. [[EMCDDeviceManager sharedInstance] stopPlaying];
  965. MessageModel *playingModel = [self.messageReadManager stopMessageAudioModel];
  966. NSIndexPath *indexPath = nil;
  967. if (playingModel) {
  968. indexPath = [NSIndexPath indexPathForRow:[self.dataSource indexOfObject:playingModel] inSection:0];
  969. }
  970. if (indexPath) {
  971. dispatch_async(dispatch_get_main_queue(), ^{
  972. [self.tableView beginUpdates];
  973. [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
  974. [self.tableView endUpdates];
  975. });
  976. }
  977. }
  978. - (void)loadMoreMessages {
  979. __weak typeof(self) weakSelf = self;
  980. EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:self.chatter type:EMConversationTypeChat createIfNotExist:YES];
  981. [conversation loadMessagesStartFromId:nil
  982. count:1000
  983. searchDirection:EMMessageSearchDirectionUp
  984. completion:^(NSArray *aMessages, EMError *aError)
  985. {
  986. if ([aMessages count] > 0) {
  987. dispatch_async(dispatch_get_main_queue(), ^{
  988. weakSelf.dataSource.array = [weakSelf sortChatSource:aMessages];
  989. [weakSelf.tableView reloadData];
  990. NSIndexPath *indexPath = [NSIndexPath indexPathForRow:MAX(0, [weakSelf.dataSource count] - 1) inSection:0];
  991. [weakSelf.tableView scrollToRowAtIndexPath:indexPath
  992. atScrollPosition:UITableViewScrollPositionTop animated:NO];
  993. [weakSelf finishLoadingDataWith:0.5];
  994. });
  995. }
  996. }];
  997. }
  998. - (NSArray *)sortChatSource:(NSArray *)array
  999. {
  1000. NSMutableArray *resultArray = [[NSMutableArray alloc] init];
  1001. if (array && [array count] > 0) {
  1002. for (EMMessage *message in array) {
  1003. NSDate *createDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:(NSTimeInterval)message.timestamp];
  1004. NSTimeInterval tempDate = [createDate timeIntervalSinceDate:self.chatTagDate];
  1005. if (tempDate > 120 || tempDate < -120 || (self.chatTagDate == nil)) {
  1006. [resultArray addObject:[FLStringHelper dateForMessage:createDate]];
  1007. self.chatTagDate = createDate;
  1008. }
  1009. MessageModel *model = [MessageModelManager modelWithMessage:message];
  1010. if (model) {
  1011. [resultArray addObject:model];
  1012. }
  1013. }
  1014. }
  1015. return resultArray;
  1016. }
  1017. -(NSMutableArray *)addChatToMessage:(EMMessage *)message
  1018. {
  1019. NSMutableArray *ret = [[NSMutableArray alloc] init];
  1020. NSDate *createDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:(NSTimeInterval)message.timestamp];
  1021. NSTimeInterval tempDate = [createDate timeIntervalSinceDate:self.chatTagDate];
  1022. if (tempDate > 60 || tempDate < -60 || (self.chatTagDate == nil)) {
  1023. [ret addObject:[createDate formattedTime]];
  1024. self.chatTagDate = createDate;
  1025. }
  1026. MessageModel *model = [MessageModelManager modelWithMessage:message];
  1027. if (model) {
  1028. [ret addObject:model];
  1029. }
  1030. return ret;
  1031. }
  1032. -(void)addChatDataToMessage:(EMMessage *)message
  1033. {
  1034. __weak ChatViewController *weakSelf = self;
  1035. dispatch_async(_messageQueue, ^{
  1036. NSArray *messages = [weakSelf addChatToMessage:message];
  1037. NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
  1038. for (int i = 0; i < messages.count; i++) {
  1039. NSIndexPath *indexPath = [NSIndexPath indexPathForRow:weakSelf.dataSource.count+i inSection:0];
  1040. [indexPaths addObject:indexPath];
  1041. }
  1042. dispatch_async(dispatch_get_main_queue(), ^{
  1043. [weakSelf.tableView beginUpdates];
  1044. [weakSelf.dataSource addObjectsFromArray:messages];
  1045. [weakSelf.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
  1046. [weakSelf.tableView endUpdates];
  1047. [weakSelf.tableView reloadData];
  1048. [weakSelf.tableView scrollToRowAtIndexPath:[indexPaths lastObject] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
  1049. });
  1050. });
  1051. }
  1052. - (void)scrollViewToBottom:(BOOL)animated
  1053. {
  1054. if (self.tableView.contentSize.height > self.tableView.frame.size.height)
  1055. {
  1056. CGPoint offset = CGPointMake(0, self.tableView.contentSize.height - self.tableView.frame.size.height);
  1057. [self.tableView setContentOffset:offset animated:YES];
  1058. }
  1059. }
  1060. - (void)showRoomContact:(id)sender
  1061. {
  1062. [self.view endEditing:YES];
  1063. }
  1064. - (void)showMenuViewController:(UIView *)showInView andIndexPath:(NSIndexPath *)indexPath messageType:(EMMessageBodyType)messageType
  1065. {
  1066. if (_menuController == nil) {
  1067. _menuController = [UIMenuController sharedMenuController];
  1068. }
  1069. if (_copyMenuItem == nil) {
  1070. _copyMenuItem = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copyMenuAction:)];
  1071. }
  1072. if (_deleteMenuItem == nil) {
  1073. _deleteMenuItem = [[UIMenuItem alloc] initWithTitle:@"删除" action:@selector(deleteMenuAction:)];
  1074. }
  1075. if (messageType == EMMessageBodyTypeText) {
  1076. [_menuController setMenuItems:@[_copyMenuItem, _deleteMenuItem]];
  1077. }
  1078. else{
  1079. [_menuController setMenuItems:@[_deleteMenuItem]];
  1080. }
  1081. [_menuController setTargetRect:showInView.frame inView:showInView.superview];
  1082. [_menuController setMenuVisible:YES animated:YES];
  1083. }
  1084. - (void)exitGroup
  1085. {
  1086. [self.navigationController popToViewController:self animated:NO];
  1087. [self.navigationController popViewControllerAnimated:YES];
  1088. }
  1089. - (void)applicationDidEnterBackground
  1090. {
  1091. [_chatToolBar cancelTouchRecord];
  1092. [_conversation markAllMessagesAsRead:nil];
  1093. }
  1094. #pragma mark - send message
  1095. - (void)checkAndSendExtMessage {
  1096. if (self.msgExtData) {
  1097. EMMessage *message = [ChatSendHelper sendTextMessageWithString:self.msgExtData[EXT_MSG_ORDER_TITLE]
  1098. toUsername:_conversation.conversationId
  1099. messageType:NO
  1100. requireEncryption:NO
  1101. ext:self.msgExtData];
  1102. [self addChatDataToMessage:message];
  1103. self.msgExtData = nil;
  1104. }
  1105. }
  1106. -(void)sendTextMessage:(NSString *)textMessage
  1107. {
  1108. NSDictionary *extDict = nil;
  1109. if (self.myNickname) {
  1110. extDict = @{SendMSGNicknameKey: self.myNickname};
  1111. }
  1112. EMMessage *message = [ChatSendHelper sendTextMessageWithString:textMessage
  1113. toUsername:_conversation.conversationId
  1114. messageType:_isChatGroup
  1115. requireEncryption:NO
  1116. ext:extDict];
  1117. [self addChatDataToMessage:message];
  1118. }
  1119. -(void)sendImageMessage:(UIImage *)imageMessage
  1120. {
  1121. EMMessage *tempMessage = [ChatSendHelper sendImageMessageWithImage:imageMessage toUsername:_conversation.conversationId isChatGroup:_isChatGroup requireEncryption:NO];
  1122. [self addChatDataToMessage:tempMessage];
  1123. }
  1124. #pragma mark - EMDeviceManagerProximitySensorDelegate
  1125. - (void)proximitySensorChanged:(BOOL)isCloseToUser{
  1126. //如果此时手机靠近面部放在耳朵旁,那么声音将通过听筒输出,并将屏幕变暗(省电啊)
  1127. if (isCloseToUser)//黑屏
  1128. {
  1129. // 使用耳机播放
  1130. // [[EaseMob sharedInstance].deviceManager switchAudioOutputDevice:eAudioOutputDevice_earphone];
  1131. } else {
  1132. // 使用扬声器播放
  1133. // [[EaseMob sharedInstance].deviceManager switchAudioOutputDevice:eAudioOutputDevice_speaker];
  1134. // if (!_isPlayingAudio) {
  1135. // [[[EaseMob sharedInstance] deviceManager] disableProximitySensor];
  1136. // }
  1137. }
  1138. }
  1139. #pragma mark - Photo GalleryScrollView
  1140. - (CGSize)photoSize:(NSString *)photoSizeStr {
  1141. if (!photoSizeStr || photoSizeStr.length == 0) {
  1142. return CGSizeZero;
  1143. }
  1144. NSArray *compoment = [photoSizeStr componentsSeparatedByString:@"x"];
  1145. if (compoment.count >= 2) {
  1146. CGFloat ratio = [compoment[0] floatValue]/[compoment[1] floatValue];
  1147. CGFloat width = (CGRectGetWidth([UIScreen mainScreen].bounds) - 2*8);
  1148. CGFloat height = width/ratio;
  1149. return CGSizeMake(width, height);
  1150. } else {
  1151. return CGSizeZero;
  1152. }
  1153. }
  1154. - (UIScrollView *)galleryScrollView {
  1155. if (!_galleryScrollView)
  1156. {
  1157. _galleryScrollView = [[UIScrollView alloc] initWithFrame:[self galleryContentFrame]];
  1158. _galleryScrollView.backgroundColor = [UIColor blackColor];
  1159. _galleryScrollView.pagingEnabled = YES;
  1160. _galleryScrollView.alpha = 0.0;
  1161. }
  1162. return _galleryScrollView;
  1163. }
  1164. - (CGRect)galleryContentFrame {
  1165. float height = [UIScreen mainScreen].bounds.size.height;
  1166. float width = [UIScreen mainScreen].bounds.size.width;
  1167. return CGRectMake(0, 0, width, height);
  1168. }
  1169. - (void)tapImage:(UIImage *)photo imageView:(UIImageView *)imageView
  1170. {
  1171. if (!photo) {
  1172. return;
  1173. }
  1174. [self.view bringSubviewToFront:self.galleryScrollView];
  1175. self.galleryScrollView.alpha = 1.0;
  1176. [self.navigationController setNavigationBarHidden:YES animated:YES];
  1177. // 添加
  1178. [self galleryAddSubImage:photo imageView:imageView];
  1179. }
  1180. - (void)setGalleryScrollViewCallBack:(GalleryScrollView *)scrollView
  1181. {
  1182. __weak ChatViewController *weakSelf = self;
  1183. scrollView.touchCallBack = ^(GalleryScrollView *scrollView, int index) {
  1184. [weakSelf.navigationController setNavigationBarHidden:NO animated:YES];
  1185. [UIView animateWithDuration:0.5 animations:^{
  1186. [scrollView resetFrame];
  1187. } completion:^(BOOL finished) {
  1188. weakSelf.galleryScrollView.alpha = 0;
  1189. }];
  1190. };
  1191. }
  1192. - (void)setOriginalFrame:(GalleryScrollView *)sender
  1193. {
  1194. [UIView animateWithDuration:0.4 animations:^{
  1195. [sender setAnimationRect];
  1196. }];
  1197. }
  1198. - (void)galleryAddSubImage:(UIImage *)image imageView:(UIImageView *)imageView
  1199. {
  1200. if (!image || !imageView) {
  1201. return;
  1202. }
  1203. for (UIView *view in self.galleryScrollView.subviews) {
  1204. [view removeFromSuperview];
  1205. }
  1206. CGRect convertRect = [imageView.superview convertRect:imageView.frame toView:self.view];
  1207. CGPoint contentOffset = self.galleryScrollView.contentOffset;
  1208. contentOffset.x = [UIScreen mainScreen].bounds.size.width;
  1209. self.galleryScrollView.contentOffset = contentOffset;
  1210. GalleryScrollView *scrollView = [[GalleryScrollView alloc] initWithFrame:(CGRect){contentOffset, self.galleryScrollView.bounds.size}];
  1211. [scrollView setContentWithFrame:convertRect initRect:convertRect];
  1212. [scrollView setImage:image];
  1213. [self.galleryScrollView addSubview:scrollView];
  1214. [self setGalleryScrollViewCallBack:scrollView];
  1215. [self performSelector:@selector(setOriginalFrame:) withObject:scrollView afterDelay:0.1];
  1216. }
  1217. @end