2
0

WFCUMessageListViewController.m 90 KB

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