TUIMessageBaseDataProvider.m 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616
  1. // Created by Tencent on 2023/06/09.
  2. // Copyright © 2023 Tencent. All rights reserved.
  3. #import <AVFoundation/AVFoundation.h>
  4. #import <TIMCommon/NSString+TUIEmoji.h>
  5. #import <TIMCommon/TIMDefine.h>
  6. #import <TIMCommon/TUIMessageCell.h>
  7. #import <TIMCommon/TUISystemMessageCellData.h>
  8. #import <TIMCommon/TUIRelationUserModel.h>
  9. #import <TUICore/NSString+TUIUtil.h>
  10. #import <TUICore/TUICore.h>
  11. #import <TUICore/TUILogin.h>
  12. #import <TUICore/TUITool.h>
  13. #import <TUICore/OfflinePushExtInfo.h>
  14. #import "TUIChatConfig.h"
  15. #import "TUICloudCustomDataTypeCenter.h"
  16. #import "TUIMessageBaseDataProvider.h"
  17. #import "TUIMessageProgressManager.h"
  18. #import "TUITypingStatusCellData.h"
  19. /**
  20. * Date time interval above the message in the UIMessageCell, in seconds, default is (5 * 60)
  21. */
  22. #define MaxDateMessageDelay 5 * 60
  23. @interface TUIMessageBaseDataProvider () <V2TIMAdvancedMsgListener, V2TIMGroupListener,TUIMessageProgressManagerDelegate>
  24. @property(nonatomic, strong) TUIChatConversationModel *conversationModel;
  25. @property(nonatomic, strong) NSMutableArray<TUIMessageCellData *> *uiMsgs_;
  26. @property(nonatomic, strong) NSMutableSet<NSString *> *sentReadGroupMsgSet;
  27. @property(nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *heightCache_;
  28. @property(nonatomic, assign) BOOL isLoadingData;
  29. @property(nonatomic, assign) BOOL isNoMoreMsg;
  30. @property(nonatomic, assign) BOOL isFirstLoad;
  31. @property(nonatomic, strong) V2TIMMessage *lastMsg;
  32. @property(nonatomic, strong) V2TIMMessage *msgForDate;
  33. @property(nonatomic, strong) V2TIMGroupMemberFullInfo *groupSelfInfo;
  34. @property(nonatomic, strong) NSMutableArray<V2TIMMessage *> *groupPinList;
  35. @property(nonatomic, assign) V2TIMGroupMemberRole changedRole;
  36. @property(nonatomic, strong) V2TIMGroupInfo *groupInfo;
  37. @end
  38. @implementation TUIMessageBaseDataProvider
  39. - (instancetype)initWithConversationModel:(TUIChatConversationModel *)conversationModel {
  40. self = [super init];
  41. if (self) {
  42. _conversationModel = conversationModel;
  43. _isLoadingData = NO;
  44. _isNoMoreMsg = NO;
  45. _pageCount = 20;
  46. _isFirstLoad = YES;
  47. [self registerTUIKitNotification];
  48. }
  49. return self;
  50. }
  51. - (void)dealloc {
  52. [[NSNotificationCenter defaultCenter] removeObserver:self];
  53. }
  54. - (NSMutableSet<NSString *> *)sentReadGroupMsgSet {
  55. if (_sentReadGroupMsgSet == nil) {
  56. _sentReadGroupMsgSet = [NSMutableSet setWithCapacity:10];
  57. }
  58. return _sentReadGroupMsgSet;
  59. }
  60. - (NSMutableArray<TUIMessageCellData *> *)uiMsgs_ {
  61. if (_uiMsgs_ == nil) {
  62. _uiMsgs_ = [NSMutableArray array];
  63. }
  64. return _uiMsgs_;
  65. }
  66. - (NSMutableDictionary<NSString *, NSNumber *> *)heightCache_ {
  67. if (_heightCache_ == nil) {
  68. _heightCache_ = [NSMutableDictionary dictionary];
  69. }
  70. return _heightCache_;
  71. }
  72. - (NSArray<TUIMessageCellData *> *)uiMsgs {
  73. return _uiMsgs_;
  74. }
  75. - (NSDictionary<NSString *, NSNumber *> *)heightCache {
  76. return _heightCache_;
  77. }
  78. - (void)setChangedRole:(V2TIMGroupMemberRole)changedRole {
  79. _changedRole = changedRole;
  80. if (self.groupRoleChanged) {
  81. self.groupRoleChanged(changedRole);
  82. }
  83. }
  84. #pragma mark - TUIKitNotification
  85. - (void)registerTUIKitNotification {
  86. [[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
  87. [[V2TIMManager sharedInstance] addGroupListener:self];
  88. [[NSNotificationCenter defaultCenter] addObserver:self
  89. selector:@selector(onMessageStatusChanged:)
  90. name:TUIKitNotification_onMessageStatusChanged
  91. object:nil];
  92. }
  93. - (void)onMessageStatusChanged:(NSNotification *)notification {
  94. V2TIMMessage *targetMsg = notification.object;
  95. NSString *msgId = targetMsg.msgID;
  96. TUIMessageCellData *uiMsg = nil;
  97. BOOL isMatch = NO;
  98. for (uiMsg in self.uiMsgs) {
  99. if ([uiMsg.msgID isEqualToString:msgId]) {
  100. [self.dataSource dataProviderDataSourceWillChange:self];
  101. NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
  102. [self.dataSource dataProviderDataSourceChange:self withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload atIndex:index animation:YES];
  103. [self.dataSource dataProviderDataSourceDidChange:self];
  104. isMatch = YES;
  105. break;
  106. }
  107. }
  108. if (!isMatch) {
  109. // Need insert UI Message
  110. [self onRecvNewMessage:targetMsg];
  111. }
  112. }
  113. #pragma mark - V2TIMAdvancedMsgListener
  114. - (void)onRecvNewMessage:(V2TIMMessage *)msg {
  115. // immsg -> uimsg
  116. NSMutableArray *newUIMsgs = [self transUIMsgFromIMMsg:@[ msg ]];
  117. if (newUIMsgs.count == 0) {
  118. return;
  119. }
  120. TUIMessageCellData *newUIMsg = newUIMsgs.lastObject;
  121. newUIMsg.source = Msg_Source_OnlinePush;
  122. if ([newUIMsg isKindOfClass:TUITypingStatusCellData.class]) {
  123. if (![TUIChatConfig defaultConfig].enableTypingStatus) {
  124. return;
  125. }
  126. TUITypingStatusCellData *stastusData = (TUITypingStatusCellData *)newUIMsg;
  127. if (!NSThread.isMainThread) {
  128. @weakify(self);
  129. dispatch_async(dispatch_get_main_queue(), ^{
  130. @strongify(self);
  131. [self dealTypingByStatusCellData:stastusData];
  132. });
  133. return;
  134. } else {
  135. [self dealTypingByStatusCellData:stastusData];
  136. }
  137. return;
  138. }
  139. @weakify(self);
  140. [self preProcessMessage:newUIMsgs
  141. callback:^{
  142. @strongify(self);
  143. [self.dataSource dataProviderDataSourceWillChange:self];
  144. @autoreleasepool {
  145. for (TUIMessageCellData *uiMsg in newUIMsgs) {
  146. [self addUIMsg:uiMsg];
  147. [self.dataSource dataProviderDataSourceChange:self
  148. withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
  149. atIndex:(self.uiMsgs_.count - 1)
  150. animation:YES];
  151. }
  152. }
  153. [self.dataSource dataProviderDataSourceDidChange:self];
  154. if ([self.dataSource respondsToSelector:@selector(dataProvider:ReceiveNewUIMsg:)]) {
  155. /**
  156. * Note that firstObject cannot be taken here, firstObject may be SystemMessageCellData that displays system time
  157. */
  158. [self.dataSource dataProvider:self ReceiveNewUIMsg:newUIMsgs.lastObject];
  159. }
  160. }];
  161. }
  162. - (NSMutableArray *)transUIMsgFromIMMsg:(NSArray *)msgs {
  163. NSMutableArray *uiMsgs = [NSMutableArray array];
  164. for (NSInteger k = msgs.count - 1; k >= 0; --k) {
  165. V2TIMMessage *msg = msgs[k];
  166. /**
  167. * Messages that are not the current session, ignore them directly
  168. */
  169. if (![msg.userID isEqualToString:self.conversationModel.userID] && ![msg.groupID isEqualToString:self.conversationModel.groupID]) {
  170. continue;
  171. }
  172. TUIMessageCellData *cellData = nil;
  173. /**
  174. * Determine whether it is a custom message outside the component
  175. */
  176. if ([self.dataSource respondsToSelector:@selector(dataProvider:CustomCellDataFromNewIMMessage:)]) {
  177. cellData = [self.dataSource dataProvider:self CustomCellDataFromNewIMMessage:msg];
  178. }
  179. if([self.dataSource_Two respondsToSelector:@selector(dataProvider_Two:CustomCellDataFromNewIMMessage:)]) {
  180. V2TIMMessage *newMsg = [self.dataSource_Two dataProvider_Two:self CustomCellDataFromNewIMMessage:msg];
  181. if(newMsg){
  182. msg = newMsg;
  183. }
  184. }
  185. /**
  186. * Determine whether it is a component internal message
  187. */
  188. if (!cellData) {
  189. cellData = [self.class getCellData:msg];
  190. }
  191. if (cellData) {
  192. if([cellData.innerMessage.sender isEqualToString:@"10000"] || [cellData.innerMessage.sender isEqualToString:@"10001"]){
  193. //不加入时间dateMsg
  194. }
  195. else{
  196. TUIMessageCellData *dateMsg = [self getSystemMsgFromDate:msg.timestamp];
  197. if (dateMsg) {
  198. if (self.mergeAdjacentMsgsFromTheSameSender) {
  199. dateMsg.showName = NO;
  200. }
  201. self.msgForDate = msg;
  202. [uiMsgs addObject:dateMsg];
  203. }
  204. }
  205. if (self.mergeAdjacentMsgsFromTheSameSender) {
  206. cellData.showName = NO;
  207. }
  208. [uiMsgs addObject:cellData];
  209. }
  210. }
  211. return uiMsgs;
  212. }
  213. /// Received message read receipts, both in group and c2c conversation.
  214. - (void)onRecvMessageReadReceipts:(NSArray<V2TIMMessageReceipt *> *)receiptList {
  215. if (receiptList.count == 0) {
  216. NSLog(@"group receipt data is empty, ignore");
  217. return;
  218. }
  219. if (![self.dataSource respondsToSelector:@selector(dataProvider:ReceiveReadMsgWithGroupID:msgID:readCount:unreadCount:)]) {
  220. NSLog(@"data source can not respond to protocol, ignore");
  221. }
  222. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  223. for (V2TIMMessageReceipt *receipt in receiptList) {
  224. [dict setObject:receipt forKey:receipt.msgID];
  225. }
  226. // update TUIMessageCellData readCount/unreadCount
  227. for (TUIMessageCellData *data in self.uiMsgs) {
  228. if ([dict.allKeys containsObject:data.innerMessage.msgID]) {
  229. V2TIMMessageReceipt *receipt = dict[data.innerMessage.msgID];
  230. data.messageReceipt = receipt;
  231. if ([self.dataSource respondsToSelector:@selector(dataProvider:ReceiveReadMsgWithGroupID:msgID:readCount:unreadCount:)]) {
  232. [self.dataSource dataProvider:self
  233. ReceiveReadMsgWithGroupID:receipt.groupID
  234. msgID:receipt.msgID
  235. readCount:receipt.readCount
  236. unreadCount:receipt.unreadCount];
  237. }
  238. }
  239. }
  240. }
  241. - (void)onRecvMessageRevoked:(NSString *)msgID operateUser:(V2TIMUserFullInfo *)operateUser reason:(NSString *)reason {
  242. @weakify(self);
  243. [TUITool dispatchMainAsync:^{
  244. @strongify(self);
  245. TUIMessageCellData *uiMsg = nil;
  246. for (uiMsg in self.uiMsgs) {
  247. if ([uiMsg.msgID isEqualToString:msgID]) {
  248. [self.dataSource dataProviderDataSourceWillChange:self];
  249. NSUInteger index = [self.uiMsgs indexOfObject:uiMsg];
  250. TUISystemMessageCellData *revokeCellData = (TUISystemMessageCellData *)[self.class getRevokeCellData:uiMsg.innerMessage];
  251. revokeCellData.content = [self.class getRevokeDispayString:uiMsg.innerMessage operateUser:operateUser reason:reason];
  252. if(![operateUser.userID isEqualToString:uiMsg.innerMessage.sender]) {
  253. //Super User revoke
  254. revokeCellData.supportReEdit = NO;
  255. }
  256. [self replaceUIMsg:revokeCellData atIndex:index];
  257. [self.dataSource dataProviderDataSourceChange:self withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload atIndex:index animation:YES];
  258. [self.dataSource dataProviderDataSourceDidChange:self];
  259. break;
  260. }
  261. }
  262. if ([self.dataSource respondsToSelector:@selector(dataProvider:ReceiveRevokeUIMsg:)]) {
  263. [self.dataSource dataProvider:self ReceiveRevokeUIMsg:uiMsg];
  264. }
  265. }];
  266. }
  267. - (void)onRecvMessageModified:(V2TIMMessage *)msg {
  268. V2TIMMessage *imMsg = msg;
  269. if (imMsg == nil || ![imMsg isKindOfClass:V2TIMMessage.class]) {
  270. return;
  271. }
  272. @weakify(self);
  273. for (TUIMessageCellData *uiMsg in self.uiMsgs) {
  274. if ([uiMsg.msgID isEqualToString:imMsg.msgID]) {
  275. if ([uiMsg customReloadCellWithNewMsg:imMsg]) {
  276. return;
  277. }
  278. NSMutableArray *newUIMsgs = [self transUIMsgFromIMMsg:@[ imMsg ]];
  279. if (newUIMsgs.count == 0) {
  280. return;
  281. }
  282. /**
  283. * Note that firstObject cannot be taken here, firstObject may be SystemMessageCellData that displays system time
  284. */
  285. TUIMessageCellData *newUIMsg = newUIMsgs.lastObject;
  286. newUIMsg.messageReceipt = uiMsg.messageReceipt;
  287. [self preProcessMessage:@[newUIMsg] callback:^{
  288. @strongify(self);
  289. NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
  290. if (index < self.uiMsgs.count) {
  291. [self.dataSource dataProviderDataSourceWillChange:self];
  292. [self replaceUIMsg:newUIMsg atIndex:index];
  293. [self.dataSource dataProviderDataSourceChange:self
  294. withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
  295. atIndex:index
  296. animation:YES];
  297. [self.dataSource dataProviderDataSourceDidChange:self];
  298. }
  299. }];
  300. return;
  301. }
  302. }
  303. }
  304. - (void)dealTypingByStatusCellData:(TUITypingStatusCellData *)stastusData {
  305. if (1 == stastusData.typingStatus) {
  306. // The timer is retimed upon receipt of the notification from the other party's input
  307. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetTypingStatus) object:nil];
  308. self.conversationModel.otherSideTyping = YES;
  309. // If the other party does not continue typing, end the status every 5 seconds
  310. [self performSelector:@selector(resetTypingStatus) withObject:nil afterDelay:5.0];
  311. } else {
  312. self.conversationModel.otherSideTyping = NO;
  313. }
  314. }
  315. - (void)resetTypingStatus {
  316. self.conversationModel.otherSideTyping = NO;
  317. }
  318. #pragma mark - Msgs
  319. - (void)loadMessageSucceedBlock:(void (^)(BOOL isFirstLoad, BOOL isNoMoreMsg, NSArray<TUIMessageCellData *> *newMsgs))succeedBlock
  320. FailBlock:(V2TIMFail)failBlock {
  321. if (self.isLoadingData || self.isNoMoreMsg) {
  322. failBlock(ERR_SUCC, @"refreshing");
  323. return;
  324. }
  325. self.isLoadingData = YES;
  326. @weakify(self);
  327. if (self.conversationModel.userID.length > 0) {
  328. [[V2TIMManager sharedInstance] getC2CHistoryMessageList:self.conversationModel.userID
  329. count:self.pageCount
  330. lastMsg:self.lastMsg
  331. succ:^(NSArray<V2TIMMessage *> *msgs) {
  332. @strongify(self);
  333. if (msgs.count != 0) {
  334. self.lastMsg = msgs[msgs.count - 1];
  335. }
  336. [self loadMessages:msgs SucceedBlock:succeedBlock];
  337. }
  338. fail:^(int code, NSString *desc) {
  339. @strongify(self);
  340. self.isLoadingData = NO;
  341. if (failBlock) {
  342. failBlock(code, desc);
  343. }
  344. }];
  345. } else if (self.conversationModel.groupID.length > 0) {
  346. [[V2TIMManager sharedInstance] getGroupHistoryMessageList:self.conversationModel.groupID
  347. count:self.pageCount
  348. lastMsg:self.lastMsg
  349. succ:^(NSArray<V2TIMMessage *> *msgs) {
  350. @strongify(self);
  351. if (msgs.count != 0) {
  352. self.lastMsg = msgs[msgs.count - 1];
  353. }
  354. [self loadMessages:msgs SucceedBlock:succeedBlock];
  355. }
  356. fail:^(int code, NSString *desc) {
  357. @strongify(self);
  358. self.isLoadingData = NO;
  359. if (failBlock) {
  360. failBlock(code, desc);
  361. }
  362. }];
  363. }
  364. }
  365. - (void)loadMessages:(NSArray<V2TIMMessage *> *)msgs
  366. SucceedBlock:(void (^)(BOOL isFirstLoad, BOOL isNoMoreMsg, NSArray<TUIMessageCellData *> *newMsgs))succeedBlock {
  367. NSMutableArray<TUIMessageCellData *> *uiMsgs = [self transUIMsgFromIMMsg:msgs];
  368. if (uiMsgs.count == 0) {
  369. return;
  370. }
  371. @weakify(self);
  372. [self preProcessMessage:uiMsgs
  373. callback:^{
  374. @strongify(self);
  375. if (msgs.count < self.pageCount) {
  376. self.isNoMoreMsg = YES;
  377. }
  378. if (uiMsgs.count != 0) {
  379. NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, uiMsgs.count)];
  380. [self insertUIMsgs:uiMsgs atIndexes:indexSet];
  381. }
  382. self.isLoadingData = NO;
  383. if (succeedBlock) {
  384. succeedBlock(self.isFirstLoad, self.isNoMoreMsg, uiMsgs);
  385. }
  386. self.isFirstLoad = NO;
  387. }];
  388. }
  389. - (void)preProcessMessage:(NSArray<TUIMessageCellData *> *)uiMsgs callback:(void (^)(void))callback {
  390. // Synchronous message processing: Messages can be preprocessed here, and complex and time-consuming operations are not recommended.
  391. [self processMessageSync:uiMsgs callback:callback];
  392. // Asynchronous processing of messages: Please handle complex time-consuming operations in this function and update them in the form of reload Cell.
  393. [self processMessageAsync:uiMsgs];
  394. }
  395. - (void)processMessageSync:(NSArray<TUIMessageCellData *> *)uiMsgs callback:(void (^)(void))callback {
  396. if (callback) {
  397. callback();
  398. }
  399. }
  400. - (void)processMessageAsync:(NSArray<TUIMessageCellData *> *)uiMsgs {
  401. __weak typeof(self) weakSelf = self;
  402. [self getReactFromMessage:uiMsgs];
  403. [self requestForAdditionalUserInfo:uiMsgs
  404. callback:^{
  405. dispatch_async(dispatch_get_main_queue(), ^{
  406. [weakSelf.dataSource dataProviderDataSourceWillChange:weakSelf];
  407. for (TUIMessageCellData *uiMsg in uiMsgs) {
  408. NSArray *userIDList = [weakSelf getUserIDListForAdditionalUserInfo:@[ uiMsg ]];
  409. if (userIDList.count == 0) {
  410. continue;
  411. }
  412. NSUInteger index = [weakSelf.uiMsgs indexOfObject:uiMsg];
  413. if (index != NSNotFound) {
  414. [weakSelf.dataSource dataProvider:weakSelf onRemoveHeightCache:uiMsg];
  415. [weakSelf.dataSource dataProviderDataSourceChange:weakSelf
  416. withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
  417. atIndex:index
  418. animation:YES];
  419. }
  420. }
  421. [weakSelf.dataSource dataProviderDataSourceDidChange:weakSelf];
  422. });
  423. [weakSelf processQuoteMessage:uiMsgs];
  424. }];
  425. }
  426. - (void)getReactFromMessage:(NSArray<TUIMessageCellData *> *)uiMsgs {
  427. if (uiMsgs.count == 0) {
  428. return;
  429. }
  430. // fetch react
  431. [[NSNotificationCenter defaultCenter] postNotificationName:@"TUIKitFetchReactNotification" object:uiMsgs];
  432. }
  433. - (void)requestForAdditionalUserInfo:(NSArray<TUIMessageCellData *> *)uiMsgs callback:(void (^)(void))callback {
  434. NSArray *userIDList = [self getUserIDListForAdditionalUserInfo:uiMsgs];
  435. if (userIDList.count == 0) {
  436. if (callback) {
  437. callback();
  438. }
  439. return;
  440. }
  441. [self requestForUserDetailsInfo:userIDList
  442. callback:^(NSDictionary<NSString *, TUIRelationUserModel *> *result) {
  443. for (TUIMessageCellData *cellData in uiMsgs) {
  444. NSMutableDictionary *additionalUserInfoResult = [NSMutableDictionary dictionary];
  445. NSArray *userIDList = [self getUserIDListForAdditionalUserInfo:@[ cellData ]];
  446. for (NSString *userID in userIDList) {
  447. TUIRelationUserModel *userInfo = [result objectForKey:userID];
  448. if (userID.length > 0 && userInfo) {
  449. additionalUserInfoResult[userID] = userInfo;
  450. }
  451. }
  452. cellData.additionalUserInfoResult = additionalUserInfoResult;
  453. }
  454. if (callback) {
  455. callback();
  456. }
  457. }];
  458. }
  459. - (void)requestForUserDetailsInfo:(NSArray *)userIDList callback:(void (^)(NSDictionary<NSString *, TUIRelationUserModel *> *))callback {
  460. if (callback == nil) {
  461. return;
  462. }
  463. NSMutableDictionary<NSString *, TUIRelationUserModel *> *result = [NSMutableDictionary dictionary];
  464. if (self.conversationModel.groupID.length > 0) {
  465. [[V2TIMManager sharedInstance] getGroupMembersInfo:self.conversationModel.groupID
  466. memberList:userIDList
  467. succ:^(NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
  468. [memberList enumerateObjectsUsingBlock:^(V2TIMGroupMemberFullInfo *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
  469. if (obj.userID.length > 0) {
  470. TUIRelationUserModel *userInfo = [[TUIRelationUserModel alloc] init];
  471. userInfo.userID = obj.userID;
  472. userInfo.nickName = obj.nickName;
  473. userInfo.friendRemark = obj.friendRemark;
  474. userInfo.nameCard = obj.nameCard;
  475. userInfo.faceURL = obj.faceURL;
  476. [result setObject:userInfo forKey:userInfo.userID];
  477. }
  478. }];
  479. callback(result);
  480. }
  481. fail:^(int code, NSString *desc) {
  482. callback(result);
  483. }];
  484. } else {
  485. [V2TIMManager.sharedInstance getFriendsInfo:userIDList
  486. succ:^(NSArray<V2TIMFriendInfoResult *> *resultList) {
  487. for (V2TIMFriendInfoResult *item in resultList) {
  488. if (item.friendInfo && item.friendInfo.userID.length > 0) {
  489. TUIRelationUserModel *userInfo = [[TUIRelationUserModel alloc] init];
  490. userInfo.userID = item.friendInfo.userID;
  491. userInfo.nickName = item.friendInfo.userFullInfo.nickName;
  492. userInfo.friendRemark = item.friendInfo.friendRemark;
  493. userInfo.faceURL = item.friendInfo.userFullInfo.faceURL;
  494. [result setObject:userInfo forKey:userInfo.userID];
  495. }
  496. }
  497. callback(result);
  498. }
  499. fail:^(int code, NSString *desc) {
  500. callback(result);
  501. }];
  502. }
  503. }
  504. - (NSArray<NSString *> *)getUserIDListForAdditionalUserInfo:(NSArray<TUIMessageCellData *> *)uiMsgs {
  505. NSMutableSet *userIDSet = [NSMutableSet set];
  506. // Built-in
  507. for (TUIMessageCellData *cellData in uiMsgs) {
  508. if (![cellData.messageModifyReplies isKindOfClass:NSArray.class] || cellData.messageModifyReplies.count == 0) {
  509. continue;
  510. }
  511. [cellData.messageModifyReplies enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
  512. if (obj && [obj isKindOfClass:NSDictionary.class]) {
  513. NSDictionary *dic = (NSDictionary *)obj;
  514. if (IS_NOT_EMPTY_NSSTRING(dic[@"messageSender"])) {
  515. [userIDSet addObject:dic[@"messageSender"]];
  516. }
  517. }
  518. }];
  519. }
  520. // Get userid from cellData which override the -requestForAdditionalUserInfo method
  521. for (TUIMessageCellData *cellData in uiMsgs) {
  522. if ([cellData respondsToSelector:@selector(requestForAdditionalUserInfo)]) {
  523. NSArray *array = [cellData requestForAdditionalUserInfo];
  524. if (array && array.count > 0) {
  525. [userIDSet addObjectsFromArray:array];
  526. }
  527. }
  528. }
  529. NSArray *userIDList = userIDSet.allObjects;
  530. return userIDList;
  531. }
  532. - (void)processQuoteMessage:(NSArray<TUIMessageCellData *> *)uiMsgs {
  533. // Subclasses implement this method
  534. return;
  535. }
  536. - (void)sendUIMsg:(TUIMessageCellData *)uiMsg
  537. toConversation:(TUIChatConversationModel *)conversationData
  538. willSendBlock:(void (^)(BOOL isReSend, TUIMessageCellData *dateUIMsg))willSendBlock
  539. SuccBlock:(nullable V2TIMSucc)succ
  540. FailBlock:(nullable V2TIMFail)fail {
  541. [self preProcessMessage:@[ uiMsg ]
  542. callback:^{
  543. [TUITool dispatchMainAsync:^{
  544. V2TIMMessage *imMsg = uiMsg.innerMessage;
  545. TUIMessageCellData *placeholderCellData = uiMsg.placeHolderCellData;
  546. TUIMessageCellData *dateMsg = nil;
  547. BOOL isReSent = NO;
  548. if (uiMsg.status == Msg_Status_Init) {
  549. // New message
  550. dateMsg = [self getSystemMsgFromDate:imMsg.timestamp];
  551. } else if (imMsg) {
  552. // Re-sent
  553. isReSent = YES;
  554. dateMsg = [self getSystemMsgFromDate:[NSDate date]];
  555. } else {
  556. if (fail) {
  557. fail(ERR_INVALID_PARAMETERS, @"Unknown message state");
  558. }
  559. return;
  560. }
  561. imMsg.isExcludedFromUnreadCount = [TUIConfig defaultConfig].isExcludedFromUnreadCount;
  562. imMsg.isExcludedFromLastMessage = [TUIConfig defaultConfig].isExcludedFromLastMessage;
  563. // Update sender
  564. uiMsg.identifier = [TUILogin getUserID];
  565. [self.dataSource dataProviderDataSourceWillChange:self];
  566. // Handle data
  567. if (isReSent) {
  568. NSInteger row = [self.uiMsgs indexOfObject:uiMsg];
  569. [self removeUImsgAtIndex:row];
  570. [self.dataSource dataProviderDataSourceChange:self
  571. withType:TUIMessageBaseDataProviderDataSourceChangeTypeDelete
  572. atIndex:row
  573. animation:YES];
  574. }
  575. if (placeholderCellData) {
  576. NSInteger row = [self.uiMsgs indexOfObject:placeholderCellData];
  577. if (row != NSNotFound) {
  578. [self replaceUIMsg:uiMsg atIndex:row];
  579. [self.dataSource dataProviderDataSourceChange:self
  580. withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
  581. atIndex:row
  582. animation:NO];
  583. }
  584. }
  585. else {
  586. if (dateMsg) {
  587. [self addUIMsg:dateMsg];
  588. [self.dataSource dataProviderDataSourceChange:self
  589. withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
  590. atIndex:(self.uiMsgs.count - 1)
  591. animation:YES];
  592. }
  593. [self addUIMsg:uiMsg];
  594. [self.dataSource dataProviderDataSourceChange:self
  595. withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
  596. atIndex:(self.uiMsgs.count - 1)
  597. animation:YES];
  598. }
  599. [self.dataSource dataProviderDataSourceDidChange:self];
  600. if (willSendBlock) {
  601. willSendBlock(isReSent, dateMsg);
  602. }
  603. if (dateMsg) {
  604. self.msgForDate = imMsg;
  605. }
  606. TUISendMessageAppendParams *appendParams = [[TUISendMessageAppendParams alloc] init];
  607. appendParams.isSendPushInfo = YES;
  608. appendParams.isOnlineUserOnly = NO;
  609. appendParams.priority = V2TIM_PRIORITY_NORMAL;
  610. uiMsg.msgID = [self.class sendMessage:imMsg
  611. toConversation:conversationData
  612. appendParams:appendParams
  613. Progress:^(uint32_t progress) {
  614. [TUIMessageProgressManager.shareManager appendUploadProgress:uiMsg.msgID progress:progress];
  615. }
  616. SuccBlock:^{
  617. [TUIMessageProgressManager.shareManager appendUploadProgress:uiMsg.msgID progress:100];
  618. if (succ) {
  619. succ();
  620. }
  621. [TUIMessageProgressManager.shareManager notifyMessageSendingResult:uiMsg.msgID result:TUIMessageSendingResultTypeSucc];
  622. }
  623. FailBlock:^(int code, NSString *desc) {
  624. if (fail) {
  625. fail(code, desc);
  626. }
  627. [TUIMessageProgressManager.shareManager notifyMessageSendingResult:uiMsg.msgID result:TUIMessageSendingResultTypeFail];
  628. }];
  629. }];
  630. }];
  631. }
  632. - (void)revokeUIMsg:(TUIMessageCellData *)uiMsg SuccBlock:(nullable V2TIMSucc)succ FailBlock:(nullable V2TIMFail)fail {
  633. V2TIMMessage *imMsg = uiMsg.innerMessage;
  634. if (imMsg == nil) {
  635. if (fail) {
  636. fail(ERR_INVALID_PARAMETERS, @"cellData.innerMessage is nil");
  637. }
  638. return;
  639. }
  640. NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
  641. if (index == NSNotFound) {
  642. if (fail) {
  643. fail(ERR_INVALID_PARAMETERS, @"not found cellData in uiMsgs");
  644. }
  645. return;
  646. }
  647. @weakify(self);
  648. [self.class revokeMessage:imMsg
  649. succ:^{
  650. @strongify(self);
  651. if (succ) {
  652. succ();
  653. }
  654. }
  655. fail:fail];
  656. }
  657. - (void)deleteUIMsgs:(NSArray<TUIMessageCellData *> *)uiMsgs SuccBlock:(nullable V2TIMSucc)succ FailBlock:(nullable V2TIMFail)fail {
  658. }
  659. - (void)addUIMsg:(TUIMessageCellData *)cellData {
  660. [self.uiMsgs_ addObject:cellData];
  661. if (self.mergeAdjacentMsgsFromTheSameSender) {
  662. [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
  663. }
  664. }
  665. - (void)removeUIMsg:(TUIMessageCellData *)cellData {
  666. if (cellData) {
  667. [self.uiMsgs_ removeObject:cellData];
  668. if ([self.dataSource respondsToSelector:@selector(dataProvider:onRemoveHeightCache:)]) {
  669. [self.dataSource dataProvider:self onRemoveHeightCache:cellData];
  670. }
  671. if (self.mergeAdjacentMsgsFromTheSameSender) {
  672. [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
  673. }
  674. }
  675. }
  676. - (void)sendPlaceHolderUIMessage:(TUIMessageCellData *)placeHolderCellData {
  677. V2TIMMessage *imMsg = placeHolderCellData.innerMessage;
  678. TUIMessageCellData *dateMsg = nil;
  679. if (placeHolderCellData.status == Msg_Status_Init) {
  680. // New message
  681. dateMsg = [self getSystemMsgFromDate:imMsg.timestamp];
  682. }
  683. [self.dataSource dataProviderDataSourceWillChange:self];
  684. if (dateMsg) {
  685. [self addUIMsg:dateMsg];
  686. [self.dataSource dataProviderDataSourceChange:self
  687. withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
  688. atIndex:(self.uiMsgs.count - 1)
  689. animation:YES];
  690. }
  691. [self addUIMsg:placeHolderCellData];
  692. [self.dataSource dataProviderDataSourceChange:self
  693. withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
  694. atIndex:(self.uiMsgs.count - 1)
  695. animation:YES];
  696. [self.dataSource dataProviderDataSourceDidChange:self];
  697. }
  698. - (void)insertUIMsgs:(NSArray<TUIMessageCellData *> *)uiMsgs atIndexes:(NSIndexSet *)indexes {
  699. [self.uiMsgs_ insertObjects:uiMsgs atIndexes:indexes];
  700. if (self.mergeAdjacentMsgsFromTheSameSender) {
  701. for (TUIMessageCellData *cellData in uiMsgs) {
  702. [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
  703. }
  704. }
  705. }
  706. - (void)addUIMsgs:(NSArray<TUIMessageCellData *> *)uiMsgs {
  707. [self.uiMsgs_ addObjectsFromArray:uiMsgs];
  708. if (self.mergeAdjacentMsgsFromTheSameSender) {
  709. for (TUIMessageCellData *cellData in uiMsgs) {
  710. [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
  711. }
  712. }
  713. }
  714. - (void)removeUIMsgList:(NSArray<TUIMessageCellData *> *)cellDatas {
  715. for (TUIMessageCellData *uiMsg in cellDatas) {
  716. [self removeUIMsg:uiMsg];
  717. }
  718. }
  719. - (void)removeUImsgAtIndex:(NSUInteger)index {
  720. if (index < self.uiMsgs.count) {
  721. TUIMessageCellData *msg = self.uiMsgs[index];
  722. [self removeUIMsg:msg];
  723. }
  724. }
  725. - (void)clearUIMsgList {
  726. NSArray *clearArray = [NSArray arrayWithArray:self.uiMsgs];
  727. [self removeUIMsgList:clearArray];
  728. self.msgForDate = nil;
  729. self.uiMsgs_ = nil;
  730. }
  731. - (void)replaceUIMsg:(TUIMessageCellData *)cellData atIndex:(NSUInteger)index {
  732. if (index < self.uiMsgs.count) {
  733. TUIMessageCellData *oldMsg = self.uiMsgs[index];
  734. if ([self.dataSource respondsToSelector:@selector(dataProvider:onRemoveHeightCache:)]) {
  735. [self.dataSource dataProvider:self onRemoveHeightCache:oldMsg];
  736. }
  737. [self.uiMsgs_ replaceObjectAtIndex:index withObject:cellData];
  738. if (self.mergeAdjacentMsgsFromTheSameSender) {
  739. [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
  740. }
  741. }
  742. }
  743. - (void)sendLatestMessageReadReceipt {
  744. [self sendMessageReadReceiptAtIndexes:@[ @(self.uiMsgs.count - 1) ]];
  745. }
  746. - (void)sendMessageReadReceiptAtIndexes:(NSArray *)indexes {
  747. if (indexes.count == 0) {
  748. NSLog(@"sendMessageReadReceipt, but indexes is empty, ignore");
  749. return;
  750. }
  751. NSMutableArray *array = [NSMutableArray array];
  752. for (NSNumber *i in indexes) {
  753. if ([i intValue] < 0 || [i intValue] >= self.uiMsgs_.count) {
  754. continue;
  755. }
  756. TUIMessageCellData *data = self.uiMsgs_[[i intValue]];
  757. if (data.innerMessage.isSelf) {
  758. continue;
  759. }
  760. if (data.innerMessage == nil) {
  761. continue;
  762. }
  763. // Use Set to avoid sending duplicate element to SDK
  764. if (data.msgID.length > 0) {
  765. if ([self.sentReadGroupMsgSet containsObject:data.msgID]) {
  766. continue;
  767. } else {
  768. [self.sentReadGroupMsgSet addObject:data.msgID];
  769. }
  770. }
  771. // If needReadReceipt is NO, receiver won't send message read receipt
  772. if (!data.innerMessage.needReadReceipt) {
  773. continue;
  774. }
  775. [array addObject:data.innerMessage];
  776. }
  777. if (array.count == 0) {
  778. return;
  779. }
  780. [self.class sendMessageReadReceipts:array];
  781. }
  782. - (NSInteger)getIndexOfMessage:(NSString *)msgID {
  783. if (msgID.length == 0) {
  784. return -1;
  785. }
  786. for (int i = 0; i < self.uiMsgs.count; i++) {
  787. TUIMessageCellData *data = self.uiMsgs[i];
  788. if ([data.msgID isEqualToString:msgID]) {
  789. return i;
  790. }
  791. }
  792. return -1;
  793. }
  794. - (nullable TUIMessageCellData *)getSystemMsgFromDate:(NSDate *)date {
  795. if (self.msgForDate == nil || fabs([date timeIntervalSinceDate:self.msgForDate.timestamp]) > MaxDateMessageDelay) {
  796. TUIMessageCellData *system = [self.class getSystemMsgFromDate:date];
  797. return system;
  798. }
  799. return nil;
  800. }
  801. + (void)updateUIMsgStatus:(TUIMessageCellData *)cellData uiMsgs:(NSArray *)uiMsgs {
  802. if (![uiMsgs containsObject:cellData]) {
  803. return;
  804. }
  805. NSInteger index = [uiMsgs indexOfObject:cellData];
  806. TUIMessageCellData *data = uiMsgs[index];
  807. TUIMessageCellData *lastData = nil;
  808. if (index >= 1) {
  809. lastData = uiMsgs[index - 1];
  810. if (![lastData isKindOfClass:[TUISystemMessageCellData class]]) {
  811. if ([lastData.identifier isEqualToString:data.identifier] &&
  812. ![data isKindOfClass:[TUISystemMessageCellData class]] &&(lastData.direction == data.direction)) {
  813. lastData.sameToNextMsgSender = YES;
  814. lastData.showAvatar = NO;
  815. } else {
  816. lastData.sameToNextMsgSender = NO;
  817. lastData.showAvatar = (lastData.direction == MsgDirectionIncoming ? YES : NO);
  818. }
  819. }
  820. }
  821. TUIMessageCellData *nextData = nil;
  822. if (index < uiMsgs.count - 1) {
  823. nextData = uiMsgs[index + 1];
  824. if ([data.identifier isEqualToString:nextData.identifier] &&(data.direction == nextData.direction)) {
  825. data.sameToNextMsgSender = YES;
  826. data.showAvatar = NO;
  827. } else {
  828. data.sameToNextMsgSender = NO;
  829. data.showAvatar = (data.direction == MsgDirectionIncoming ? YES : NO);
  830. }
  831. }
  832. if (index == uiMsgs.count - 1) {
  833. data.showAvatar = (data.direction == MsgDirectionIncoming ? YES : NO);
  834. data.sameToNextMsgSender = NO;
  835. }
  836. }
  837. - (void)getPinMessageList {
  838. if (self.conversationModel.groupID.length > 0) {
  839. __weak typeof(self) weakSelf = self;
  840. [V2TIMManager.sharedInstance getPinnedGroupMessageList:self.conversationModel.groupID succ:^(NSArray<V2TIMMessage *> *messageList) {
  841. weakSelf.groupPinList = [NSMutableArray arrayWithArray:messageList];
  842. if (weakSelf.pinGroupMessageChanged) {
  843. weakSelf.pinGroupMessageChanged(weakSelf.groupPinList);
  844. }
  845. } fail:^(int code, NSString *desc) {
  846. weakSelf.groupPinList = [NSMutableArray array];
  847. if (weakSelf.pinGroupMessageChanged) {
  848. weakSelf.pinGroupMessageChanged(weakSelf.groupPinList);
  849. }
  850. }];
  851. }
  852. }
  853. - (void)loadGroupInfo:(dispatch_block_t)callback {
  854. if (self.conversationModel.groupID.length == 0) {
  855. if (callback) {
  856. callback();
  857. }
  858. return;
  859. }
  860. __weak typeof(self) weakSelf = self;
  861. [[V2TIMManager sharedInstance] getGroupsInfo:@[ self.conversationModel.groupID ]
  862. succ:^(NSArray<V2TIMGroupInfoResult *> *groupResultList) {
  863. if (groupResultList.count == 1) {
  864. V2TIMGroupInfo *info = groupResultList[0].info;
  865. weakSelf.groupInfo = info;
  866. }
  867. if (callback) {
  868. callback();
  869. }
  870. }
  871. fail:^(int code, NSString *msg) {
  872. [TUITool makeToastError:code msg:msg];
  873. }];
  874. }
  875. - (void)getSelfInfoInGroup:(dispatch_block_t)callback {
  876. NSString *loginUserID = [[V2TIMManager sharedInstance] getLoginUser];
  877. if (loginUserID.length == 0) {
  878. if (callback) {
  879. callback();
  880. }
  881. return;
  882. }
  883. if (!self.conversationModel.enableRoom) {
  884. if (callback) {
  885. callback();
  886. }
  887. return;
  888. }
  889. __weak typeof(self) weakSelf = self;
  890. [[V2TIMManager sharedInstance] getGroupMembersInfo:self.conversationModel.groupID
  891. memberList:@[ loginUserID ]
  892. succ:^(NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
  893. for (V2TIMGroupMemberFullInfo *item in memberList) {
  894. if ([item.userID isEqualToString:loginUserID]) {
  895. weakSelf.groupSelfInfo = item;
  896. if ([weakSelf.groupInfo.owner isEqualToString:loginUserID]) {
  897. weakSelf.changedRole = V2TIM_GROUP_MEMBER_ROLE_SUPER;
  898. }
  899. else {
  900. weakSelf.changedRole = item.role;
  901. }
  902. break;
  903. }
  904. }
  905. if (callback) {
  906. callback();
  907. }
  908. }
  909. fail:^(int code, NSString *desc) {
  910. [TUITool makeToastError:code msg:desc];
  911. if (callback) {
  912. callback();
  913. }
  914. }];
  915. }
  916. - (BOOL)isCurrentUserRoleSuperAdminInGroup {
  917. if (self.changedRole != V2TIM_GROUP_MEMBER_UNDEFINED) {
  918. return (self.changedRole == V2TIM_GROUP_MEMBER_ROLE_ADMIN || self.changedRole == V2TIM_GROUP_MEMBER_ROLE_SUPER);
  919. }
  920. return ([self.groupInfo.owner isEqualToString:[[V2TIMManager sharedInstance] getLoginUser]] ||self.groupSelfInfo.role == V2TIM_GROUP_MEMBER_ROLE_ADMIN || self.groupSelfInfo.role == V2TIM_GROUP_MEMBER_ROLE_SUPER) ;
  921. }
  922. - (BOOL)isCurrentMessagePin:(NSString *)msgID {
  923. BOOL isPin = NO;
  924. for (V2TIMMessage *msg in self.groupPinList) {
  925. if ([msg.msgID isEqualToString:msgID]) {
  926. isPin = YES;
  927. break;
  928. }
  929. }
  930. return isPin;
  931. }
  932. - (void)pinGroupMessage:(NSString *)groupID
  933. message:(V2TIMMessage *)message
  934. isPinned:(BOOL)isPinned
  935. succ:(V2TIMSucc)succ
  936. fail:(V2TIMFail)fail {
  937. __weak typeof(self) weakSelf = self;
  938. [V2TIMManager.sharedInstance pinGroupMessage:groupID message:message isPinned:isPinned succ:^{
  939. if (isPinned) {
  940. //del from changed
  941. }
  942. else {
  943. //add from changed
  944. }
  945. if (succ) {
  946. succ();
  947. }
  948. } fail:^(int code, NSString *desc) {
  949. if (fail) {
  950. fail(code,desc);
  951. }
  952. }];
  953. }
  954. - (void)onGroupMessagePinned:(NSString *)groupID message:(V2TIMMessage *)message isPinned:(BOOL)isPinned opUser:(V2TIMGroupMemberInfo *)opUser {
  955. if (![groupID isEqualToString:self.conversationModel.groupID]) {
  956. return;
  957. }
  958. if (isPinned) {
  959. //add
  960. [self.groupPinList addObject:message];
  961. }
  962. else {
  963. //del
  964. NSMutableArray *formatArray = [NSMutableArray arrayWithArray:self.groupPinList];
  965. for (V2TIMMessage *msg in formatArray) {
  966. if ([msg.msgID isEqualToString:message.msgID]) {
  967. [self.groupPinList removeObject:msg];
  968. break;
  969. }
  970. }
  971. }
  972. if (self.pinGroupMessageChanged) {
  973. self.pinGroupMessageChanged(self.groupPinList);
  974. }
  975. }
  976. - (void)onGroupInfoChanged:(NSString *)groupID changeInfoList:(NSArray<V2TIMGroupChangeInfo *> *)changeInfoList {
  977. if (![groupID isEqualToString:self.conversationModel.groupID]) {
  978. return;
  979. }
  980. for (V2TIMGroupChangeInfo *changeInfo in changeInfoList) {
  981. if (changeInfo.type == V2TIM_GROUP_INFO_CHANGE_TYPE_OWNER) {
  982. NSString *ownerID = changeInfo.value;
  983. if ([ownerID isEqualToString:[TUILogin getUserID]]) {
  984. self.changedRole = V2TIM_GROUP_MEMBER_ROLE_SUPER;
  985. }
  986. else {
  987. if (self.changedRole ==V2TIM_GROUP_MEMBER_ROLE_SUPER) {
  988. self.changedRole = V2TIM_GROUP_MEMBER_ROLE_MEMBER;
  989. }
  990. }
  991. return;
  992. }
  993. }
  994. }
  995. - (void)onGrantAdministrator:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray <V2TIMGroupMemberInfo *> *)memberList {
  996. if (![groupID isEqualToString:self.conversationModel.groupID]) {
  997. return;
  998. }
  999. for (V2TIMGroupMemberInfo *changeInfo in memberList) {
  1000. if (changeInfo.userID == [TUILogin getUserID]) {
  1001. self.changedRole = V2TIM_GROUP_MEMBER_ROLE_ADMIN;
  1002. return;
  1003. }
  1004. }
  1005. }
  1006. - (void)onRevokeAdministrator:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray <V2TIMGroupMemberInfo *> *)memberList {
  1007. if (![groupID isEqualToString:self.conversationModel.groupID]) {
  1008. return;
  1009. }
  1010. for (V2TIMGroupMemberInfo *changeInfo in memberList) {
  1011. if (changeInfo.userID == [TUILogin getUserID]) {
  1012. self.changedRole = V2TIM_GROUP_MEMBER_ROLE_MEMBER;
  1013. return;
  1014. }
  1015. }
  1016. }
  1017. @end
  1018. @implementation TUIMessageBaseDataProvider (IMSDK)
  1019. static const int kOfflinePushVersion = 1;
  1020. + (NSString *)sendMessage:(V2TIMMessage *)message
  1021. toConversation:(TUIChatConversationModel *)conversationData
  1022. appendParams:(TUISendMessageAppendParams *)appendParams
  1023. Progress:(nullable V2TIMProgress)progress
  1024. SuccBlock:(nullable V2TIMSucc)succ
  1025. FailBlock:(nullable V2TIMFail)fail {
  1026. NSString *userID = conversationData.userID;
  1027. NSString *groupID = conversationData.groupID;
  1028. NSAssert(userID || groupID, @"userID and groupID cannot be null at same time");
  1029. NSString *conversationID = @"";
  1030. if (!appendParams) {
  1031. NSLog(@"appendParams cannot be nil");
  1032. }
  1033. BOOL isSendPushInfo = appendParams.isSendPushInfo;
  1034. BOOL isOnlineUserOnly = appendParams.isOnlineUserOnly;
  1035. V2TIMMessagePriority priority = appendParams.priority;
  1036. if (IS_NOT_EMPTY_NSSTRING(userID)) {
  1037. conversationID = [NSString stringWithFormat:@"c2c_%@", userID];
  1038. }
  1039. if (IS_NOT_EMPTY_NSSTRING(groupID)) {
  1040. conversationID = [NSString stringWithFormat:@"group_%@", groupID];
  1041. }
  1042. if (IS_NOT_EMPTY_NSSTRING(conversationData.conversationID)) {
  1043. conversationID = conversationData.conversationID;
  1044. }
  1045. NSParameterAssert(message);
  1046. V2TIMOfflinePushInfo *pushInfo = nil;
  1047. if (isSendPushInfo) {
  1048. pushInfo = [[V2TIMOfflinePushInfo alloc] init];
  1049. BOOL isGroup = groupID.length > 0;
  1050. NSString *senderId = isGroup ? (groupID) : ([TUILogin getUserID]);
  1051. senderId = senderId ?: @"";
  1052. NSString *nickName = isGroup ? (conversationData.title) : ([TUILogin getNickName] ?: [TUILogin getUserID]);
  1053. nickName = nickName ?: @"";
  1054. NSString * content = [self getDisplayString:message] ?: @"";
  1055. OfflinePushExtInfo *extInfo = [[OfflinePushExtInfo alloc] init];
  1056. OfflinePushExtBusinessInfo * entity = extInfo.entity;
  1057. entity.action = 1;
  1058. entity.content = content;
  1059. entity.sender = senderId;
  1060. entity.nickname = nickName;
  1061. entity.faceUrl = [TUILogin getFaceUrl] ?: @"";
  1062. entity.chatType = [isGroup ? @(V2TIM_GROUP) : @(V2TIM_C2C) integerValue];
  1063. entity.version = kOfflinePushVersion;
  1064. pushInfo.ext = [extInfo toReportExtString];
  1065. if (content.length > 0) {
  1066. pushInfo.desc = content;
  1067. }
  1068. if (nickName.length > 0) {
  1069. pushInfo.title = nickName;
  1070. }
  1071. pushInfo.AndroidOPPOChannelID = @"tuikit";
  1072. pushInfo.AndroidSound = TUIConfig.defaultConfig.enableCustomRing ? @"private_ring" : nil;
  1073. pushInfo.AndroidHuaWeiCategory = @"IM";
  1074. pushInfo.AndroidVIVOCategory = @"IM";
  1075. pushInfo.AndroidHonorImportance = @"NORMAL";
  1076. pushInfo.iOSInterruptionLevel = @"time-sensitive";
  1077. pushInfo.enableIOSBackgroundNotification = NO;
  1078. }
  1079. if ([self isGroupCommunity:conversationData.groupType groupID:conversationData.groupID] ||
  1080. [self isGroupAVChatRoom:conversationData.groupType]) {
  1081. message.needReadReceipt = NO;
  1082. }
  1083. // Hidden conversation evokes the chat page from the address book entry - to send a message, the hidden flag needs to be cleared
  1084. if (conversationID.length > 0) {
  1085. [V2TIMManager.sharedInstance markConversation:@[ conversationID ] markType:@(V2TIM_CONVERSATION_MARK_TYPE_HIDE) enableMark:NO succ:nil fail:nil];
  1086. }
  1087. if (conversationData.userID.length > 0) {
  1088. // C2C
  1089. NSDictionary *cloudCustomDataDic = @{
  1090. @"needTyping" : @1,
  1091. @"version" : @1,
  1092. };
  1093. [message setCloudCustomData:cloudCustomDataDic forType:messageFeature];
  1094. }
  1095. return [V2TIMManager.sharedInstance sendMessage:message
  1096. receiver:userID
  1097. groupID:groupID
  1098. priority:priority
  1099. onlineUserOnly:isOnlineUserOnly
  1100. offlinePushInfo:pushInfo
  1101. progress:progress
  1102. succ:^{
  1103. succ();
  1104. }
  1105. fail:^(int code, NSString *desc) {
  1106. if (code == ERR_SDK_INTERFACE_NOT_SUPPORT) {
  1107. [TUITool postUnsupportNotificationOfService:TUIKitLocalizableString(TUIKitErrorUnsupportIntefaceMessageRead)];
  1108. }
  1109. fail(code, desc);
  1110. }];
  1111. }
  1112. - (void)getLastMessage:(BOOL)isFromLocal succ:(void (^)(V2TIMMessage *message))succ fail:(V2TIMFail)fail; {
  1113. V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];
  1114. if (self.conversationModel.userID.length > 0) {
  1115. option.userID = self.conversationModel.userID;
  1116. }
  1117. if (self.conversationModel.groupID.length > 0) {
  1118. option.groupID = self.conversationModel.groupID;
  1119. }
  1120. option.getType = isFromLocal ? V2TIM_GET_LOCAL_OLDER_MSG : V2TIM_GET_CLOUD_OLDER_MSG;
  1121. option.lastMsg = nil;
  1122. option.count = 1;
  1123. [[V2TIMManager sharedInstance] getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) {
  1124. if (succ) {
  1125. succ(msgs.count > 0 ? msgs.firstObject : nil);
  1126. }
  1127. } fail:^(int code, NSString *desc) {
  1128. if (fail) {
  1129. fail(code, desc);
  1130. }
  1131. }];
  1132. }
  1133. + (BOOL)isGroupCommunity:(NSString *)groupType groupID:(NSString *)groupID {
  1134. return [groupType isEqualToString:@"Community"] || [groupID startsWith:@"@TGS#_"];
  1135. }
  1136. + (BOOL)isGroupAVChatRoom:(NSString *)groupType {
  1137. return [groupType isEqualToString:@"AVChatRoom"];
  1138. }
  1139. + (void)markC2CMessageAsRead:(NSString *)userID succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1140. NSString * conversationID = [NSString stringWithFormat:@"c2c_%@",userID];
  1141. [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:succ fail:fail];
  1142. }
  1143. + (void)markGroupMessageAsRead:(NSString *)groupID succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1144. NSString * conversationID = [NSString stringWithFormat:@"group_%@",groupID];
  1145. [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:succ fail:fail];
  1146. }
  1147. + (void)markConversationAsUndead:(NSArray<NSString *> *)conversationIDList enableMark:(BOOL)enableMark {
  1148. [V2TIMManager.sharedInstance markConversation:conversationIDList markType:@(V2TIM_CONVERSATION_MARK_TYPE_UNREAD) enableMark:enableMark succ:nil fail:nil];
  1149. }
  1150. + (void)revokeMessage:(V2TIMMessage *)msg succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1151. [[V2TIMManager sharedInstance] revokeMessage:msg succ:succ fail:fail];
  1152. }
  1153. + (void)deleteMessages:(NSArray<V2TIMMessage *> *)msgList succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1154. [[V2TIMManager sharedInstance] deleteMessages:msgList succ:succ fail:fail];
  1155. }
  1156. + (void)modifyMessage:(V2TIMMessage *)msg completion:(V2TIMMessageModifyCompletion)completion {
  1157. [[V2TIMManager sharedInstance] modifyMessage:msg completion:completion];
  1158. }
  1159. + (void)sendMessageReadReceipts:(NSArray *)msgs {
  1160. [[V2TIMManager sharedInstance] sendMessageReadReceipts:msgs
  1161. succ:^{
  1162. NSLog(@"sendMessageReadReceipts succeed");
  1163. }
  1164. fail:^(int code, NSString *desc) {
  1165. if (code == ERR_SDK_INTERFACE_NOT_SUPPORT) {
  1166. [TUITool postUnsupportNotificationOfService:TUIKitLocalizableString(TUIKitErrorUnsupportIntefaceMessageRead)];
  1167. }
  1168. }];
  1169. }
  1170. + (void)getReadMembersOfMessage:(V2TIMMessage *)msg
  1171. filter:(V2TIMGroupMessageReadMembersFilter)filter
  1172. nextSeq:(NSUInteger)nextSeq
  1173. completion:(void (^)(int code, NSString *desc, NSArray *members, NSUInteger nextSeq, BOOL isFinished))block {
  1174. [[V2TIMManager sharedInstance] getGroupMessageReadMemberList:msg
  1175. filter:filter
  1176. nextSeq:nextSeq
  1177. count:100
  1178. succ:^(NSMutableArray<V2TIMGroupMemberInfo *> *members, uint64_t nextSeq, BOOL isFinished) {
  1179. if (block) {
  1180. block(0, nil, members, nextSeq, isFinished);
  1181. }
  1182. }
  1183. fail:^(int code, NSString *desc) {
  1184. if (block) {
  1185. block(code, desc, nil, 0, NO);
  1186. }
  1187. }];
  1188. }
  1189. + (void)getMessageReadReceipt:(NSArray *)messages succ:(nullable V2TIMMessageReadReceiptsSucc)succ fail:(nullable V2TIMFail)fail {
  1190. if (messages.count == 0) {
  1191. if (fail) {
  1192. fail(-1, @"messages empty");
  1193. }
  1194. return;
  1195. }
  1196. [[V2TIMManager sharedInstance] getMessageReadReceipts:messages succ:succ fail:fail];
  1197. }
  1198. + (TUIMessageCellData *__nullable)getCellData:(V2TIMMessage *)message {
  1199. // subclass override required
  1200. return nil;
  1201. }
  1202. + (nullable TUIMessageCellData *)getSystemMsgFromDate:(NSDate *)date {
  1203. // subclass override required
  1204. return nil;
  1205. }
  1206. + (TUIMessageCellData *)getRevokeCellData:(V2TIMMessage *)message {
  1207. // subclass override required
  1208. return nil;
  1209. }
  1210. + (nullable NSString *)getDisplayString:(V2TIMMessage *)message {
  1211. // subclass override required
  1212. return nil;
  1213. }
  1214. + (NSString *)getRevokeDispayString:(V2TIMMessage *)message {
  1215. return [self getRevokeDispayString:message operateUser:nil reason:nil];
  1216. }
  1217. + (NSString *)getRevokeDispayString:(V2TIMMessage *)message operateUser:(V2TIMUserFullInfo *)operateUser reason:(NSString *)reason {
  1218. V2TIMUserFullInfo *revokerInfo = message.revokerInfo ? message.revokerInfo : operateUser;
  1219. BOOL hasRiskContent = message.hasRiskContent;
  1220. NSString *revoker = message.sender;
  1221. NSString *messageSender = message.sender;
  1222. if (revokerInfo) {
  1223. revoker = revokerInfo.userID;
  1224. }
  1225. NSString *content = TIMCommonLocalizableString(TUIKitMessageTipsNormalRecallMessage);
  1226. if ([revoker isEqualToString:messageSender]) {
  1227. if (message.isSelf) {
  1228. content = TIMCommonLocalizableString(TUIKitMessageTipsYouRecallMessage);
  1229. } else {
  1230. if (message.userID.length > 0) {
  1231. // c2c
  1232. content = TIMCommonLocalizableString(TUIKitMessageTipsOthersRecallMessage);
  1233. } else if (message.groupID.length > 0) {
  1234. NSString *userName = [self.class getShowName:message];
  1235. content = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
  1236. } else {
  1237. // empty
  1238. }
  1239. }
  1240. } else {
  1241. NSString *userName = [self.class getShowName:message];
  1242. if (revokerInfo) {
  1243. userName = revokerInfo.showName;
  1244. }
  1245. content = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
  1246. }
  1247. return rtlString(content);
  1248. }
  1249. + (NSString *)getGroupTipsDisplayString:(V2TIMMessage *)message {
  1250. V2TIMGroupTipsElem *tips = message.groupTipsElem;
  1251. NSString *opUser = [self getOpUserName:tips.opMember];
  1252. NSMutableArray<NSString *> *userList = [self getUserNameList:tips.memberList];
  1253. NSString *str = nil;
  1254. switch (tips.type) {
  1255. case V2TIM_GROUP_TIPS_TYPE_JOIN: {
  1256. if (opUser.length > 0) {
  1257. if ((userList.count == 0) || (userList.count == 1 && [opUser isEqualToString:userList.firstObject])) {
  1258. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsJoinGroupFormat), opUser];
  1259. } else {
  1260. NSString *users = [userList componentsJoinedByString:@"、"];
  1261. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsInviteJoinGroupFormat), opUser, users];
  1262. }
  1263. }
  1264. } break;
  1265. case V2TIM_GROUP_TIPS_TYPE_INVITE: {
  1266. if (userList.count > 0) {
  1267. NSString *users = [userList componentsJoinedByString:@"、"];
  1268. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsInviteJoinGroupFormat), opUser, users];
  1269. }
  1270. } break;
  1271. case V2TIM_GROUP_TIPS_TYPE_QUIT: {
  1272. if (opUser.length > 0) {
  1273. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsLeaveGroupFormat), opUser];
  1274. }
  1275. } break;
  1276. case V2TIM_GROUP_TIPS_TYPE_KICKED: {
  1277. if (userList.count > 0) {
  1278. NSString *users = [userList componentsJoinedByString:@"、"];
  1279. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsKickoffGroupFormat), opUser, users];
  1280. }
  1281. } break;
  1282. case V2TIM_GROUP_TIPS_TYPE_SET_ADMIN: {
  1283. if (userList.count > 0) {
  1284. NSString *users = [userList componentsJoinedByString:@"、"];
  1285. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsSettAdminFormat), users];
  1286. }
  1287. } break;
  1288. case V2TIM_GROUP_TIPS_TYPE_CANCEL_ADMIN: {
  1289. if (userList.count > 0) {
  1290. NSString *users = [userList componentsJoinedByString:@"、"];
  1291. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsCancelAdminFormat), users];
  1292. }
  1293. } break;
  1294. case V2TIM_GROUP_TIPS_TYPE_GROUP_INFO_CHANGE: {
  1295. str = [self opGroupInfoChagedFormatStr:opUser ofUserList:userList ofTips:tips];
  1296. if (str.length > 0) {
  1297. str = [str substringToIndex:str.length - 1];
  1298. }
  1299. } break;
  1300. case V2TIM_GROUP_TIPS_TYPE_MEMBER_INFO_CHANGE: {
  1301. for (V2TIMGroupChangeInfo *info in tips.memberChangeInfoList) {
  1302. if ([info isKindOfClass:V2TIMGroupMemberChangeInfo.class]) {
  1303. NSString *userId = [(V2TIMGroupMemberChangeInfo *)info userID];
  1304. int32_t muteTime = [(V2TIMGroupMemberChangeInfo *)info muteTime];
  1305. NSString *myId = V2TIMManager.sharedInstance.getLoginUser;
  1306. NSString *showName = [self.class getUserName:tips with:userId];
  1307. str = [NSString stringWithFormat:@"%@ %@", [userId isEqualToString:myId] ? TIMCommonLocalizableString(You) : showName,
  1308. muteTime == 0 ? TIMCommonLocalizableString(TUIKitMessageTipsUnmute)
  1309. : TIMCommonLocalizableString(TUIKitMessageTipsMute)];
  1310. break;
  1311. }
  1312. }
  1313. } break;
  1314. case V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_ADDED: {
  1315. if (opUser.length > 0) {
  1316. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsGroupPinMessage), opUser];
  1317. }
  1318. }
  1319. break;
  1320. case V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_DELETED: {
  1321. if (opUser.length > 0) {
  1322. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsGroupUnPinMessage), opUser];
  1323. }
  1324. }
  1325. break;
  1326. default:
  1327. break;
  1328. }
  1329. return rtlString(str);
  1330. }
  1331. + (V2TIMMessage *)getCustomMessageWithJsonData:(NSData *)data {
  1332. return [[V2TIMManager sharedInstance] createCustomMessage:data];
  1333. }
  1334. + (V2TIMMessage *)getCustomMessageWithJsonData:(NSData *)data desc:(NSString *)desc extension:(NSString *)extension {
  1335. return [[V2TIMManager sharedInstance] createCustomMessage:data desc:desc extension:extension];
  1336. }
  1337. + (NSString *)opGroupInfoChagedFormatStr:(NSString *)opUser ofUserList:(NSMutableArray<NSString *> *)userList ofTips:(V2TIMGroupTipsElem *)tips{
  1338. NSString *str = nil;
  1339. str = [NSString stringWithFormat:@"%@", opUser];
  1340. for (V2TIMGroupChangeInfo *info in tips.groupChangeInfoList) {
  1341. switch (info.type) {
  1342. case V2TIM_GROUP_INFO_CHANGE_TYPE_NAME: {
  1343. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIkitMessageTipsEditGroupNameFormat), str, info.value];
  1344. } break;
  1345. case V2TIM_GROUP_INFO_CHANGE_TYPE_INTRODUCTION: {
  1346. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupIntroFormat), str, info.value];
  1347. } break;
  1348. case V2TIM_GROUP_INFO_CHANGE_TYPE_NOTIFICATION: {
  1349. if (info.value.length) {
  1350. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAnnounceFormat), str, info.value];
  1351. } else {
  1352. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsDeleteGroupAnnounceFormat), str];
  1353. }
  1354. } break;
  1355. case V2TIM_GROUP_INFO_CHANGE_TYPE_FACE: {
  1356. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAvatarFormat), str];
  1357. } break;
  1358. case V2TIM_GROUP_INFO_CHANGE_TYPE_OWNER: {
  1359. if (userList.count) {
  1360. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupOwnerFormat), str, userList.firstObject];
  1361. } else {
  1362. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupOwnerFormat), str, info.value];
  1363. }
  1364. } break;
  1365. case V2TIM_GROUP_INFO_CHANGE_TYPE_SHUT_UP_ALL: {
  1366. if (info.boolValue) {
  1367. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSetShutupAllFormat), opUser];
  1368. } else {
  1369. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitCancelShutupAllFormat), opUser];
  1370. }
  1371. } break;
  1372. case V2TIM_GROUP_INFO_CHANGE_TYPE_GROUP_ADD_OPT: {
  1373. uint32_t addOpt = info.intValue;
  1374. NSString *addOptDesc = @"unknown";
  1375. if (addOpt == V2TIM_GROUP_ADD_FORBID) {
  1376. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileJoinDisable);
  1377. } else if (addOpt == V2TIM_GROUP_ADD_AUTH) {
  1378. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAdminApprove);
  1379. } else if (addOpt == V2TIM_GROUP_ADD_ANY) {
  1380. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAutoApproval);
  1381. }
  1382. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAddOptFormat), str, addOptDesc];
  1383. } break;
  1384. case V2TIM_GROUP_INFO_CHANGE_TYPE_GROUP_APPROVE_OPT: {
  1385. uint32_t addOpt = info.intValue;
  1386. NSString *addOptDesc = @"unknown";
  1387. if (addOpt == V2TIM_GROUP_ADD_FORBID) {
  1388. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileInviteDisable);
  1389. } else if (addOpt == V2TIM_GROUP_ADD_AUTH) {
  1390. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAdminApprove);
  1391. } else if (addOpt == V2TIM_GROUP_ADD_ANY) {
  1392. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAutoApproval);
  1393. }
  1394. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupInviteOptFormat), str, addOptDesc];
  1395. } break;
  1396. default:
  1397. break;
  1398. }
  1399. }
  1400. return rtlString(str);
  1401. }
  1402. + (NSString *)getOpUserName:(V2TIMGroupMemberInfo *)info {
  1403. NSString *opUser;
  1404. if (info.nameCard.length > 0) {
  1405. opUser = info.nameCard;
  1406. } else if (info.nickName.length > 0) {
  1407. opUser = info.nickName;
  1408. } else {
  1409. opUser = info.userID;
  1410. }
  1411. return opUser;
  1412. }
  1413. + (NSMutableArray *)getUserNameList:(NSArray<V2TIMGroupMemberInfo *> *)infoList {
  1414. NSMutableArray<NSString *> *userNameList = [NSMutableArray array];
  1415. for (V2TIMGroupMemberInfo *info in infoList) {
  1416. if (info.nameCard.length > 0) {
  1417. [userNameList addObject:info.nameCard];
  1418. } else if (info.nickName.length > 0) {
  1419. [userNameList addObject:info.nickName];
  1420. } else {
  1421. if (info.userID.length > 0) {
  1422. [userNameList addObject:info.userID];
  1423. }
  1424. }
  1425. }
  1426. return userNameList;
  1427. }
  1428. + (NSMutableArray *)getUserIDList:(NSArray<V2TIMGroupMemberInfo *> *)infoList {
  1429. NSMutableArray<NSString *> *userIDList = [NSMutableArray array];
  1430. for (V2TIMGroupMemberInfo *info in infoList) {
  1431. if (info.userID.length > 0) {
  1432. [userIDList addObject:info.userID];
  1433. }
  1434. }
  1435. return userIDList;
  1436. }
  1437. + (NSString *)getShowName:(V2TIMMessage *)message {
  1438. NSString *showName = message.sender;
  1439. if (message.nameCard.length > 0) {
  1440. showName = message.nameCard;
  1441. } else if (message.friendRemark.length > 0) {
  1442. showName = message.friendRemark;
  1443. } else if (message.nickName.length > 0) {
  1444. showName = message.nickName;
  1445. }
  1446. return showName;
  1447. }
  1448. + (NSString *)getUserName:(V2TIMGroupTipsElem *)tips with:(NSString *)userId {
  1449. NSString *str = @"";
  1450. for (V2TIMGroupMemberInfo *info in tips.memberList) {
  1451. if ([info.userID isEqualToString:userId]) {
  1452. if (info.nameCard.length > 0) {
  1453. str = info.nameCard;
  1454. } else if (info.friendRemark.length > 0) {
  1455. str = info.friendRemark;
  1456. } else if (info.nickName.length > 0) {
  1457. str = info.nickName;
  1458. } else {
  1459. str = userId;
  1460. }
  1461. break;
  1462. }
  1463. }
  1464. return str;
  1465. }
  1466. @end