TUIMessageBaseDataProvider.m 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  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. [[NSNotificationCenter defaultCenter] postNotificationName:@"kNotification_SendMessage" object:nil];
  1105. }
  1106. fail:^(int code, NSString *desc) {
  1107. if (code == ERR_SDK_INTERFACE_NOT_SUPPORT) {
  1108. [TUITool postUnsupportNotificationOfService:TUIKitLocalizableString(TUIKitErrorUnsupportIntefaceMessageRead)];
  1109. }
  1110. fail(code, desc);
  1111. }];
  1112. }
  1113. - (void)getLastMessage:(BOOL)isFromLocal succ:(void (^)(V2TIMMessage *message))succ fail:(V2TIMFail)fail; {
  1114. V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];
  1115. if (self.conversationModel.userID.length > 0) {
  1116. option.userID = self.conversationModel.userID;
  1117. }
  1118. if (self.conversationModel.groupID.length > 0) {
  1119. option.groupID = self.conversationModel.groupID;
  1120. }
  1121. option.getType = isFromLocal ? V2TIM_GET_LOCAL_OLDER_MSG : V2TIM_GET_CLOUD_OLDER_MSG;
  1122. option.lastMsg = nil;
  1123. option.count = 1;
  1124. [[V2TIMManager sharedInstance] getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) {
  1125. if (succ) {
  1126. succ(msgs.count > 0 ? msgs.firstObject : nil);
  1127. }
  1128. } fail:^(int code, NSString *desc) {
  1129. if (fail) {
  1130. fail(code, desc);
  1131. }
  1132. }];
  1133. }
  1134. + (BOOL)isGroupCommunity:(NSString *)groupType groupID:(NSString *)groupID {
  1135. return [groupType isEqualToString:@"Community"] || [groupID startsWith:@"@TGS#_"];
  1136. }
  1137. + (BOOL)isGroupAVChatRoom:(NSString *)groupType {
  1138. return [groupType isEqualToString:@"AVChatRoom"];
  1139. }
  1140. + (void)markC2CMessageAsRead:(NSString *)userID succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1141. NSString * conversationID = [NSString stringWithFormat:@"c2c_%@",userID];
  1142. [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:succ fail:fail];
  1143. }
  1144. + (void)markGroupMessageAsRead:(NSString *)groupID succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1145. NSString * conversationID = [NSString stringWithFormat:@"group_%@",groupID];
  1146. [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:succ fail:fail];
  1147. }
  1148. + (void)markConversationAsUndead:(NSArray<NSString *> *)conversationIDList enableMark:(BOOL)enableMark {
  1149. [V2TIMManager.sharedInstance markConversation:conversationIDList markType:@(V2TIM_CONVERSATION_MARK_TYPE_UNREAD) enableMark:enableMark succ:nil fail:nil];
  1150. }
  1151. + (void)revokeMessage:(V2TIMMessage *)msg succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1152. [[V2TIMManager sharedInstance] revokeMessage:msg succ:succ fail:fail];
  1153. }
  1154. + (void)deleteMessages:(NSArray<V2TIMMessage *> *)msgList succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
  1155. [[V2TIMManager sharedInstance] deleteMessages:msgList succ:succ fail:fail];
  1156. }
  1157. + (void)modifyMessage:(V2TIMMessage *)msg completion:(V2TIMMessageModifyCompletion)completion {
  1158. [[V2TIMManager sharedInstance] modifyMessage:msg completion:completion];
  1159. }
  1160. + (void)sendMessageReadReceipts:(NSArray *)msgs {
  1161. [[V2TIMManager sharedInstance] sendMessageReadReceipts:msgs
  1162. succ:^{
  1163. NSLog(@"sendMessageReadReceipts succeed");
  1164. }
  1165. fail:^(int code, NSString *desc) {
  1166. if (code == ERR_SDK_INTERFACE_NOT_SUPPORT) {
  1167. [TUITool postUnsupportNotificationOfService:TUIKitLocalizableString(TUIKitErrorUnsupportIntefaceMessageRead)];
  1168. }
  1169. }];
  1170. }
  1171. + (void)getReadMembersOfMessage:(V2TIMMessage *)msg
  1172. filter:(V2TIMGroupMessageReadMembersFilter)filter
  1173. nextSeq:(NSUInteger)nextSeq
  1174. completion:(void (^)(int code, NSString *desc, NSArray *members, NSUInteger nextSeq, BOOL isFinished))block {
  1175. [[V2TIMManager sharedInstance] getGroupMessageReadMemberList:msg
  1176. filter:filter
  1177. nextSeq:nextSeq
  1178. count:100
  1179. succ:^(NSMutableArray<V2TIMGroupMemberInfo *> *members, uint64_t nextSeq, BOOL isFinished) {
  1180. if (block) {
  1181. block(0, nil, members, nextSeq, isFinished);
  1182. }
  1183. }
  1184. fail:^(int code, NSString *desc) {
  1185. if (block) {
  1186. block(code, desc, nil, 0, NO);
  1187. }
  1188. }];
  1189. }
  1190. + (void)getMessageReadReceipt:(NSArray *)messages succ:(nullable V2TIMMessageReadReceiptsSucc)succ fail:(nullable V2TIMFail)fail {
  1191. if (messages.count == 0) {
  1192. if (fail) {
  1193. fail(-1, @"messages empty");
  1194. }
  1195. return;
  1196. }
  1197. [[V2TIMManager sharedInstance] getMessageReadReceipts:messages succ:succ fail:fail];
  1198. }
  1199. + (TUIMessageCellData *__nullable)getCellData:(V2TIMMessage *)message {
  1200. // subclass override required
  1201. return nil;
  1202. }
  1203. + (nullable TUIMessageCellData *)getSystemMsgFromDate:(NSDate *)date {
  1204. // subclass override required
  1205. return nil;
  1206. }
  1207. + (TUIMessageCellData *)getRevokeCellData:(V2TIMMessage *)message {
  1208. // subclass override required
  1209. return nil;
  1210. }
  1211. + (nullable NSString *)getDisplayString:(V2TIMMessage *)message {
  1212. // subclass override required
  1213. return nil;
  1214. }
  1215. + (NSString *)getRevokeDispayString:(V2TIMMessage *)message {
  1216. return [self getRevokeDispayString:message operateUser:nil reason:nil];
  1217. }
  1218. + (NSString *)getRevokeDispayString:(V2TIMMessage *)message operateUser:(V2TIMUserFullInfo *)operateUser reason:(NSString *)reason {
  1219. V2TIMUserFullInfo *revokerInfo = message.revokerInfo ? message.revokerInfo : operateUser;
  1220. BOOL hasRiskContent = message.hasRiskContent;
  1221. NSString *revoker = message.sender;
  1222. NSString *messageSender = message.sender;
  1223. if (revokerInfo) {
  1224. revoker = revokerInfo.userID;
  1225. }
  1226. NSString *content = TIMCommonLocalizableString(TUIKitMessageTipsNormalRecallMessage);
  1227. if ([revoker isEqualToString:messageSender]) {
  1228. if (message.isSelf) {
  1229. content = TIMCommonLocalizableString(TUIKitMessageTipsYouRecallMessage);
  1230. } else {
  1231. if (message.userID.length > 0) {
  1232. // c2c
  1233. content = TIMCommonLocalizableString(TUIKitMessageTipsOthersRecallMessage);
  1234. } else if (message.groupID.length > 0) {
  1235. NSString *userName = [self.class getShowName:message];
  1236. content = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
  1237. } else {
  1238. // empty
  1239. }
  1240. }
  1241. } else {
  1242. NSString *userName = [self.class getShowName:message];
  1243. if (revokerInfo) {
  1244. userName = revokerInfo.showName;
  1245. }
  1246. content = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
  1247. }
  1248. return rtlString(content);
  1249. }
  1250. + (NSString *)getGroupTipsDisplayString:(V2TIMMessage *)message {
  1251. V2TIMGroupTipsElem *tips = message.groupTipsElem;
  1252. NSString *opUser = [self getOpUserName:tips.opMember];
  1253. NSMutableArray<NSString *> *userList = [self getUserNameList:tips.memberList];
  1254. NSString *str = nil;
  1255. switch (tips.type) {
  1256. case V2TIM_GROUP_TIPS_TYPE_JOIN: {
  1257. if (opUser.length > 0) {
  1258. if ((userList.count == 0) || (userList.count == 1 && [opUser isEqualToString:userList.firstObject])) {
  1259. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsJoinGroupFormat), opUser];
  1260. } else {
  1261. NSString *users = [userList componentsJoinedByString:@"、"];
  1262. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsInviteJoinGroupFormat), opUser, users];
  1263. }
  1264. }
  1265. } break;
  1266. case V2TIM_GROUP_TIPS_TYPE_INVITE: {
  1267. if (userList.count > 0) {
  1268. NSString *users = [userList componentsJoinedByString:@"、"];
  1269. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsInviteJoinGroupFormat), opUser, users];
  1270. }
  1271. } break;
  1272. case V2TIM_GROUP_TIPS_TYPE_QUIT: {
  1273. if (opUser.length > 0) {
  1274. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsLeaveGroupFormat), opUser];
  1275. }
  1276. } break;
  1277. case V2TIM_GROUP_TIPS_TYPE_KICKED: {
  1278. if (userList.count > 0) {
  1279. NSString *users = [userList componentsJoinedByString:@"、"];
  1280. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsKickoffGroupFormat), opUser, users];
  1281. }
  1282. } break;
  1283. case V2TIM_GROUP_TIPS_TYPE_SET_ADMIN: {
  1284. if (userList.count > 0) {
  1285. NSString *users = [userList componentsJoinedByString:@"、"];
  1286. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsSettAdminFormat), users];
  1287. }
  1288. } break;
  1289. case V2TIM_GROUP_TIPS_TYPE_CANCEL_ADMIN: {
  1290. if (userList.count > 0) {
  1291. NSString *users = [userList componentsJoinedByString:@"、"];
  1292. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsCancelAdminFormat), users];
  1293. }
  1294. } break;
  1295. case V2TIM_GROUP_TIPS_TYPE_GROUP_INFO_CHANGE: {
  1296. str = [self opGroupInfoChagedFormatStr:opUser ofUserList:userList ofTips:tips];
  1297. if (str.length > 0) {
  1298. str = [str substringToIndex:str.length - 1];
  1299. }
  1300. } break;
  1301. case V2TIM_GROUP_TIPS_TYPE_MEMBER_INFO_CHANGE: {
  1302. for (V2TIMGroupChangeInfo *info in tips.memberChangeInfoList) {
  1303. if ([info isKindOfClass:V2TIMGroupMemberChangeInfo.class]) {
  1304. NSString *userId = [(V2TIMGroupMemberChangeInfo *)info userID];
  1305. int32_t muteTime = [(V2TIMGroupMemberChangeInfo *)info muteTime];
  1306. NSString *myId = V2TIMManager.sharedInstance.getLoginUser;
  1307. NSString *showName = [self.class getUserName:tips with:userId];
  1308. str = [NSString stringWithFormat:@"%@ %@", [userId isEqualToString:myId] ? TIMCommonLocalizableString(You) : showName,
  1309. muteTime == 0 ? TIMCommonLocalizableString(TUIKitMessageTipsUnmute)
  1310. : TIMCommonLocalizableString(TUIKitMessageTipsMute)];
  1311. break;
  1312. }
  1313. }
  1314. } break;
  1315. case V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_ADDED: {
  1316. if (opUser.length > 0) {
  1317. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsGroupPinMessage), opUser];
  1318. }
  1319. }
  1320. break;
  1321. case V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_DELETED: {
  1322. if (opUser.length > 0) {
  1323. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsGroupUnPinMessage), opUser];
  1324. }
  1325. }
  1326. break;
  1327. default:
  1328. break;
  1329. }
  1330. return rtlString(str);
  1331. }
  1332. + (V2TIMMessage *)getCustomMessageWithJsonData:(NSData *)data {
  1333. return [[V2TIMManager sharedInstance] createCustomMessage:data];
  1334. }
  1335. + (V2TIMMessage *)getCustomMessageWithJsonData:(NSData *)data desc:(NSString *)desc extension:(NSString *)extension {
  1336. return [[V2TIMManager sharedInstance] createCustomMessage:data desc:desc extension:extension];
  1337. }
  1338. + (NSString *)opGroupInfoChagedFormatStr:(NSString *)opUser ofUserList:(NSMutableArray<NSString *> *)userList ofTips:(V2TIMGroupTipsElem *)tips{
  1339. NSString *str = nil;
  1340. str = [NSString stringWithFormat:@"%@", opUser];
  1341. for (V2TIMGroupChangeInfo *info in tips.groupChangeInfoList) {
  1342. switch (info.type) {
  1343. case V2TIM_GROUP_INFO_CHANGE_TYPE_NAME: {
  1344. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIkitMessageTipsEditGroupNameFormat), str, info.value];
  1345. } break;
  1346. case V2TIM_GROUP_INFO_CHANGE_TYPE_INTRODUCTION: {
  1347. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupIntroFormat), str, info.value];
  1348. } break;
  1349. case V2TIM_GROUP_INFO_CHANGE_TYPE_NOTIFICATION: {
  1350. if (info.value.length) {
  1351. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAnnounceFormat), str, info.value];
  1352. } else {
  1353. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsDeleteGroupAnnounceFormat), str];
  1354. }
  1355. } break;
  1356. case V2TIM_GROUP_INFO_CHANGE_TYPE_FACE: {
  1357. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAvatarFormat), str];
  1358. } break;
  1359. case V2TIM_GROUP_INFO_CHANGE_TYPE_OWNER: {
  1360. if (userList.count) {
  1361. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupOwnerFormat), str, userList.firstObject];
  1362. } else {
  1363. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupOwnerFormat), str, info.value];
  1364. }
  1365. } break;
  1366. case V2TIM_GROUP_INFO_CHANGE_TYPE_SHUT_UP_ALL: {
  1367. if (info.boolValue) {
  1368. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSetShutupAllFormat), opUser];
  1369. } else {
  1370. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitCancelShutupAllFormat), opUser];
  1371. }
  1372. } break;
  1373. case V2TIM_GROUP_INFO_CHANGE_TYPE_GROUP_ADD_OPT: {
  1374. uint32_t addOpt = info.intValue;
  1375. NSString *addOptDesc = @"unknown";
  1376. if (addOpt == V2TIM_GROUP_ADD_FORBID) {
  1377. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileJoinDisable);
  1378. } else if (addOpt == V2TIM_GROUP_ADD_AUTH) {
  1379. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAdminApprove);
  1380. } else if (addOpt == V2TIM_GROUP_ADD_ANY) {
  1381. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAutoApproval);
  1382. }
  1383. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAddOptFormat), str, addOptDesc];
  1384. } break;
  1385. case V2TIM_GROUP_INFO_CHANGE_TYPE_GROUP_APPROVE_OPT: {
  1386. uint32_t addOpt = info.intValue;
  1387. NSString *addOptDesc = @"unknown";
  1388. if (addOpt == V2TIM_GROUP_ADD_FORBID) {
  1389. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileInviteDisable);
  1390. } else if (addOpt == V2TIM_GROUP_ADD_AUTH) {
  1391. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAdminApprove);
  1392. } else if (addOpt == V2TIM_GROUP_ADD_ANY) {
  1393. addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAutoApproval);
  1394. }
  1395. str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupInviteOptFormat), str, addOptDesc];
  1396. } break;
  1397. default:
  1398. break;
  1399. }
  1400. }
  1401. return rtlString(str);
  1402. }
  1403. + (NSString *)getOpUserName:(V2TIMGroupMemberInfo *)info {
  1404. NSString *opUser;
  1405. if (info.nameCard.length > 0) {
  1406. opUser = info.nameCard;
  1407. } else if (info.nickName.length > 0) {
  1408. opUser = info.nickName;
  1409. } else {
  1410. opUser = info.userID;
  1411. }
  1412. return opUser;
  1413. }
  1414. + (NSMutableArray *)getUserNameList:(NSArray<V2TIMGroupMemberInfo *> *)infoList {
  1415. NSMutableArray<NSString *> *userNameList = [NSMutableArray array];
  1416. for (V2TIMGroupMemberInfo *info in infoList) {
  1417. if (info.nameCard.length > 0) {
  1418. [userNameList addObject:info.nameCard];
  1419. } else if (info.nickName.length > 0) {
  1420. [userNameList addObject:info.nickName];
  1421. } else {
  1422. if (info.userID.length > 0) {
  1423. [userNameList addObject:info.userID];
  1424. }
  1425. }
  1426. }
  1427. return userNameList;
  1428. }
  1429. + (NSMutableArray *)getUserIDList:(NSArray<V2TIMGroupMemberInfo *> *)infoList {
  1430. NSMutableArray<NSString *> *userIDList = [NSMutableArray array];
  1431. for (V2TIMGroupMemberInfo *info in infoList) {
  1432. if (info.userID.length > 0) {
  1433. [userIDList addObject:info.userID];
  1434. }
  1435. }
  1436. return userIDList;
  1437. }
  1438. + (NSString *)getShowName:(V2TIMMessage *)message {
  1439. NSString *showName = message.sender;
  1440. if (message.nameCard.length > 0) {
  1441. showName = message.nameCard;
  1442. } else if (message.friendRemark.length > 0) {
  1443. showName = message.friendRemark;
  1444. } else if (message.nickName.length > 0) {
  1445. showName = message.nickName;
  1446. }
  1447. return showName;
  1448. }
  1449. + (NSString *)getUserName:(V2TIMGroupTipsElem *)tips with:(NSString *)userId {
  1450. NSString *str = @"";
  1451. for (V2TIMGroupMemberInfo *info in tips.memberList) {
  1452. if ([info.userID isEqualToString:userId]) {
  1453. if (info.nameCard.length > 0) {
  1454. str = info.nameCard;
  1455. } else if (info.friendRemark.length > 0) {
  1456. str = info.friendRemark;
  1457. } else if (info.nickName.length > 0) {
  1458. str = info.nickName;
  1459. } else {
  1460. str = userId;
  1461. }
  1462. break;
  1463. }
  1464. }
  1465. return str;
  1466. }
  1467. @end