WFCUMessageListViewController.m 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789
  1. //
  2. // MessageListViewController.m
  3. // WFChat UIKit
  4. //
  5. // Created by WF Chat on 2017/8/31.
  6. // Copyright © 2017年 WildFireChat. All rights reserved.
  7. //
  8. #import "WFCUMessageListViewController.h"
  9. #import <AVFoundation/AVFoundation.h>
  10. #import "WFCUImagePreviewViewController.h"
  11. #import "WFCUVoiceRecordView.h"
  12. #import "WFCUImageCell.h"
  13. #import "WFCUTextCell.h"
  14. #import "WFCUVoiceCell.h"
  15. #import "WFCULocationCell.h"
  16. #import "WFCUFileCell.h"
  17. #import "WFCUInformationCell.h"
  18. #import "WFCUCallSummaryCell.h"
  19. #import "WFCUStickerCell.h"
  20. #import "WFCUVideoCell.h"
  21. #import "WFCURecallCell.h"
  22. #import "WFCUBrowserViewController.h"
  23. #import <WFChatClient/WFCChatClient.h>
  24. #import "WFCUProfileTableViewController.h"
  25. #import "WFCUMultiVideoViewController.h"
  26. #import "WFCUChatInputBar.h"
  27. #import "UIView+Toast.h"
  28. #import "WFCUConversationSettingViewController.h"
  29. #import "SDPhotoBrowser.h"
  30. #import "WFCULocationViewController.h"
  31. #import "WFCULocationPoint.h"
  32. #import "WFCUVideoViewController.h"
  33. #import "WFCUContactListViewController.h"
  34. #import "WFCUBrowserViewController.h"
  35. #import "MBProgressHUD.h"
  36. #import "WFCUMediaMessageDownloader.h"
  37. #import "VideoPlayerKit.h"
  38. #import "WFCUForwardViewController.h"
  39. #import <WFChatClient/WFCChatClient.h>
  40. #if WFCU_SUPPORT_VOIP
  41. #import <WFAVEngineKit/WFAVEngineKit.h>
  42. #endif
  43. #import "WFCUConfigManager.h"
  44. #import "WFCUSeletedUserViewController.h"
  45. #import "WFCUReceiptViewController.h"
  46. @interface WFCUMessageListViewController () <UITextFieldDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UINavigationControllerDelegate, WFCUMessageCellDelegate, AVAudioPlayerDelegate, WFCUChatInputBarDelegate, SDPhotoBrowserDelegate, UIGestureRecognizerDelegate>
  47. @property (nonatomic, strong)NSMutableArray<WFCUMessageModel *> *modelList;
  48. @property (nonatomic, strong)NSMutableDictionary<NSNumber *, Class> *cellContentDict;
  49. @property(nonatomic) AVAudioPlayer *player;
  50. @property(nonatomic) NSTimer *playTimer;
  51. @property(nonatomic, assign)long playingMessageId;
  52. @property(nonatomic, assign)BOOL loadingMore;
  53. @property(nonatomic, assign)BOOL hasMoreOld;
  54. @property(nonatomic, strong)WFCCUserInfo *targetUser;
  55. @property(nonatomic, strong)WFCCGroupInfo *targetGroup;
  56. @property(nonatomic, strong)WFCCChannelInfo *targetChannel;
  57. @property(nonatomic, strong)WFCCChatroomInfo *targetChatroom;
  58. @property(nonatomic, strong)WFCUChatInputBar *chatInputBar;
  59. @property(nonatomic, strong)VideoPlayerKit *videoPlayerViewController;
  60. @property (strong, nonatomic) UICollectionView *collectionView;
  61. @property (strong, nonatomic)NSArray<WFCCMessage *> *imageMsgs;
  62. @property (strong, nonatomic)NSString *orignalDraft;
  63. @property (nonatomic, strong)id<UIGestureRecognizerDelegate> scrollBackDelegate;
  64. @property (nonatomic, strong)UIView *backgroundView;
  65. @property (nonatomic, assign)BOOL showAlias;
  66. @property (nonatomic, strong)WFCUMessageCellBase *cell4Menu;
  67. @property (nonatomic, assign)BOOL firstAppear;
  68. @property (nonatomic, assign)BOOL hasNewMessage;
  69. @property (nonatomic, assign)BOOL loadingNew;
  70. @property (nonatomic, strong)UICollectionReusableView *headerView;
  71. @property (nonatomic, strong)UICollectionReusableView *footerView;
  72. @property (nonatomic, strong)UIActivityIndicatorView *headerActivityView;
  73. @property (nonatomic, strong)UIActivityIndicatorView *footerActivityView;
  74. @property (nonatomic, strong)NSTimer *showTypingTimer;
  75. @property (nonatomic, assign)BOOL isShowingKeyboard;
  76. @property (nonatomic, strong)NSMutableDictionary<NSString *, NSNumber *> *deliveryDict;
  77. @property (nonatomic, strong)NSMutableDictionary<NSString *, NSNumber *> *readDict;
  78. @end
  79. @implementation WFCUMessageListViewController
  80. - (void)viewDidLoad {
  81. [super viewDidLoad];
  82. self.cellContentDict = [[NSMutableDictionary alloc] init];
  83. [self initializedSubViews];
  84. self.firstAppear = YES;
  85. self.hasMoreOld = YES;
  86. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResetKeyboard:)];
  87. [self.collectionView addGestureRecognizer:tap];
  88. [self reloadMessageList];
  89. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReceiveMessages:) name:kReceiveMessages object:nil];
  90. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRecallMessages:) name:kRecallMessages object:nil];
  91. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDeleteMessages:) name:kDeleteMessages object:nil];
  92. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMessageDelivered:) name:kMessageDelivered object:nil];
  93. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMessageReaded:) name:kMessageReaded object:nil];
  94. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onSendingMessage:) name:kSendingMessageStatusUpdated object:nil];
  95. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMessageListChanged:) name:kMessageListChanged object:self.conversation];
  96. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMenuHidden:) name:UIMenuControllerDidHideMenuNotification object:nil];
  97. #if WFCU_SUPPORT_VOIP
  98. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onCallStateChanged:) name:kCallStateUpdated object:nil];
  99. #endif
  100. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onSettingUpdated:) name:kSettingUpdated object:nil];
  101. __weak typeof(self) ws = self;
  102. if(self.conversation.type == Single_Type) {
  103. [[NSNotificationCenter defaultCenter] addObserverForName:kUserInfoUpdated object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
  104. if ([ws.conversation.target isEqualToString:note.object]) {
  105. ws.targetUser = note.userInfo[@"userInfo"];
  106. }
  107. }];
  108. self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"nav_chat_single"] style:UIBarButtonItemStyleDone target:self action:@selector(onRightBarBtn:)];
  109. } else if(self.conversation.type == Group_Type) {
  110. [[NSNotificationCenter defaultCenter] addObserverForName:kGroupInfoUpdated object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
  111. if ([ws.conversation.target isEqualToString:note.object]) {
  112. ws.targetGroup = note.userInfo[@"groupInfo"];
  113. }
  114. }];
  115. [[NSNotificationCenter defaultCenter] addObserverForName:kGroupMemberUpdated object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
  116. if ([ws.conversation.target isEqualToString:note.object]) {
  117. ws.targetGroup = ws.targetGroup;
  118. }
  119. }];
  120. self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"nav_chat_group"] style:UIBarButtonItemStyleDone target:self action:@selector(onRightBarBtn:)];
  121. } else if(self.conversation.type == Channel_Type) {
  122. [[NSNotificationCenter defaultCenter] addObserverForName:kChannelInfoUpdated object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
  123. if ([ws.conversation.target isEqualToString:note.object]) {
  124. ws.targetChannel = note.userInfo[@"channelInfo"];
  125. }
  126. }];
  127. self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"nav_chat_channel"] style:UIBarButtonItemStyleDone target:self action:@selector(onRightBarBtn:)];
  128. }
  129. self.chatInputBar = [[WFCUChatInputBar alloc] initWithSuperView:self.backgroundView conversation:self.conversation delegate:self];
  130. self.orignalDraft = [[WFCCIMService sharedWFCIMService] getConversationInfo:self.conversation].draft;
  131. if (self.conversation.type == Chatroom_Type) {
  132. __block MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:ws.view animated:YES];
  133. hud.label.text = WFCString(@"JoinChatroom");
  134. [hud showAnimated:YES];
  135. [[WFCCIMService sharedWFCIMService] joinChatroom:ws.conversation.target success:^{
  136. NSLog(@"join chatroom successs");
  137. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  138. [ws sendChatroomWelcomeMessage];
  139. });
  140. [hud hideAnimated:YES];
  141. } error:^(int error_code) {
  142. NSLog(@"join chatroom error");
  143. hud.mode = MBProgressHUDModeText;
  144. hud.label.text = WFCString(@"JoinChatroomFailure");
  145. // hud.offset = CGPointMake(0.f, MBProgressMaxOffset);
  146. [hud hideAnimated:YES afterDelay:1.f];
  147. hud.completionBlock = ^{
  148. [ws.navigationController popViewControllerAnimated:YES];
  149. };
  150. }];
  151. }
  152. WFCCConversationInfo *info = [[WFCCIMService sharedWFCIMService] getConversationInfo:self.conversation];
  153. self.chatInputBar.draft = info.draft;
  154. if (self.conversation.type == Group_Type) {
  155. dispatch_async(dispatch_get_main_queue(), ^{
  156. NSArray<WFCCGroupMember *> *groupMembers = [[WFCCIMService sharedWFCIMService] getGroupMembers:self.conversation.target forceUpdate:NO];
  157. NSMutableArray *memberIds = [[NSMutableArray alloc] init];
  158. for (WFCCGroupMember *member in groupMembers) {
  159. [memberIds addObject:member.memberId];
  160. }
  161. [[WFCCIMService sharedWFCIMService] getUserInfos:memberIds inGroup:self.conversation.target];
  162. });
  163. }
  164. }
  165. - (void)setLoadingMore:(BOOL)loadingMore {
  166. _loadingMore = loadingMore;
  167. if (_loadingMore) {
  168. [self.headerActivityView startAnimating];
  169. } else {
  170. [self.headerActivityView stopAnimating];
  171. }
  172. }
  173. - (UIActivityIndicatorView *)headerActivityView {
  174. if (!_headerActivityView) {
  175. _headerActivityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
  176. }
  177. return _headerActivityView;
  178. }
  179. - (UIActivityIndicatorView *)footerActivityView {
  180. if (!_footerActivityView) {
  181. _footerActivityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
  182. }
  183. return _footerActivityView;
  184. }
  185. - (void)setLoadingNew:(BOOL)loadingNew {
  186. _loadingNew = loadingNew;
  187. if (loadingNew) {
  188. [self.footerActivityView startAnimating];
  189. } else {
  190. [self.footerActivityView stopAnimating];
  191. }
  192. }
  193. - (void)setHasNewMessage:(BOOL)hasNewMessage {
  194. _hasNewMessage = hasNewMessage;
  195. UICollectionViewFlowLayout *_customFlowLayout = (UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout;
  196. if (hasNewMessage) {
  197. _customFlowLayout.footerReferenceSize = CGSizeMake(320.0f, 20.0f);
  198. } else {
  199. _customFlowLayout.footerReferenceSize = CGSizeZero;
  200. }
  201. }
  202. - (void)loadMoreMessage:(BOOL)isHistory {
  203. __weak typeof(self) weakSelf = self;
  204. if (isHistory) {
  205. if (self.loadingMore) {
  206. return;
  207. }
  208. self.loadingMore = YES;
  209. long lastIndex = 0;
  210. if (weakSelf.modelList.count) {
  211. lastIndex = [weakSelf.modelList firstObject].message.messageId;
  212. }
  213. dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
  214. NSArray *messageList = [[WFCCIMService sharedWFCIMService] getMessages:weakSelf.conversation contentTypes:nil from:lastIndex count:10 withUser:self.privateChatUser];
  215. if (!messageList.count) {
  216. long long lastUid = self.modelList.lastObject.message.messageUid;
  217. for (WFCUMessageModel *model in self.modelList) {
  218. if (model.message.messageUid > 0 && model.message.messageUid < lastUid) {
  219. lastUid = model.message.messageUid;
  220. }
  221. }
  222. [[WFCCIMService sharedWFCIMService] getRemoteMessages:weakSelf.conversation before:lastUid count:10 success:^(NSArray<WFCCMessage *> *messages) {
  223. NSMutableArray *reversedMsgs = [[NSMutableArray alloc] init];
  224. for (WFCCMessage *msg in messages) {
  225. [reversedMsgs insertObject:msg atIndex:0];
  226. }
  227. dispatch_async(dispatch_get_main_queue(), ^{
  228. if (!reversedMsgs.count) {
  229. weakSelf.hasMoreOld = NO;
  230. } else {
  231. [weakSelf appendMessages:reversedMsgs newMessage:NO highlightId:0 forceButtom:NO];
  232. }
  233. weakSelf.loadingMore = NO;
  234. });
  235. } error:^(int error_code) {
  236. dispatch_async(dispatch_get_main_queue(), ^{
  237. weakSelf.hasMoreOld = NO;
  238. weakSelf.loadingMore = NO;
  239. });
  240. }];
  241. } else {
  242. [NSThread sleepForTimeInterval:0.5];
  243. dispatch_async(dispatch_get_main_queue(), ^{
  244. [weakSelf appendMessages:messageList newMessage:NO highlightId:0 forceButtom:NO];
  245. weakSelf.loadingMore = NO;
  246. });
  247. }
  248. });
  249. } else {
  250. if (weakSelf.loadingNew || !weakSelf.hasNewMessage) {
  251. return;
  252. }
  253. weakSelf.loadingNew = YES;
  254. long lastIndex = 0;
  255. if (self.modelList.count) {
  256. lastIndex = [self.modelList lastObject].message.messageId;
  257. }
  258. dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
  259. NSArray *messageList = [[WFCCIMService sharedWFCIMService] getMessages:self.conversation contentTypes:nil from:lastIndex count:-10 withUser:self.privateChatUser];
  260. if (!messageList.count || messageList.count < 10) {
  261. self.hasNewMessage = NO;
  262. }
  263. NSMutableArray *mutableMessages = [messageList mutableCopy];
  264. for (int i = 0; i < mutableMessages.count/2; i++) {
  265. int j = (int)mutableMessages.count - 1 - i;
  266. WFCCMessage *msg = [mutableMessages objectAtIndex:i];
  267. [mutableMessages insertObject:[mutableMessages objectAtIndex:j] atIndex:i];
  268. [mutableMessages removeObjectAtIndex:i+1];
  269. [mutableMessages insertObject:msg atIndex:j];
  270. [mutableMessages removeObjectAtIndex:j+1];
  271. }
  272. [NSThread sleepForTimeInterval:3];
  273. dispatch_async(dispatch_get_main_queue(), ^{
  274. [weakSelf appendMessages:mutableMessages newMessage:YES highlightId:0 forceButtom:NO];
  275. weakSelf.loadingNew = NO;
  276. });
  277. });
  278. }
  279. }
  280. - (void)sendChatroomWelcomeMessage {
  281. WFCCTipNotificationContent *tip = [[WFCCTipNotificationContent alloc] init];
  282. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:[WFCCNetworkService sharedInstance].userId refresh:NO];
  283. tip.tip = [NSString stringWithFormat:WFCString(@"WelcomeJoinChatroomHint"), userInfo.displayName];
  284. [self sendMessage:tip];
  285. }
  286. - (void)sendChatroomLeaveMessage {
  287. __block WFCCConversation *strongConv = self.conversation;
  288. dispatch_async(dispatch_get_main_queue(), ^{
  289. WFCCTipNotificationContent *tip = [[WFCCTipNotificationContent alloc] init];
  290. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:[WFCCNetworkService sharedInstance].userId refresh:NO];
  291. tip.tip = [NSString stringWithFormat:WFCString(@"LeaveChatroomHint"), userInfo.displayName];
  292. [[WFCCIMService sharedWFCIMService] send:strongConv content:tip success:^(long long messageUid, long long timestamp) {
  293. [[WFCCIMService sharedWFCIMService] quitChatroom:strongConv.target success:nil error:nil];
  294. } error:^(int error_code) {
  295. }];
  296. });
  297. }
  298. - (void)onLeftBtnPressed:(id)sender {
  299. [self.navigationController popViewControllerAnimated:YES];
  300. }
  301. - (void)didMoveToParentViewController:(UIViewController*)parent
  302. {
  303. [super didMoveToParentViewController:parent];
  304. if(!parent){
  305. [self leftMessageVC];
  306. }
  307. }
  308. - (void)leftMessageVC {
  309. if (self.conversation.type == Chatroom_Type) {
  310. [self sendChatroomLeaveMessage];
  311. }
  312. }
  313. - (void)onRightBarBtn:(UIBarButtonItem *)sender {
  314. WFCUConversationSettingViewController *gvc = [[WFCUConversationSettingViewController alloc] init];
  315. gvc.conversation = self.conversation;
  316. [self.navigationController pushViewController:gvc animated:YES];
  317. }
  318. - (void)setTargetUser:(WFCCUserInfo *)targetUser {
  319. _targetUser = targetUser;
  320. if(targetUser.friendAlias.length) {
  321. self.title = targetUser.friendAlias;
  322. } else if(targetUser.displayName.length == 0) {
  323. self.title = [NSString stringWithFormat:@"%@<%@>", WFCString(@"User"), self.conversation.target];
  324. } else {
  325. self.title = targetUser.displayName;
  326. }
  327. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
  328. self.navigationItem.backBarButtonItem.title = self.title;
  329. }
  330. - (void)setTargetGroup:(WFCCGroupInfo *)targetGroup {
  331. _targetGroup = targetGroup;
  332. if(targetGroup.name.length == 0) {
  333. self.title = WFCString(@"GroupChat");
  334. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
  335. self.navigationItem.backBarButtonItem.title = WFCString(@"Message");
  336. } else {
  337. self.title = [NSString stringWithFormat:@"%@(%d)", targetGroup.name, (int)targetGroup.memberCount];
  338. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
  339. self.navigationItem.backBarButtonItem.title = targetGroup.name;
  340. }
  341. ChatInputBarStatus defaultStatus = ChatInputBarDefaultStatus;
  342. WFCCGroupMember *member = [[WFCCIMService sharedWFCIMService] getGroupMember:targetGroup.target memberId:[WFCCNetworkService sharedInstance].userId];
  343. if (targetGroup.mute || member.type == Member_Type_Muted) {
  344. if ([targetGroup.owner isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  345. self.chatInputBar.inputBarStatus = defaultStatus;
  346. } else {
  347. WFCCGroupMember *gm = [[WFCCIMService sharedWFCIMService] getGroupMember:targetGroup.target memberId:[WFCCNetworkService sharedInstance].userId];
  348. if (gm.type == Member_Type_Manager) {
  349. self.chatInputBar.inputBarStatus = defaultStatus;
  350. } else {
  351. self.chatInputBar.inputBarStatus = ChatInputBarMuteStatus;
  352. }
  353. }
  354. } else {
  355. self.chatInputBar.inputBarStatus = defaultStatus;
  356. }
  357. }
  358. - (void)setTargetChannel:(WFCCChannelInfo *)targetChannel {
  359. _targetChannel = targetChannel;
  360. if(targetChannel.name.length == 0) {
  361. self.title = WFCString(@"Channel");
  362. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
  363. self.navigationItem.backBarButtonItem.title = WFCString(@"Message");
  364. } else {
  365. self.title = targetChannel.name;
  366. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
  367. self.navigationItem.backBarButtonItem.title = targetChannel.name;
  368. }
  369. }
  370. - (void)setTargetChatroom:(WFCCChatroomInfo *)targetChatroom {
  371. _targetChatroom = targetChatroom;
  372. if(targetChatroom.title.length == 0) {
  373. self.title = WFCString(@"Chatroom");
  374. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
  375. self.navigationItem.backBarButtonItem.title = WFCString(@"Message");
  376. } else {
  377. self.title = targetChatroom.title;
  378. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
  379. self.navigationItem.backBarButtonItem.title = targetChatroom.title;
  380. }
  381. }
  382. - (void)setShowAlias:(BOOL)showAlias {
  383. _showAlias = showAlias;
  384. if (self.modelList) {
  385. for (WFCUMessageModel *model in self.modelList) {
  386. if (showAlias && model.message.direction == MessageDirection_Receive) {
  387. model.showNameLabel = YES;
  388. } else {
  389. model.showNameLabel = NO;
  390. }
  391. }
  392. }
  393. }
  394. - (void)scrollToBottom:(BOOL)animated {
  395. NSUInteger rowCount = [self.collectionView numberOfItemsInSection:0];
  396. if (rowCount == 0) {
  397. return;
  398. }
  399. NSUInteger finalRow = rowCount - 1;
  400. for (int i = 0; i < self.modelList.count; i++) {
  401. if ([self.modelList objectAtIndex:i].highlighted) {
  402. finalRow = i;
  403. break;
  404. }
  405. }
  406. NSIndexPath *finalIndexPath = [NSIndexPath indexPathForItem:finalRow inSection:0];
  407. [self.collectionView scrollToItemAtIndexPath:finalIndexPath
  408. atScrollPosition:UICollectionViewScrollPositionBottom
  409. animated:animated];
  410. }
  411. - (void)initializedSubViews {
  412. UICollectionViewFlowLayout *_customFlowLayout = [[UICollectionViewFlowLayout alloc] init];
  413. _customFlowLayout.minimumLineSpacing = 0.0f;
  414. _customFlowLayout.sectionInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
  415. _customFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
  416. _customFlowLayout.headerReferenceSize = CGSizeMake(320.0f, 20.0f);
  417. UIEdgeInsets insets = UIEdgeInsetsZero;
  418. if (@available(iOS 11.0, *)) {
  419. insets = self.view.safeAreaInsets;
  420. }
  421. CGRect frame = self.view.bounds;
  422. frame.origin.y += kStatusBarAndNavigationBarHeight;
  423. frame.size.height -= (kTabbarSafeBottomMargin + kStatusBarAndNavigationBarHeight);
  424. self.backgroundView = [[UIView alloc] initWithFrame:frame];
  425. [self.view addSubview:self.backgroundView];
  426. self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.backgroundView.bounds.size.width, self.backgroundView.bounds.size.height - CHAT_INPUT_BAR_HEIGHT) collectionViewLayout:_customFlowLayout];
  427. [self.backgroundView addSubview:self.collectionView];
  428. self.backgroundView.backgroundColor = [UIColor whiteColor];
  429. self.collectionView.backgroundColor = [WFCUConfigManager globalManager].backgroudColor;
  430. self.collectionView.showsHorizontalScrollIndicator = NO;
  431. self.collectionView.showsVerticalScrollIndicator = NO;
  432. self.collectionView.alwaysBounceVertical = YES;
  433. self.view.backgroundColor = self.collectionView.backgroundColor;
  434. [self registerCell:[WFCUTextCell class] forContent:[WFCCTextMessageContent class]];
  435. [self registerCell:[WFCUTextCell class] forContent:[WFCCPTextMessageContent class]];
  436. [self registerCell:[WFCUImageCell class] forContent:[WFCCImageMessageContent class]];
  437. [self registerCell:[WFCUVoiceCell class] forContent:[WFCCSoundMessageContent class]];
  438. [self registerCell:[WFCUVideoCell class] forContent:[WFCCVideoMessageContent class]];
  439. [self registerCell:[WFCULocationCell class] forContent:[WFCCLocationMessageContent class]];
  440. [self registerCell:[WFCUFileCell class] forContent:[WFCCFileMessageContent class]];
  441. [self registerCell:[WFCUStickerCell class] forContent:[WFCCStickerMessageContent class]];
  442. [self registerCell:[WFCUInformationCell class] forContent:[WFCCCreateGroupNotificationContent class]];
  443. [self registerCell:[WFCUInformationCell class] forContent:[WFCCAddGroupeMemberNotificationContent class]];
  444. [self registerCell:[WFCUInformationCell class] forContent:[WFCCKickoffGroupMemberNotificaionContent class]];
  445. [self registerCell:[WFCUInformationCell class] forContent:[WFCCQuitGroupNotificationContent class]];
  446. [self registerCell:[WFCUInformationCell class] forContent:[WFCCDismissGroupNotificationContent class]];
  447. [self registerCell:[WFCUInformationCell class] forContent:[WFCCTransferGroupOwnerNotificationContent class]];
  448. [self registerCell:[WFCUInformationCell class] forContent:[WFCCModifyGroupAliasNotificationContent class]];
  449. [self registerCell:[WFCUInformationCell class] forContent:[WFCCChangeGroupNameNotificationContent class]];
  450. [self registerCell:[WFCUInformationCell class] forContent:[WFCCChangeGroupPortraitNotificationContent class]];
  451. [self registerCell:[WFCUInformationCell class] forContent:[WFCCFriendAddedMessageContent class]];
  452. [self registerCell:[WFCUInformationCell class] forContent:[WFCCFriendGreetingMessageContent class]];
  453. [self registerCell:[WFCUCallSummaryCell class] forContent:[WFCCCallStartMessageContent class]];
  454. [self registerCell:[WFCUInformationCell class] forContent:[WFCCTipNotificationContent class]];
  455. [self registerCell:[WFCUInformationCell class] forContent:[WFCCUnknownMessageContent class]];
  456. [self registerCell:[WFCURecallCell class] forContent:[WFCCRecallMessageContent class]];
  457. [self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"];
  458. [self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView"];
  459. self.collectionView.dataSource = self;
  460. self.collectionView.delegate = self;
  461. }
  462. - (void)registerCell:(Class)cellCls forContent:(Class)msgContentCls {
  463. [self.collectionView registerClass:cellCls
  464. forCellWithReuseIdentifier:[NSString stringWithFormat:@"%d", [msgContentCls getContentType]]];
  465. [self.cellContentDict setObject:cellCls forKey:@([msgContentCls getContentType])];
  466. }
  467. - (void)showTyping:(WFCCTypingType)typingType {
  468. if (self.showTypingTimer) {
  469. [self.showTypingTimer invalidate];
  470. }
  471. self.showTypingTimer = [NSTimer timerWithTimeInterval:TYPING_INTERVAL/2 target:self selector:@selector(stopShowTyping) userInfo:nil repeats:NO];
  472. [[NSRunLoop mainRunLoop] addTimer:self.showTypingTimer forMode:NSDefaultRunLoopMode];
  473. if (typingType == Typing_TEXT) {
  474. self.title = WFCString(@"TypingHint");
  475. } else if(typingType == Typing_VOICE) {
  476. self.title = WFCString(@"RecordingHint");
  477. } else if(typingType == Typing_CAMERA) {
  478. self.title = WFCString(@"PhotographingHint");
  479. } else if(typingType == Typing_LOCATION) {
  480. self.title = WFCString(@"GetLocationHint");
  481. } else if(typingType == Typing_FILE) {
  482. self.title = WFCString(@"SelectingFileHint");
  483. }
  484. }
  485. - (void)stopShowTyping {
  486. if(self.showTypingTimer != nil) {
  487. [self.showTypingTimer invalidate];
  488. self.showTypingTimer = nil;
  489. if (self.conversation.type == Single_Type) {
  490. self.targetUser = self.targetUser;
  491. } else if(self.conversation.type == Group_Type) {
  492. self.targetGroup = self.targetGroup;
  493. } else if(self.conversation.type == Channel_Type) {
  494. self.targetChannel = self.targetChannel;
  495. } else if(self.conversation.type == Group_Type) {
  496. self.targetGroup = self.targetGroup;
  497. }
  498. }
  499. }
  500. - (void)onResetKeyboard:(id)sender {
  501. [self.chatInputBar resetInputBarStatue];
  502. }
  503. - (void)didReceiveMemoryWarning {
  504. [super didReceiveMemoryWarning];
  505. }
  506. - (void)viewWillAppear:(BOOL)animated {
  507. [super viewWillAppear:animated];
  508. [self.chatInputBar willAppear];
  509. if(self.conversation.type == Single_Type) {
  510. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.conversation.target refresh:YES];
  511. self.targetUser = userInfo;
  512. } else if(self.conversation.type == Group_Type) {
  513. WFCCGroupInfo *groupInfo = [[WFCCIMService sharedWFCIMService] getGroupInfo:self.conversation.target refresh:YES];
  514. self.targetGroup = groupInfo;
  515. } else if (self.conversation.type == Channel_Type) {
  516. WFCCChannelInfo *channelInfo = [[WFCCIMService sharedWFCIMService] getChannelInfo:self.conversation.target refresh:YES];
  517. self.targetChannel = channelInfo;
  518. } else if(self.conversation.type == Chatroom_Type) {
  519. __weak typeof(self)ws = self;
  520. [[WFCCIMService sharedWFCIMService] getChatroomInfo:self.conversation.target upateDt:ws.targetChatroom.updateDt success:^(WFCCChatroomInfo *chatroomInfo) {
  521. ws.targetChatroom = chatroomInfo;
  522. } error:^(int error_code) {
  523. }];
  524. }
  525. self.tabBarController.tabBar.hidden = YES;
  526. [self.collectionView reloadData];
  527. if (self.navigationController.viewControllers.count > 1) { // 记录系统返回手势的代理
  528. _scrollBackDelegate = self.navigationController.interactivePopGestureRecognizer.delegate; // 设置系统返回手势的代理为当前控制器
  529. self.navigationController.interactivePopGestureRecognizer.delegate = self;
  530. }
  531. if (self.conversation.type == Group_Type) {
  532. self.showAlias = ![[WFCCIMService sharedWFCIMService] isHiddenGroupMemberName:self.targetGroup.target];
  533. }
  534. if (self.firstAppear) {
  535. self.firstAppear = NO;
  536. [self scrollToBottom:NO];
  537. }
  538. }
  539. - (void)viewDidAppear:(BOOL)animated {
  540. [super viewDidAppear:animated];
  541. }
  542. - (void)viewWillDisappear:(BOOL)animated {
  543. [super viewWillDisappear:animated];
  544. NSString *newDraft = self.chatInputBar.draft;
  545. if (![self.orignalDraft isEqualToString:newDraft]) {
  546. self.orignalDraft = newDraft;
  547. [[WFCCIMService sharedWFCIMService] setConversation:self.conversation draft:newDraft];
  548. }
  549. // 设置系统返回手势的代理为我们刚进入控制器的时候记录的系统的返回手势代理
  550. self.navigationController.interactivePopGestureRecognizer.delegate = _scrollBackDelegate;
  551. [self.chatInputBar resetInputBarStatue];
  552. }
  553. - (void)sendMessage:(WFCCMessageContent *)content {
  554. //发送消息时,client会发出"kSendingMessageStatusUpdated“的通知,消息界面收到通知后加入到列表中。
  555. __weak typeof(self) ws = self;
  556. NSMutableArray *tousers = nil;
  557. if (self.privateChatUser) {
  558. tousers = [[NSMutableArray alloc] init];
  559. [tousers addObject:self.privateChatUser];
  560. }
  561. [[WFCCIMService sharedWFCIMService] send:self.conversation content:content toUsers:tousers expireDuration:0 success:^(long long messageUid, long long timestamp) {
  562. NSLog(@"send message success");
  563. if ([content isKindOfClass:[WFCCStickerMessageContent class]]) {
  564. [ws saveStickerRemoteUrl:(WFCCStickerMessageContent *)content];
  565. }
  566. } error:^(int error_code) {
  567. NSLog(@"send message fail(%d)", error_code);
  568. }];
  569. }
  570. - (void)onReceiveMessages:(NSNotification *)notification {
  571. NSArray<WFCCMessage *> *messages = notification.object;
  572. [self appendMessages:messages newMessage:YES highlightId:0 forceButtom:NO];
  573. [[WFCCIMService sharedWFCIMService] clearUnreadStatus:self.conversation];
  574. }
  575. - (void)onRecallMessages:(NSNotification *)notification {
  576. long long messageUid = [notification.object longLongValue];
  577. WFCCMessage *msg = [[WFCCIMService sharedWFCIMService] getMessageByUid:messageUid];
  578. if (msg != nil) {
  579. for (int i = 0; i < self.modelList.count; i++) {
  580. WFCUMessageModel *model = [self.modelList objectAtIndex:i];
  581. if (model.message.messageUid == messageUid) {
  582. model.message = msg;
  583. [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  584. break;
  585. }
  586. }
  587. }
  588. }
  589. - (void)onDeleteMessages:(NSNotification *)notification {
  590. long long messageUid = [notification.object longLongValue];
  591. for (int i = 0; i < self.modelList.count; i++) {
  592. WFCUMessageModel *model = [self.modelList objectAtIndex:i];
  593. if (model.message.messageUid == messageUid) {
  594. [self.modelList removeObject:model];
  595. [self.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  596. break;
  597. }
  598. }
  599. }
  600. - (void)onMessageDelivered:(NSNotification *)notification {
  601. if (self.conversation.type != Single_Type && self.conversation.type != Group_Type) {
  602. return;
  603. }
  604. NSArray<WFCCGroupMember *> *members = nil;
  605. if (self.conversation.type == Group_Type) {
  606. members = [[WFCCIMService sharedWFCIMService] getGroupMembers:self.conversation.target forceUpdate:NO];
  607. }
  608. NSArray<WFCCDeliveryReport *> *delivereds = notification.object;
  609. __block BOOL refresh = NO;
  610. [delivereds enumerateObjectsUsingBlock:^(WFCCDeliveryReport * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  611. if (self.conversation.type == Single_Type) {
  612. if ([self.conversation.target isEqualToString:obj.userId]) {
  613. *stop = YES;
  614. refresh = YES;
  615. }
  616. }
  617. if (self.conversation.type == Group_Type) {
  618. for (WFCCGroupMember *member in members) {
  619. if ([member.memberId isEqualToString:obj.userId]) {
  620. *stop = YES;
  621. refresh = YES;
  622. }
  623. }
  624. }
  625. }];
  626. if (refresh) {
  627. self.deliveryDict = [[WFCCIMService sharedWFCIMService] getMessageDelivery:self.conversation];
  628. WFCCGroupInfo *groupInfo = nil;
  629. for (int i = 0; i < self.modelList.count; i++) {
  630. WFCUMessageModel *model = self.modelList[i];
  631. model.deliveryDict = self.deliveryDict;
  632. if (model.message.direction == MessageDirection_Receive || model.deliveryRate == 1.f) {
  633. continue;
  634. }
  635. if (self.conversation.type == Single_Type) {
  636. if (model.message.serverTime <= [[model.deliveryDict objectForKey:model.message.conversation.target] longLongValue]) {
  637. float rate = 1.f;
  638. if (rate != model.deliveryRate) {
  639. model.deliveryRate = rate;
  640. [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  641. }
  642. }
  643. } else { //group
  644. long long messageTS = model.message.serverTime;
  645. __block int delieveriedCount = 0;
  646. [model.deliveryDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSNumber * _Nonnull obj, BOOL * _Nonnull stop) {
  647. if ([obj longLongValue] >= messageTS) {
  648. delieveriedCount++;
  649. }
  650. }];
  651. if (!groupInfo) {
  652. groupInfo = [[WFCCIMService sharedWFCIMService] getGroupInfo:model.message.conversation.target refresh:NO];
  653. }
  654. float rate = (float)delieveriedCount/(groupInfo.memberCount - 1);
  655. if (rate != model.deliveryRate) {
  656. model.deliveryRate = rate;
  657. [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  658. }
  659. }
  660. }
  661. }
  662. }
  663. - (void)onMessageReaded:(NSNotification *)notification {
  664. if (self.conversation.type != Single_Type && self.conversation.type != Group_Type) {
  665. return;
  666. }
  667. NSArray<WFCCReadReport *> *readeds = notification.object;
  668. __block BOOL refresh = NO;
  669. [readeds enumerateObjectsUsingBlock:^(WFCCReadReport * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  670. if ([obj.conversation isEqual:self.conversation]) {
  671. *stop = YES;
  672. refresh = YES;
  673. }
  674. }];
  675. if (refresh) {
  676. self.readDict = [[WFCCIMService sharedWFCIMService] getConversationRead:self.conversation];
  677. WFCCGroupInfo *groupInfo = nil;
  678. for (int i = 0; i < self.modelList.count; i++) {
  679. WFCUMessageModel *model = self.modelList[i];
  680. model.readDict = self.readDict;
  681. if (model.message.direction == MessageDirection_Receive || model.readRate == 1.f) {
  682. continue;
  683. }
  684. if (self.conversation.type == Single_Type) {
  685. if (model.message.serverTime <= [[model.readDict objectForKey:model.message.conversation.target] longLongValue]) {
  686. float rate = 1.f;
  687. if (rate != model.readRate) {
  688. model.readRate = rate;
  689. [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  690. }
  691. }
  692. } else { //group
  693. long long messageTS = model.message.serverTime;
  694. __block int delieveriedCount = 0;
  695. [model.readDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSNumber * _Nonnull obj, BOOL * _Nonnull stop) {
  696. if ([obj longLongValue] >= messageTS) {
  697. delieveriedCount++;
  698. }
  699. }];
  700. if (!groupInfo) {
  701. groupInfo = [[WFCCIMService sharedWFCIMService] getGroupInfo:model.message.conversation.target refresh:NO];
  702. }
  703. float rate = (float)delieveriedCount/(groupInfo.memberCount - 1);
  704. if (rate != model.readRate) {
  705. model.readRate = rate;
  706. [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  707. }
  708. }
  709. }
  710. }
  711. }
  712. #if WFCU_SUPPORT_VOIP
  713. - (void)onCallStateChanged:(NSNotification *)notification {
  714. long long messageUid = [[notification.userInfo objectForKey:@"messageUid"] longLongValue];
  715. WFCCMessage *msg = [[WFCCIMService sharedWFCIMService] getMessageByUid:messageUid];
  716. for (int i = 0; i < self.modelList.count; i++) {
  717. WFCUMessageModel *model = [self.modelList objectAtIndex:i];
  718. if (model.message.messageUid == messageUid) {
  719. model.message.content = msg.content;
  720. [self.collectionView reloadData];
  721. break;
  722. }
  723. }
  724. if ([[notification.userInfo objectForKey:@"state"] intValue] == kWFAVEngineStateIncomming) {
  725. if ([[[UIDevice currentDevice] systemVersion] rangeOfString:@"10."].location == 0) {
  726. [self.chatInputBar resetInputBarStatue];
  727. }
  728. }
  729. }
  730. #endif
  731. - (void)onSendingMessage:(NSNotification *)notification {
  732. WFCCMessage *message = [notification.userInfo objectForKey:@"message"];
  733. WFCCMessageStatus status = [[notification.userInfo objectForKey:@"status"] integerValue];
  734. if (status == Message_Status_Sending) {
  735. if ([message.conversation isEqual:self.conversation]) {
  736. [self appendMessages:@[message] newMessage:YES highlightId:0 forceButtom:YES];
  737. }
  738. }
  739. }
  740. - (void)onMessageListChanged:(NSNotification *)notification {
  741. [self reloadMessageList];
  742. }
  743. - (void)onSettingUpdated:(NSNotification *)notification {
  744. [self reloadMessageList];
  745. }
  746. - (void)reloadMessageList {
  747. self.deliveryDict = [[WFCCIMService sharedWFCIMService] getMessageDelivery:self.conversation];
  748. self.readDict = [[WFCCIMService sharedWFCIMService] getConversationRead:self.conversation];
  749. NSArray *messageList;
  750. if (self.highlightMessageId > 0) {
  751. NSArray *messageListOld = [[WFCCIMService sharedWFCIMService] getMessages:self.conversation contentTypes:nil from:self.highlightMessageId+1 count:15 withUser:self.privateChatUser];
  752. NSArray *messageListNew = [[WFCCIMService sharedWFCIMService] getMessages:self.conversation contentTypes:nil from:self.highlightMessageId count:-15 withUser:self.privateChatUser];
  753. NSMutableArray *list = [[NSMutableArray alloc] init];
  754. [list addObjectsFromArray:messageListNew];
  755. [list addObjectsFromArray:messageListOld];
  756. messageList = [list copy];
  757. [[WFCCIMService sharedWFCIMService] clearUnreadStatus:self.conversation];
  758. if (messageListNew.count == 15) {
  759. self.hasNewMessage = YES;
  760. }
  761. } else {
  762. int count = (int)self.modelList.count;
  763. if (count > 50) {
  764. count = 50;
  765. } else if(count == 0) {
  766. count = 15;
  767. }
  768. messageList = [[WFCCIMService sharedWFCIMService] getMessages:self.conversation contentTypes:nil from:0 count:count withUser:self.privateChatUser];
  769. [[WFCCIMService sharedWFCIMService] clearUnreadStatus:self.conversation];
  770. }
  771. self.modelList = [[NSMutableArray alloc] init];
  772. [self appendMessages:messageList newMessage:NO highlightId:self.highlightMessageId forceButtom:NO];
  773. self.highlightMessageId = 0;
  774. }
  775. - (void)appendMessages:(NSArray<WFCCMessage *> *)messages newMessage:(BOOL)newMessage highlightId:(long)highlightId forceButtom:(BOOL)forceButtom {
  776. if (messages.count == 0) {
  777. return;
  778. }
  779. int count = 0;
  780. for (int i = 0; i < messages.count; i++) {
  781. WFCCMessage *message = [messages objectAtIndex:i];
  782. if (![message.conversation isEqual:self.conversation]) {
  783. continue;
  784. }
  785. if ([message.content isKindOfClass:[WFCCTypingMessageContent class]] && message.direction == MessageDirection_Receive) {
  786. double now = [[NSDate date] timeIntervalSince1970];
  787. if (now - message.serverTime + [WFCCNetworkService sharedInstance].serverDeltaTime < TYPING_INTERVAL) {
  788. WFCCTypingMessageContent *content = (WFCCTypingMessageContent *)message.content;
  789. [self showTyping:content.type];
  790. }
  791. continue;
  792. }
  793. if (!([message.content.class getContentFlags] & 0x1)) {
  794. continue;
  795. }
  796. BOOL duplcated = NO;
  797. for (WFCUMessageModel *model in self.modelList) {
  798. if (model.message.messageUid !=0 && model.message.messageUid == message.messageUid) {
  799. duplcated = YES;
  800. break;
  801. }
  802. }
  803. if (duplcated) {
  804. continue;
  805. }
  806. count++;
  807. if (newMessage) {
  808. BOOL showTime = YES;
  809. if (self.modelList.count > 0 && (message.serverTime - (self.modelList[self.modelList.count - 1]).message.serverTime < 60 * 1000)) {
  810. showTime = NO;
  811. }
  812. WFCUMessageModel *model = [WFCUMessageModel modelOf:message showName:message.direction == MessageDirection_Receive && self.showAlias showTime:showTime];
  813. if (highlightId > 0 && message.messageId == highlightId) {
  814. model.highlighted = YES;
  815. }
  816. model.deliveryDict = self.deliveryDict;
  817. model.readDict = self.readDict;
  818. [self.modelList addObject:model];
  819. if (messages.count == 1) {
  820. [self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:self.modelList.count - 1 inSection:0]]];
  821. }
  822. } else {
  823. if (self.modelList.count > 0 && (self.modelList[0].message.serverTime - message.serverTime < 60 * 1000) && i != 0) {
  824. self.modelList[0].showTimeLabel = NO;
  825. }
  826. WFCUMessageModel *model = [WFCUMessageModel modelOf:message showName:message.direction == MessageDirection_Receive&&self.showAlias showTime:YES];
  827. if (highlightId > 0 && message.messageId == highlightId) {
  828. model.highlighted = YES;
  829. }
  830. model.deliveryDict = self.deliveryDict;
  831. model.readDict = self.readDict;
  832. [self.modelList insertObject:model atIndex:0];
  833. }
  834. }
  835. if (count > 0) {
  836. [self stopShowTyping];
  837. }
  838. BOOL isAtButtom = NO;
  839. if (newMessage) {
  840. if (@available(iOS 12.0, *)) {
  841. CGPoint offset = self.collectionView.contentOffset;
  842. CGSize size = self.collectionView.contentSize;
  843. CGSize visiableSize = CGSizeZero;
  844. visiableSize = self.collectionView.visibleSize;
  845. isAtButtom = (offset.y + visiableSize.height - size.height) > -100;
  846. } else {
  847. isAtButtom = YES;
  848. }
  849. }
  850. if (newMessage && messages.count == 1) {
  851. NSLog(@"alread reload the message");
  852. } else {
  853. [self.collectionView reloadData];
  854. }
  855. if (newMessage || self.modelList.count == messages.count) {
  856. if(isAtButtom) {
  857. forceButtom = true;
  858. }
  859. } else {
  860. CGFloat offset = 0;
  861. for (int i = 0; i < count; i++) {
  862. CGSize size = [self collectionView:self.collectionView layout:self.collectionView.collectionViewLayout sizeForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
  863. offset += size.height;
  864. }
  865. self.collectionView.contentOffset = CGPointMake(0, offset);
  866. [UIView animateWithDuration:0.2 animations:^{
  867. self.collectionView.contentOffset = CGPointMake(0, offset - 20);
  868. }];
  869. }
  870. if (forceButtom) {
  871. [self scrollToBottom:YES];
  872. }
  873. }
  874. - (WFCUMessageModel *)modelOfMessage:(long)messageId {
  875. if (messageId <= 0) {
  876. return nil;
  877. }
  878. for (WFCUMessageModel *model in self.modelList) {
  879. if (model.message.messageId == messageId) {
  880. return model;
  881. }
  882. }
  883. return nil;
  884. }
  885. - (void)stopPlayer {
  886. if (self.player && [self.player isPlaying]) {
  887. [self.player stop];
  888. if ([self.playTimer isValid]) {
  889. [self.playTimer invalidate];
  890. self.playTimer = nil;
  891. }
  892. }
  893. [self modelOfMessage:self.playingMessageId].voicePlaying = NO;
  894. self.playingMessageId = 0;
  895. [[NSNotificationCenter defaultCenter] postNotificationName:kVoiceMessagePlayStoped object:nil];
  896. }
  897. -(void)prepardToPlay:(WFCUMessageModel *)model {
  898. if (self.playingMessageId == model.message.messageId) {
  899. [self stopPlayer];
  900. } else {
  901. [self stopPlayer];
  902. self.playingMessageId = model.message.messageId;
  903. WFCCSoundMessageContent *soundContent = (WFCCSoundMessageContent *)model.message.content;
  904. if (soundContent.localPath.length == 0) {
  905. model.mediaDownloading = YES;
  906. __weak typeof(self) weakSelf = self;
  907. [[WFCUMediaMessageDownloader sharedDownloader] tryDownload:model.message success:^(long long messageUid, NSString *localPath) {
  908. model.mediaDownloading = NO;
  909. [weakSelf startPlay:model];
  910. } error:^(long long messageUid, int error_code) {
  911. model.mediaDownloading = NO;
  912. }];
  913. } else {
  914. [self startPlay:model];
  915. }
  916. }
  917. }
  918. -(void)startPlay:(WFCUMessageModel *)model {
  919. if ([model.message.content isKindOfClass:[WFCCSoundMessageContent class]]) {
  920. // Setup audio session
  921. AVAudioSession *session = [AVAudioSession sharedInstance];
  922. [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
  923. [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
  924. error:nil];
  925. WFCCSoundMessageContent *snc = (WFCCSoundMessageContent *)model.message.content;
  926. NSError *error = nil;
  927. self.player = [[AVAudioPlayer alloc] initWithData:[snc getWavData] error:&error];
  928. [self.player setDelegate:self];
  929. [self.player prepareToPlay];
  930. [self.player play];
  931. model.voicePlaying = YES;
  932. [[NSNotificationCenter defaultCenter] postNotificationName:kVoiceMessageStartPlaying object:@(self.playingMessageId)];
  933. } else if([model.message.content isKindOfClass:[WFCCVideoMessageContent class]]) {
  934. WFCCVideoMessageContent *videoMsg = (WFCCVideoMessageContent *)model.message.content;
  935. NSURL *url = [NSURL fileURLWithPath:[videoMsg.localPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
  936. if (!self.videoPlayerViewController) {
  937. self.videoPlayerViewController = [VideoPlayerKit videoPlayerWithContainingView:self.view optionalTopView:nil hideTopViewWithControls:YES];
  938. // self.videoPlayerViewController.delegate = self;
  939. self.videoPlayerViewController.allowPortraitFullscreen = YES;
  940. } else {
  941. [self.videoPlayerViewController.view removeFromSuperview];
  942. }
  943. [self.view addSubview:self.videoPlayerViewController.view];
  944. [self.videoPlayerViewController playVideoWithTitle:@" " URL:url videoID:nil shareURL:nil isStreaming:NO playInFullScreen:YES];
  945. }
  946. }
  947. #pragma mark - UICollectionViewDataSource
  948. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  949. return self.modelList.count;
  950. }
  951. // The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
  952. - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  953. WFCUMessageModel *model = self.modelList[indexPath.row];
  954. NSString *objName = [NSString stringWithFormat:@"%d", [model.message.content.class getContentType]];
  955. WFCUMessageCellBase *cell = nil;
  956. if(![self.cellContentDict objectForKey:@([model.message.content.class getContentType])]) {
  957. cell = [collectionView dequeueReusableCellWithReuseIdentifier:[NSString stringWithFormat:@"%d", [WFCCUnknownMessageContent getContentType]] forIndexPath:indexPath];
  958. } else {
  959. cell = [collectionView dequeueReusableCellWithReuseIdentifier:objName forIndexPath:indexPath];
  960. }
  961. cell.delegate = self;
  962. [[NSNotificationCenter defaultCenter] removeObserver:cell];
  963. cell.model = model;
  964. return cell;
  965. }
  966. - (UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
  967. {
  968. if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
  969. if(!self.headerView) {
  970. self.headerView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];
  971. self.headerActivityView.center = CGPointMake(self.headerView.bounds.size.width/2, self.headerView.bounds.size.height/2);
  972. [self.headerView addSubview:self.headerActivityView];
  973. }
  974. return self.headerView;
  975. } else {
  976. if(!self.footerView) {
  977. self.footerView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"FooterView" forIndexPath:indexPath];
  978. self.footerActivityView.center = CGPointMake(self.footerView.bounds.size.width/2, self.footerView.bounds.size.height/2);
  979. [self.footerView addSubview:self.footerActivityView];
  980. }
  981. return self.footerView;
  982. }
  983. return nil;
  984. }
  985. #pragma mark - UICollectionViewDelegateFlowLayout
  986. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
  987. WFCUMessageModel *model = self.modelList[indexPath.row];
  988. Class cellCls = self.cellContentDict[@([[model.message.content class] getContentType])];
  989. if (!cellCls) {
  990. cellCls = self.cellContentDict[@([[WFCCUnknownMessageContent class] getContentType])];
  991. }
  992. return [cellCls sizeForCell:model withViewWidth:self.collectionView.frame.size.width];
  993. }
  994. #pragma mark - MessageCellDelegate
  995. - (void)didTapMessageCell:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model {
  996. if ([model.message.content isKindOfClass:[WFCCImageMessageContent class]]) {
  997. if (self.conversation.type == Chatroom_Type) {
  998. NSMutableArray *imageMsgs = [[NSMutableArray alloc] init];
  999. for (WFCUMessageModel *msgModle in self.modelList) {
  1000. if ([msgModle.message.content isKindOfClass:[WFCCImageMessageContent class]]) {
  1001. [imageMsgs addObject:msgModle.message];
  1002. }
  1003. }
  1004. self.imageMsgs = imageMsgs;
  1005. } else {
  1006. self.imageMsgs = [[WFCCIMService sharedWFCIMService] getMessages:self.conversation contentTypes:@[@(MESSAGE_CONTENT_TYPE_IMAGE)] from:0 count:100 withUser:self.privateChatUser];
  1007. }
  1008. SDPhotoBrowser *browser = [[SDPhotoBrowser alloc] init];
  1009. browser.sourceImagesContainerView = self.backgroundView;
  1010. browser.imageCount = self.imageMsgs.count;
  1011. int i;
  1012. for (i = 0; i < self.imageMsgs.count; i++) {
  1013. if ([self.imageMsgs objectAtIndex:i].messageId == model.message.messageId) {
  1014. break;
  1015. }
  1016. }
  1017. if (i == self.imageMsgs.count) {
  1018. i = 0;
  1019. }
  1020. [self onResetKeyboard:nil];
  1021. browser.currentImageIndex = i;
  1022. browser.delegate = self;
  1023. [browser show]; // 展示图片浏览器
  1024. } else if([model.message.content isKindOfClass:[WFCCSoundMessageContent class]]) {
  1025. if (model.message.direction == MessageDirection_Receive && model.message.status != Message_Status_Played) {
  1026. [[WFCCIMService sharedWFCIMService] setMediaMessagePlayed:model.message.messageId];
  1027. model.message.status = Message_Status_Played;
  1028. [self.collectionView reloadItemsAtIndexPaths:@[[self.collectionView indexPathForCell:cell]]];
  1029. }
  1030. [self prepardToPlay:model];
  1031. } else if([model.message.content isKindOfClass:[WFCCLocationMessageContent class]]) {
  1032. WFCCLocationMessageContent *locContent = (WFCCLocationMessageContent *)model.message.content;
  1033. WFCULocationViewController *vc = [[WFCULocationViewController alloc] initWithLocationPoint:[[WFCULocationPoint alloc] initWithCoordinate:locContent.coordinate andTitle:locContent.title]];
  1034. [self.navigationController pushViewController:vc animated:YES];
  1035. } else if ([model.message.content isKindOfClass:[WFCCFileMessageContent class]]) {
  1036. WFCCFileMessageContent *fileContent = (WFCCFileMessageContent *)model.message.content;
  1037. WFCUBrowserViewController *bvc = [[WFCUBrowserViewController alloc] init];
  1038. bvc.url = fileContent.remoteUrl;
  1039. [self.navigationController pushViewController:bvc animated:YES];
  1040. } else if ([model.message.content isKindOfClass:[WFCCCallStartMessageContent class]]) {
  1041. WFCCCallStartMessageContent *callStartMsg = (WFCCCallStartMessageContent *)model.message.content;
  1042. #if WFCU_SUPPORT_VOIP
  1043. [self didTouchVideoBtn:callStartMsg.isAudioOnly];
  1044. #endif
  1045. } else if([model.message.content isKindOfClass:[WFCCVideoMessageContent class]]) {
  1046. WFCCVideoMessageContent *videoMsg = (WFCCVideoMessageContent *)model.message.content;
  1047. if (model.message.direction == MessageDirection_Receive && model.message.status != Message_Status_Played) {
  1048. [[WFCCIMService sharedWFCIMService] setMediaMessagePlayed:model.message.messageId];
  1049. model.message.status = Message_Status_Played;
  1050. [self.collectionView reloadItemsAtIndexPaths:@[[self.collectionView indexPathForCell:cell]]];
  1051. }
  1052. if (videoMsg.localPath.length == 0) {
  1053. model.mediaDownloading = YES;
  1054. __weak typeof(self) weakSelf = self;
  1055. [[WFCUMediaMessageDownloader sharedDownloader] tryDownload:model.message success:^(long long messageUid, NSString *localPath) {
  1056. model.mediaDownloading = NO;
  1057. [weakSelf startPlay:model];
  1058. } error:^(long long messageUid, int error_code) {
  1059. model.mediaDownloading = NO;
  1060. }];
  1061. } else {
  1062. [self startPlay:model];
  1063. }
  1064. }
  1065. }
  1066. - (void)didTapMessagePortrait:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model {
  1067. if(self.conversation.type == Group_Type) {
  1068. if (self.targetGroup.privateChat) {
  1069. if (![self.targetGroup.owner isEqualToString:model.message.fromUser] && ![self.targetGroup.owner isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  1070. WFCCGroupMember *gm = [[WFCCIMService sharedWFCIMService] getGroupMember:self.conversation.target memberId:[WFCCNetworkService sharedInstance].userId];
  1071. if (gm.type != Member_Type_Manager) {
  1072. WFCCGroupMember *gm = [[WFCCIMService sharedWFCIMService] getGroupMember:self.conversation.target memberId:model.message.fromUser];
  1073. if (gm.type != Member_Type_Manager) {
  1074. [self.view makeToast:WFCString(@"NotAllowTemporarySession") duration:1 position:CSToastPositionCenter];
  1075. return;
  1076. }
  1077. }
  1078. }
  1079. }
  1080. }
  1081. WFCUProfileTableViewController *vc = [[WFCUProfileTableViewController alloc] init];
  1082. vc.userId = model.message.fromUser;
  1083. vc.hidesBottomBarWhenPushed = YES;
  1084. [self.navigationController pushViewController:vc animated:YES];
  1085. }
  1086. - (void)didLongPressMessageCell:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model {
  1087. if ([cell isKindOfClass:[WFCUMessageCellBase class]]) {
  1088. // if (!self.isFirstResponder) {
  1089. // [self becomeFirstResponder];
  1090. // }
  1091. [self displayMenu:(WFCUMessageCellBase *)cell];
  1092. }
  1093. }
  1094. - (void)didLongPressMessagePortrait:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model {
  1095. if (self.conversation.type == Group_Type) {
  1096. if (model.message.direction == MessageDirection_Receive) {
  1097. WFCCUserInfo *sender = [[WFCCIMService sharedWFCIMService] getUserInfo:model.message.fromUser refresh:NO];
  1098. [self.chatInputBar appendMention:model.message.fromUser name:sender.displayName];
  1099. }
  1100. } else if(self.conversation.type == Channel_Type) {
  1101. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
  1102. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:WFCString(@"Cancel") style:UIAlertActionStyleCancel handler:nil];
  1103. UIAlertAction *okAction = [UIAlertAction actionWithTitle:WFCString(@"ChatWithSubscriber") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1104. if (model.message.direction == MessageDirection_Receive) {
  1105. WFCCChannelInfo *channelInfo = [[WFCCIMService sharedWFCIMService] getChannelInfo:self.conversation.target refresh:NO];
  1106. if ([channelInfo.owner isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  1107. WFCUMessageListViewController *mvc = [[WFCUMessageListViewController alloc] init];
  1108. mvc.conversation = [WFCCConversation conversationWithType:self.conversation.type target:self.conversation.target line:self.conversation.line];
  1109. mvc.privateChatUser = model.message.fromUser;
  1110. [self.navigationController pushViewController:mvc animated:YES];
  1111. }
  1112. }
  1113. }];
  1114. [alertController addAction:cancelAction];
  1115. [alertController addAction:okAction];
  1116. [self presentViewController:alertController animated:YES completion:nil];
  1117. }
  1118. }
  1119. - (void)didTapResendBtn:(WFCUMessageModel *)model {
  1120. NSInteger index = [self.modelList indexOfObject:model];
  1121. if (index >= 0) {
  1122. NSIndexPath *path = [NSIndexPath indexPathForRow:index inSection:0];
  1123. [self.modelList removeObjectAtIndex:index];
  1124. [self.collectionView deleteItemsAtIndexPaths:@[path]];
  1125. [[WFCCIMService sharedWFCIMService] deleteMessage:model.message.messageId];
  1126. [self sendMessage:model.message.content];
  1127. }
  1128. }
  1129. - (void)didSelectUrl:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model withUrl:(NSString *)urlString {
  1130. WFCUBrowserViewController *bvc = [[WFCUBrowserViewController alloc] init];
  1131. bvc.url = urlString;
  1132. [self.navigationController pushViewController:bvc animated:YES];
  1133. }
  1134. - (void)didSelectPhoneNumber:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model withPhoneNumber:(NSString *)phoneNumber {
  1135. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:WFCString(@"PhoneNumberHint"), phoneNumber] message:nil preferredStyle:UIAlertControllerStyleActionSheet];
  1136. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:WFCString(@"Cancel") style:UIAlertActionStyleCancel handler:nil];
  1137. UIAlertAction *callAction = [UIAlertAction actionWithTitle:WFCString(@"Call") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1138. NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"telprompt:%@", phoneNumber]];
  1139. [[UIApplication sharedApplication] openURL:url];
  1140. }];
  1141. UIAlertAction *copyAction = [UIAlertAction actionWithTitle:WFCString(@"CopyNumber") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1142. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  1143. pasteboard.string = phoneNumber;
  1144. }];
  1145. [alertController addAction:cancelAction];
  1146. [alertController addAction:callAction];
  1147. [alertController addAction:copyAction];
  1148. // [alertController addAction:addContactAction];
  1149. [self presentViewController:alertController animated:YES completion:nil];
  1150. }
  1151. - (void)reeditRecalledMessage:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model {
  1152. WFCCRecallMessageContent *recall = (WFCCRecallMessageContent *)model.message.content;
  1153. [self.chatInputBar appendText:recall.originalSearchableContent];
  1154. }
  1155. - (void)didTapReceiptView:(WFCUMessageCellBase *)cell withModel:(WFCUMessageModel *)model {
  1156. WFCUReceiptViewController *receipt = [[WFCUReceiptViewController alloc] init];
  1157. receipt.message = model.message;
  1158. [self.navigationController pushViewController:receipt animated:YES];
  1159. }
  1160. #pragma mark - AVAudioPlayerDelegate
  1161. - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
  1162. NSLog(@"player finished");
  1163. [self stopPlayer];
  1164. }
  1165. - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error {
  1166. NSLog(@"player decode error");
  1167. [[[UIAlertView alloc] initWithTitle:WFCString(@"Warning") message:WFCString(@"NetworkError") delegate:nil cancelButtonTitle:WFCString(@"Ok") otherButtonTitles:nil, nil] show];
  1168. [self stopPlayer];
  1169. }
  1170. #pragma mark - UIScrollViewDelegate
  1171. - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  1172. }
  1173. - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
  1174. [self.chatInputBar resetInputBarStatue];
  1175. }
  1176. - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
  1177. if (self.hasNewMessage && targetContentOffset->y == (scrollView.contentSize.height - scrollView.bounds.size.height)) {
  1178. [self loadMoreMessage:NO];
  1179. }
  1180. if (targetContentOffset->y == 0 && self.hasMoreOld) {
  1181. [self loadMoreMessage:YES];
  1182. }
  1183. }
  1184. - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
  1185. }
  1186. #pragma mark - ChatInputBarDelegate
  1187. - (void)imageDidCapture:(UIImage *)capturedImage {
  1188. if (!capturedImage) {
  1189. return;
  1190. }
  1191. WFCCImageMessageContent *imgContent = [WFCCImageMessageContent contentFrom:capturedImage];
  1192. [self sendMessage:imgContent];
  1193. }
  1194. - (void)videoDidCapture:(NSString *)videoPath thumbnail:(UIImage *)image duration:(long)duration {
  1195. WFCCVideoMessageContent *videoContent = [WFCCVideoMessageContent contentPath:videoPath thumbnail:image];
  1196. [self sendMessage:videoContent];
  1197. }
  1198. - (void)didTouchSend:(NSString *)stringContent withMentionInfos:(NSMutableArray<WFCUMetionInfo *> *)mentionInfos {
  1199. if (stringContent.length == 0) {
  1200. return;
  1201. }
  1202. WFCCTextMessageContent *txtContent = [[WFCCTextMessageContent alloc] init];
  1203. txtContent.text = stringContent;
  1204. NSMutableArray *mentionTargets = [[NSMutableArray alloc] init];
  1205. for (WFCUMetionInfo *mentionInfo in mentionInfos) {
  1206. if (mentionInfo.mentionType == 2) {
  1207. txtContent.mentionedType = 2;
  1208. mentionTargets = nil;
  1209. break;
  1210. } else if(mentionInfo.mentionType == 1) {
  1211. txtContent.mentionedType = 1;
  1212. [mentionTargets addObject:mentionInfo.target];
  1213. }
  1214. }
  1215. if (txtContent.mentionedType == 1) {
  1216. txtContent.mentionedTargets = [mentionTargets copy];
  1217. }
  1218. [self sendMessage:txtContent];
  1219. }
  1220. - (void)recordDidEnd:(NSString *)dataUri duration:(long)duration error:(NSError *)error {
  1221. [self sendMessage:[WFCCSoundMessageContent soundMessageContentForWav:dataUri duration:duration]];
  1222. }
  1223. - (void)willChangeFrame:(CGRect)newFrame withDuration:(CGFloat)duration keyboardShowing:(BOOL)keyboardShowing {
  1224. if (!self.isShowingKeyboard) {
  1225. self.isShowingKeyboard = YES;
  1226. [UIView animateWithDuration:duration animations:^{
  1227. CGRect frame = self.collectionView.frame;
  1228. CGFloat diff = MIN(frame.size.height, self.collectionView.contentSize.height) - newFrame.origin.y;
  1229. if(diff > 0) {
  1230. frame.origin.y = -diff;
  1231. self.collectionView.frame = frame;
  1232. } else {
  1233. self.collectionView.frame = CGRectMake(0, 0, self.backgroundView.bounds.size.width, newFrame.origin.y);
  1234. }
  1235. } completion:^(BOOL finished) {
  1236. self.collectionView.frame = CGRectMake(0, 0, self.backgroundView.bounds.size.width, newFrame.origin.y);
  1237. if (keyboardShowing) {
  1238. [self scrollToBottom:NO];
  1239. }
  1240. self.isShowingKeyboard = NO;
  1241. }];
  1242. } else {
  1243. if (self.collectionView.frame.size.height != newFrame.origin.y) {
  1244. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1245. self.collectionView.frame = CGRectMake(0, 0, self.backgroundView.bounds.size.width, newFrame.origin.y);
  1246. [self scrollToBottom:YES];
  1247. });
  1248. }
  1249. }
  1250. }
  1251. - (UINavigationController *)requireNavi {
  1252. return self.navigationController;
  1253. }
  1254. - (void)locationDidSelect:(CLLocationCoordinate2D)location locationName:(NSString *)locationName mapScreenShot:(UIImage *)mapScreenShot {
  1255. WFCCLocationMessageContent *content = [WFCCLocationMessageContent contentWith:location title:locationName thumbnail:mapScreenShot];
  1256. [self sendMessage:content];
  1257. }
  1258. - (void)didSelectFiles:(NSArray *)files {
  1259. for (NSString *file in files) {
  1260. WFCCFileMessageContent *content = [WFCCFileMessageContent fileMessageContentFromPath:file];
  1261. [self sendMessage:content];
  1262. [NSThread sleepForTimeInterval:0.05];
  1263. }
  1264. }
  1265. - (void)saveStickerRemoteUrl:(WFCCStickerMessageContent *)stickerContent {
  1266. if (stickerContent.localPath.length && stickerContent.remoteUrl.length) {
  1267. [[NSUserDefaults standardUserDefaults] setObject:stickerContent.remoteUrl forKey:[NSString stringWithFormat:@"sticker_remote_for_%ld", stickerContent.localPath.hash]];
  1268. [[NSUserDefaults standardUserDefaults] synchronize];
  1269. }
  1270. }
  1271. - (void)didSelectSticker:(NSString *)stickerPath {
  1272. WFCCStickerMessageContent * content = [WFCCStickerMessageContent contentFrom:stickerPath];
  1273. NSString *remoteUrl = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"sticker_remote_for_%ld", stickerPath.hash]];
  1274. content.remoteUrl = remoteUrl;
  1275. [self sendMessage:content];
  1276. }
  1277. #if WFCU_SUPPORT_VOIP
  1278. - (void)didTouchVideoBtn:(BOOL)isAudioOnly {
  1279. if(self.conversation.type == Single_Type) {
  1280. WFCUVideoViewController *videoVC = [[WFCUVideoViewController alloc] initWithTargets:@[self.conversation.target] conversation:self.conversation audioOnly:isAudioOnly];
  1281. [[WFAVEngineKit sharedEngineKit] presentViewController:videoVC];
  1282. } else {
  1283. // WFCUContactListViewController *pvc = [[WFCUContactListViewController alloc] init];
  1284. // pvc.selectContact = YES;
  1285. // pvc.multiSelect = [WFAVEngineKit sharedEngineKit].supportMultiCall;
  1286. // if (pvc.multiSelect) {
  1287. // pvc.maxSelectCount = isAudioOnly ? [WFAVEngineKit sharedEngineKit].maxAudioCallCount : [WFAVEngineKit sharedEngineKit].maxVideoCallCount;
  1288. // pvc.maxSelectCount -= 1;
  1289. // }
  1290. WFCUSeletedUserViewController *vc = [[WFCUSeletedUserViewController alloc] init];
  1291. NSMutableArray *disabledUser = [[NSMutableArray alloc] init];
  1292. [disabledUser addObject:[WFCCNetworkService sharedInstance].userId];
  1293. vc.disableUserIds = disabledUser;
  1294. vc.maxSelectCount = isAudioOnly ? [WFAVEngineKit sharedEngineKit].maxAudioCallCount : [WFAVEngineKit sharedEngineKit].maxVideoCallCount;
  1295. vc.groupId = self.targetGroup.target;
  1296. // vc.maxSelectCount -= 1;
  1297. NSMutableArray *candidateUser = [[NSMutableArray alloc] init];
  1298. NSArray<WFCCGroupMember *> *members = [[WFCCIMService sharedWFCIMService] getGroupMembers:self.conversation.target forceUpdate:NO];
  1299. for (WFCCGroupMember *member in members) {
  1300. [candidateUser addObject:member.memberId];
  1301. }
  1302. vc.candidateUsers = candidateUser;
  1303. vc.type = Vertical;
  1304. __weak typeof(self)ws = self;
  1305. vc.selectResult = ^(NSArray<NSString *> * _Nonnull contacts) {
  1306. UIViewController *videoVC;
  1307. if (ws.conversation.type == Group_Type && [WFAVEngineKit sharedEngineKit].supportMultiCall) {
  1308. videoVC = [[WFCUMultiVideoViewController alloc] initWithTargets:contacts conversation:ws.conversation audioOnly:isAudioOnly];
  1309. } else {
  1310. videoVC = [[WFCUVideoViewController alloc] initWithTargets:contacts conversation:ws.conversation audioOnly:isAudioOnly];
  1311. }
  1312. [[WFAVEngineKit sharedEngineKit] presentViewController:videoVC];
  1313. };
  1314. UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:vc];
  1315. navi.modalPresentationStyle = UIModalPresentationFullScreen;
  1316. [self.navigationController presentViewController:navi animated:YES completion:nil];
  1317. }
  1318. }
  1319. #endif
  1320. - (void)onTyping:(WFCCTypingType)type {
  1321. if (self.conversation.type == Single_Type) {
  1322. [self sendMessage:[WFCCTypingMessageContent contentType:type]];
  1323. }
  1324. }
  1325. #pragma mark - SDPhotoBrowserDelegate
  1326. - (UIImage *)photoBrowser:(SDPhotoBrowser *)browser placeholderImageForIndex:(NSInteger)index {
  1327. WFCCMessage *msg = [self.imageMsgs objectAtIndex:index];
  1328. if ([[msg.content class] getContentType] == MESSAGE_CONTENT_TYPE_IMAGE) {
  1329. WFCCImageMessageContent *imgContent = (WFCCImageMessageContent *)msg.content;
  1330. return imgContent.thumbnail;
  1331. }
  1332. return nil;
  1333. }
  1334. - (NSURL *)photoBrowser:(SDPhotoBrowser *)browser highQualityImageURLForIndex:(NSInteger)index {
  1335. WFCCMessage *msg = [self.imageMsgs objectAtIndex:index];
  1336. if ([[msg.content class] getContentType] == MESSAGE_CONTENT_TYPE_IMAGE) {
  1337. WFCCImageMessageContent *imgContent = (WFCCImageMessageContent *)msg.content;
  1338. return [NSURL URLWithString:[imgContent.remoteUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
  1339. }
  1340. return nil;
  1341. }
  1342. - (void)photoBrowserDidDismiss:(SDPhotoBrowser *)browser {
  1343. self.imageMsgs = nil;
  1344. }
  1345. #pragma mark - UIGestureRecognizerDelegate
  1346. - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
  1347. return self.navigationController.childViewControllers.count > 1;
  1348. }
  1349. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
  1350. return self.navigationController.viewControllers.count > 1;
  1351. }
  1352. #pragma mark - menu
  1353. - (void)displayMenu:(WFCUMessageCellBase *)baseCell {
  1354. UIMenuController *menu = [UIMenuController sharedMenuController];
  1355. UIMenuItem *deleteItem = [[UIMenuItem alloc]initWithTitle:WFCString(@"Delete") action:@selector(performDelete:)];
  1356. UIMenuItem *copyItem = [[UIMenuItem alloc]initWithTitle:WFCString(@"Copy") action:@selector(performCopy:)];
  1357. UIMenuItem *forwardItem = [[UIMenuItem alloc]initWithTitle:WFCString(@"Forward") action:@selector(performForward:)];
  1358. UIMenuItem *recallItem = [[UIMenuItem alloc]initWithTitle:WFCString(@"Recall") action:@selector(performRecall:)];
  1359. UIMenuItem *complainItem = [[UIMenuItem alloc]initWithTitle:WFCString(@"Complain") action:@selector(performComplain:)];
  1360. CGRect menuPos;
  1361. if ([baseCell isKindOfClass:[WFCUMessageCell class]]) {
  1362. WFCUMessageCell *msgCell = (WFCUMessageCell *)baseCell;
  1363. menuPos = msgCell.bubbleView.frame;
  1364. } else {
  1365. menuPos = baseCell.frame;
  1366. }
  1367. [menu setTargetRect:menuPos inView:baseCell];
  1368. WFCCMessage *msg = baseCell.model.message;
  1369. NSMutableArray *items = [[NSMutableArray alloc] init];
  1370. [items addObject:deleteItem];
  1371. if ([msg.content isKindOfClass:[WFCCTextMessageContent class]]) {
  1372. [items addObject:copyItem];
  1373. }
  1374. if (baseCell.model.message.direction == MessageDirection_Receive) {
  1375. [items addObject:complainItem];
  1376. }
  1377. if ([msg.content isKindOfClass:[WFCCImageMessageContent class]] ||
  1378. [msg.content isKindOfClass:[WFCCTextMessageContent class]] ||
  1379. [msg.content isKindOfClass:[WFCCLocationMessageContent class]] ||
  1380. [msg.content isKindOfClass:[WFCCFileMessageContent class]] ||
  1381. [msg.content isKindOfClass:[WFCCVideoMessageContent class]] ||
  1382. // [msg.content isKindOfClass:[WFCCSoundMessageContent class]] || //语音消息禁止转发,出于安全原因考虑,微信就禁止转发。如果您能确保安全,可以把这行注释打开
  1383. [msg.content isKindOfClass:[WFCCStickerMessageContent class]]) {
  1384. [items addObject:forwardItem];
  1385. }
  1386. BOOL canRecall = NO;
  1387. if ([baseCell isKindOfClass:[WFCUMessageCell class]] &&
  1388. msg.direction == MessageDirection_Send
  1389. ) {
  1390. NSDate *cur = [NSDate date];
  1391. if ([cur timeIntervalSince1970]*1000 - msg.serverTime < 60 * 1000) {
  1392. canRecall = YES;
  1393. }
  1394. }
  1395. if (!canRecall && self.conversation.type == Group_Type) {
  1396. WFCCGroupInfo *groupInfo = [[WFCCIMService sharedWFCIMService] getGroupInfo:self.conversation.target refresh:NO];
  1397. if([groupInfo.owner isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  1398. canRecall = YES;
  1399. if ([groupInfo.owner isEqualToString:msg.fromUser]) {
  1400. canRecall = NO;
  1401. }
  1402. } else {
  1403. __block BOOL isManager = false;
  1404. NSArray *memberList = [[WFCCIMService sharedWFCIMService] getGroupMembers:self.conversation.target forceUpdate:NO];
  1405. [memberList enumerateObjectsUsingBlock:^(WFCCGroupMember * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  1406. if ([obj.memberId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  1407. if (obj.type != Member_Type_Normal && ![msg.fromUser isEqualToString:obj.memberId]) {
  1408. isManager = YES;
  1409. }
  1410. *stop = YES;
  1411. }
  1412. }];
  1413. if(isManager && ![msg.fromUser isEqualToString:groupInfo.owner]) {
  1414. canRecall = YES;
  1415. }
  1416. }
  1417. }
  1418. if (canRecall) {
  1419. [items addObject:recallItem];
  1420. }
  1421. [menu setMenuItems:items];
  1422. self.cell4Menu = baseCell;
  1423. [menu setMenuVisible:YES];
  1424. }
  1425. -(BOOL)canBecomeFirstResponder {
  1426. return YES;
  1427. }
  1428. -(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
  1429. if(self.cell4Menu) {
  1430. if (action == @selector(performDelete:) || action == @selector(performCopy:) || action == @selector(performForward:) || action == @selector(performRecall:) || action == @selector(performComplain:)) {
  1431. return YES; //显示自定义的菜单项
  1432. } else {
  1433. return NO;
  1434. }
  1435. }
  1436. if (action == @selector(paste:)) {
  1437. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  1438. return pasteboard.string != nil;
  1439. }
  1440. return NO;//[super canPerformAction:action withSender:sender];
  1441. }
  1442. - (void)paste:(id)sender {
  1443. [self.chatInputBar paste:sender];
  1444. }
  1445. - (void)deleteMessageUI:(WFCCMessage *)message {
  1446. for (int i = 0; i < self.modelList.count; i++) {
  1447. WFCUMessageModel *model = [self.modelList objectAtIndex:i];
  1448. if (model.message.messageUid == message.messageUid) {
  1449. [self.modelList removeObject:model];
  1450. [self.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]];
  1451. break;
  1452. }
  1453. }
  1454. }
  1455. -(void)performDelete:(UIMenuController *)sender {
  1456. __weak typeof(self)ws = self;
  1457. WFCCMessage *message = self.cell4Menu.model.message;
  1458. [[WFCCIMService sharedWFCIMService] deleteMessage:message.messageId];
  1459. [ws deleteMessageUI:message];
  1460. }
  1461. -(void)performCopy:(UIMenuItem *)sender {
  1462. if (self.cell4Menu) {
  1463. if ([self.cell4Menu.model.message.content isKindOfClass:[WFCCTextMessageContent class]]) {
  1464. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  1465. pasteboard.string = ((WFCCTextMessageContent *)self.cell4Menu.model.message.content).text;
  1466. }
  1467. }
  1468. }
  1469. -(void)performForward:(UIMenuItem *)sender {
  1470. if (self.cell4Menu) {
  1471. WFCUForwardViewController *controller = [[WFCUForwardViewController alloc] init];
  1472. controller.message = self.cell4Menu.model.message;
  1473. UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:controller];
  1474. [self.navigationController presentViewController:navi animated:YES completion:nil];
  1475. }
  1476. }
  1477. -(void)performRecall:(UIMenuItem *)sender {
  1478. if (self.cell4Menu.model.message) {
  1479. __block MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
  1480. hud.label.text = WFCString(@"Recalling");
  1481. [hud showAnimated:YES];
  1482. __weak typeof(self) ws = self;
  1483. long messageId = self.cell4Menu.model.message.messageId;
  1484. WFCUMessageCellBase *cell = self.cell4Menu;
  1485. [[WFCCIMService sharedWFCIMService] recall:self.cell4Menu.model.message success:^{
  1486. dispatch_async(dispatch_get_main_queue(), ^{
  1487. [hud hideAnimated:YES];
  1488. if (cell.model.message.messageId == messageId) {
  1489. cell.model.message = [[WFCCIMService sharedWFCIMService] getMessage:messageId];
  1490. [ws.collectionView reloadItemsAtIndexPaths:@[[ws.collectionView indexPathForCell:cell]]];
  1491. }
  1492. });
  1493. } error:^(int error_code) {
  1494. dispatch_async(dispatch_get_main_queue(), ^{
  1495. hud.mode = MBProgressHUDModeText;
  1496. hud.label.text = WFCString(@"RecallFailure");
  1497. [hud hideAnimated:YES afterDelay:1.f];
  1498. });
  1499. }];
  1500. }
  1501. }
  1502. - (void)performComplain:(UIMenuItem *)sender {
  1503. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:WFCString(@"Complain") message:@"如果您发现有违反法律和道德的内容,或者您的合法权益受到侵犯,请截图之后发送给我们。我们会在24小时之内处理。处理办法包括不限于删除内容,对作者进行警告,冻结账号,甚至报警处理。举报请到\"设置->设置->举报\"联系我们!" preferredStyle:UIAlertControllerStyleAlert];
  1504. UIAlertAction *action = [UIAlertAction actionWithTitle:WFCString(WFCString(@"Ok")) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  1505. }];
  1506. [alertController addAction:action];
  1507. [self presentViewController:alertController animated:YES completion:nil];
  1508. }
  1509. - (void)onMenuHidden:(id)sender {
  1510. UIMenuController *menu = [UIMenuController sharedMenuController];
  1511. [menu setMenuItems:nil];
  1512. __weak typeof(self)ws = self;
  1513. dispatch_async(dispatch_get_main_queue(), ^{
  1514. ws.cell4Menu = nil;
  1515. });
  1516. }
  1517. - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
  1518. [super traitCollectionDidChange:previousTraitCollection];
  1519. if (@available(iOS 13.0, *)) {
  1520. if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
  1521. [self.navigationController popViewControllerAnimated:NO];
  1522. }
  1523. }
  1524. }
  1525. - (void)dealloc {
  1526. [[NSNotificationCenter defaultCenter] removeObserver:self];
  1527. }
  1528. @end