| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617 |
- // Created by Tencent on 2023/06/09.
- // Copyright © 2023 Tencent. All rights reserved.
- #import <AVFoundation/AVFoundation.h>
- #import <TIMCommon/NSString+TUIEmoji.h>
- #import <TIMCommon/TIMDefine.h>
- #import <TIMCommon/TUIMessageCell.h>
- #import <TIMCommon/TUISystemMessageCellData.h>
- #import <TIMCommon/TUIRelationUserModel.h>
- #import <TUICore/NSString+TUIUtil.h>
- #import <TUICore/TUICore.h>
- #import <TUICore/TUILogin.h>
- #import <TUICore/TUITool.h>
- #import <TUICore/OfflinePushExtInfo.h>
- #import "TUIChatConfig.h"
- #import "TUICloudCustomDataTypeCenter.h"
- #import "TUIMessageBaseDataProvider.h"
- #import "TUIMessageProgressManager.h"
- #import "TUITypingStatusCellData.h"
- /**
- * Date time interval above the message in the UIMessageCell, in seconds, default is (5 * 60)
- */
- #define MaxDateMessageDelay 5 * 60
- @interface TUIMessageBaseDataProvider () <V2TIMAdvancedMsgListener, V2TIMGroupListener,TUIMessageProgressManagerDelegate>
- @property(nonatomic, strong) TUIChatConversationModel *conversationModel;
- @property(nonatomic, strong) NSMutableArray<TUIMessageCellData *> *uiMsgs_;
- @property(nonatomic, strong) NSMutableSet<NSString *> *sentReadGroupMsgSet;
- @property(nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *heightCache_;
- @property(nonatomic, assign) BOOL isLoadingData;
- @property(nonatomic, assign) BOOL isNoMoreMsg;
- @property(nonatomic, assign) BOOL isFirstLoad;
- @property(nonatomic, strong) V2TIMMessage *lastMsg;
- @property(nonatomic, strong) V2TIMMessage *msgForDate;
- @property(nonatomic, strong) V2TIMGroupMemberFullInfo *groupSelfInfo;
- @property(nonatomic, strong) NSMutableArray<V2TIMMessage *> *groupPinList;
- @property(nonatomic, assign) V2TIMGroupMemberRole changedRole;
- @property(nonatomic, strong) V2TIMGroupInfo *groupInfo;
- @end
- @implementation TUIMessageBaseDataProvider
- - (instancetype)initWithConversationModel:(TUIChatConversationModel *)conversationModel {
- self = [super init];
- if (self) {
- _conversationModel = conversationModel;
- _isLoadingData = NO;
- _isNoMoreMsg = NO;
- _pageCount = 20;
- _isFirstLoad = YES;
- [self registerTUIKitNotification];
- }
- return self;
- }
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- - (NSMutableSet<NSString *> *)sentReadGroupMsgSet {
- if (_sentReadGroupMsgSet == nil) {
- _sentReadGroupMsgSet = [NSMutableSet setWithCapacity:10];
- }
- return _sentReadGroupMsgSet;
- }
- - (NSMutableArray<TUIMessageCellData *> *)uiMsgs_ {
- if (_uiMsgs_ == nil) {
- _uiMsgs_ = [NSMutableArray array];
- }
- return _uiMsgs_;
- }
- - (NSMutableDictionary<NSString *, NSNumber *> *)heightCache_ {
- if (_heightCache_ == nil) {
- _heightCache_ = [NSMutableDictionary dictionary];
- }
- return _heightCache_;
- }
- - (NSArray<TUIMessageCellData *> *)uiMsgs {
- return _uiMsgs_;
- }
- - (NSDictionary<NSString *, NSNumber *> *)heightCache {
- return _heightCache_;
- }
- - (void)setChangedRole:(V2TIMGroupMemberRole)changedRole {
- _changedRole = changedRole;
- if (self.groupRoleChanged) {
- self.groupRoleChanged(changedRole);
- }
- }
- #pragma mark - TUIKitNotification
- - (void)registerTUIKitNotification {
- [[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
- [[V2TIMManager sharedInstance] addGroupListener:self];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(onMessageStatusChanged:)
- name:TUIKitNotification_onMessageStatusChanged
- object:nil];
- }
- - (void)onMessageStatusChanged:(NSNotification *)notification {
- V2TIMMessage *targetMsg = notification.object;
- NSString *msgId = targetMsg.msgID;
- TUIMessageCellData *uiMsg = nil;
- BOOL isMatch = NO;
- for (uiMsg in self.uiMsgs) {
- if ([uiMsg.msgID isEqualToString:msgId]) {
- [self.dataSource dataProviderDataSourceWillChange:self];
- NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
- [self.dataSource dataProviderDataSourceChange:self withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload atIndex:index animation:YES];
- [self.dataSource dataProviderDataSourceDidChange:self];
- isMatch = YES;
- break;
- }
- }
- if (!isMatch) {
- // Need insert UI Message
- [self onRecvNewMessage:targetMsg];
- }
- }
- #pragma mark - V2TIMAdvancedMsgListener
- - (void)onRecvNewMessage:(V2TIMMessage *)msg {
- // immsg -> uimsg
- NSMutableArray *newUIMsgs = [self transUIMsgFromIMMsg:@[ msg ]];
- if (newUIMsgs.count == 0) {
- return;
- }
- TUIMessageCellData *newUIMsg = newUIMsgs.lastObject;
- newUIMsg.source = Msg_Source_OnlinePush;
- if ([newUIMsg isKindOfClass:TUITypingStatusCellData.class]) {
- if (![TUIChatConfig defaultConfig].enableTypingStatus) {
- return;
- }
- TUITypingStatusCellData *stastusData = (TUITypingStatusCellData *)newUIMsg;
- if (!NSThread.isMainThread) {
- @weakify(self);
- dispatch_async(dispatch_get_main_queue(), ^{
- @strongify(self);
- [self dealTypingByStatusCellData:stastusData];
- });
- return;
- } else {
- [self dealTypingByStatusCellData:stastusData];
- }
- return;
- }
- @weakify(self);
- [self preProcessMessage:newUIMsgs
- callback:^{
- @strongify(self);
- [self.dataSource dataProviderDataSourceWillChange:self];
- @autoreleasepool {
- for (TUIMessageCellData *uiMsg in newUIMsgs) {
- [self addUIMsg:uiMsg];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
- atIndex:(self.uiMsgs_.count - 1)
- animation:YES];
- }
- }
- [self.dataSource dataProviderDataSourceDidChange:self];
- if ([self.dataSource respondsToSelector:@selector(dataProvider:ReceiveNewUIMsg:)]) {
- /**
- * Note that firstObject cannot be taken here, firstObject may be SystemMessageCellData that displays system time
- */
- [self.dataSource dataProvider:self ReceiveNewUIMsg:newUIMsgs.lastObject];
- }
- }];
- }
- - (NSMutableArray *)transUIMsgFromIMMsg:(NSArray *)msgs {
- NSMutableArray *uiMsgs = [NSMutableArray array];
- for (NSInteger k = msgs.count - 1; k >= 0; --k) {
- V2TIMMessage *msg = msgs[k];
- /**
- * Messages that are not the current session, ignore them directly
- */
- if (![msg.userID isEqualToString:self.conversationModel.userID] && ![msg.groupID isEqualToString:self.conversationModel.groupID]) {
- continue;
- }
- TUIMessageCellData *cellData = nil;
- /**
- * Determine whether it is a custom message outside the component
- */
- if ([self.dataSource respondsToSelector:@selector(dataProvider:CustomCellDataFromNewIMMessage:)]) {
- cellData = [self.dataSource dataProvider:self CustomCellDataFromNewIMMessage:msg];
- }
-
- if([self.dataSource_Two respondsToSelector:@selector(dataProvider_Two:CustomCellDataFromNewIMMessage:)]) {
- V2TIMMessage *newMsg = [self.dataSource_Two dataProvider_Two:self CustomCellDataFromNewIMMessage:msg];
- if(newMsg){
- msg = newMsg;
- }
- }
- /**
- * Determine whether it is a component internal message
- */
- if (!cellData) {
- cellData = [self.class getCellData:msg];
- }
- if (cellData) {
-
- if([cellData.innerMessage.sender isEqualToString:@"10000"] || [cellData.innerMessage.sender isEqualToString:@"10001"]){
- //不加入时间dateMsg
- }
- else{
- TUIMessageCellData *dateMsg = [self getSystemMsgFromDate:msg.timestamp];
- if (dateMsg) {
- if (self.mergeAdjacentMsgsFromTheSameSender) {
- dateMsg.showName = NO;
- }
- self.msgForDate = msg;
- [uiMsgs addObject:dateMsg];
- }
- }
-
- if (self.mergeAdjacentMsgsFromTheSameSender) {
- cellData.showName = NO;
- }
- [uiMsgs addObject:cellData];
- }
- }
- return uiMsgs;
- }
- /// Received message read receipts, both in group and c2c conversation.
- - (void)onRecvMessageReadReceipts:(NSArray<V2TIMMessageReceipt *> *)receiptList {
- if (receiptList.count == 0) {
- NSLog(@"group receipt data is empty, ignore");
- return;
- }
- if (![self.dataSource respondsToSelector:@selector(dataProvider:ReceiveReadMsgWithGroupID:msgID:readCount:unreadCount:)]) {
- NSLog(@"data source can not respond to protocol, ignore");
- }
- NSMutableDictionary *dict = [NSMutableDictionary dictionary];
- for (V2TIMMessageReceipt *receipt in receiptList) {
- [dict setObject:receipt forKey:receipt.msgID];
- }
- // update TUIMessageCellData readCount/unreadCount
- for (TUIMessageCellData *data in self.uiMsgs) {
- if ([dict.allKeys containsObject:data.innerMessage.msgID]) {
- V2TIMMessageReceipt *receipt = dict[data.innerMessage.msgID];
- data.messageReceipt = receipt;
- if ([self.dataSource respondsToSelector:@selector(dataProvider:ReceiveReadMsgWithGroupID:msgID:readCount:unreadCount:)]) {
- [self.dataSource dataProvider:self
- ReceiveReadMsgWithGroupID:receipt.groupID
- msgID:receipt.msgID
- readCount:receipt.readCount
- unreadCount:receipt.unreadCount];
- }
- }
- }
- }
- - (void)onRecvMessageRevoked:(NSString *)msgID operateUser:(V2TIMUserFullInfo *)operateUser reason:(NSString *)reason {
- @weakify(self);
- [TUITool dispatchMainAsync:^{
- @strongify(self);
- TUIMessageCellData *uiMsg = nil;
- for (uiMsg in self.uiMsgs) {
- if ([uiMsg.msgID isEqualToString:msgID]) {
- [self.dataSource dataProviderDataSourceWillChange:self];
- NSUInteger index = [self.uiMsgs indexOfObject:uiMsg];
- TUISystemMessageCellData *revokeCellData = (TUISystemMessageCellData *)[self.class getRevokeCellData:uiMsg.innerMessage];
- revokeCellData.content = [self.class getRevokeDispayString:uiMsg.innerMessage operateUser:operateUser reason:reason];
- if(![operateUser.userID isEqualToString:uiMsg.innerMessage.sender]) {
- //Super User revoke
- revokeCellData.supportReEdit = NO;
- }
- [self replaceUIMsg:revokeCellData atIndex:index];
- [self.dataSource dataProviderDataSourceChange:self withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload atIndex:index animation:YES];
- [self.dataSource dataProviderDataSourceDidChange:self];
- break;
- }
- }
- if ([self.dataSource respondsToSelector:@selector(dataProvider:ReceiveRevokeUIMsg:)]) {
- [self.dataSource dataProvider:self ReceiveRevokeUIMsg:uiMsg];
- }
- }];
- }
- - (void)onRecvMessageModified:(V2TIMMessage *)msg {
- V2TIMMessage *imMsg = msg;
- if (imMsg == nil || ![imMsg isKindOfClass:V2TIMMessage.class]) {
- return;
- }
- @weakify(self);
- for (TUIMessageCellData *uiMsg in self.uiMsgs) {
- if ([uiMsg.msgID isEqualToString:imMsg.msgID]) {
- if ([uiMsg customReloadCellWithNewMsg:imMsg]) {
- return;
- }
- NSMutableArray *newUIMsgs = [self transUIMsgFromIMMsg:@[ imMsg ]];
- if (newUIMsgs.count == 0) {
- return;
- }
- /**
- * Note that firstObject cannot be taken here, firstObject may be SystemMessageCellData that displays system time
- */
- TUIMessageCellData *newUIMsg = newUIMsgs.lastObject;
- newUIMsg.messageReceipt = uiMsg.messageReceipt;
- [self preProcessMessage:@[newUIMsg] callback:^{
- @strongify(self);
- NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
- if (index < self.uiMsgs.count) {
- [self.dataSource dataProviderDataSourceWillChange:self];
- [self replaceUIMsg:newUIMsg atIndex:index];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
- atIndex:index
- animation:YES];
- [self.dataSource dataProviderDataSourceDidChange:self];
- }
- }];
- return;
- }
- }
- }
- - (void)dealTypingByStatusCellData:(TUITypingStatusCellData *)stastusData {
- if (1 == stastusData.typingStatus) {
- // The timer is retimed upon receipt of the notification from the other party's input
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetTypingStatus) object:nil];
- self.conversationModel.otherSideTyping = YES;
- // If the other party does not continue typing, end the status every 5 seconds
- [self performSelector:@selector(resetTypingStatus) withObject:nil afterDelay:5.0];
- } else {
- self.conversationModel.otherSideTyping = NO;
- }
- }
- - (void)resetTypingStatus {
- self.conversationModel.otherSideTyping = NO;
- }
- #pragma mark - Msgs
- - (void)loadMessageSucceedBlock:(void (^)(BOOL isFirstLoad, BOOL isNoMoreMsg, NSArray<TUIMessageCellData *> *newMsgs))succeedBlock
- FailBlock:(V2TIMFail)failBlock {
- if (self.isLoadingData || self.isNoMoreMsg) {
- failBlock(ERR_SUCC, @"refreshing");
- return;
- }
- self.isLoadingData = YES;
- @weakify(self);
- if (self.conversationModel.userID.length > 0) {
- [[V2TIMManager sharedInstance] getC2CHistoryMessageList:self.conversationModel.userID
- count:self.pageCount
- lastMsg:self.lastMsg
- succ:^(NSArray<V2TIMMessage *> *msgs) {
- @strongify(self);
- if (msgs.count != 0) {
- self.lastMsg = msgs[msgs.count - 1];
- }
- [self loadMessages:msgs SucceedBlock:succeedBlock];
- }
- fail:^(int code, NSString *desc) {
- @strongify(self);
- self.isLoadingData = NO;
- if (failBlock) {
- failBlock(code, desc);
- }
- }];
- } else if (self.conversationModel.groupID.length > 0) {
- [[V2TIMManager sharedInstance] getGroupHistoryMessageList:self.conversationModel.groupID
- count:self.pageCount
- lastMsg:self.lastMsg
- succ:^(NSArray<V2TIMMessage *> *msgs) {
- @strongify(self);
- if (msgs.count != 0) {
- self.lastMsg = msgs[msgs.count - 1];
- }
- [self loadMessages:msgs SucceedBlock:succeedBlock];
- }
- fail:^(int code, NSString *desc) {
- @strongify(self);
- self.isLoadingData = NO;
- if (failBlock) {
- failBlock(code, desc);
- }
- }];
- }
- }
- - (void)loadMessages:(NSArray<V2TIMMessage *> *)msgs
- SucceedBlock:(void (^)(BOOL isFirstLoad, BOOL isNoMoreMsg, NSArray<TUIMessageCellData *> *newMsgs))succeedBlock {
- NSMutableArray<TUIMessageCellData *> *uiMsgs = [self transUIMsgFromIMMsg:msgs];
- if (uiMsgs.count == 0) {
- return;
- }
- @weakify(self);
- [self preProcessMessage:uiMsgs
- callback:^{
- @strongify(self);
- if (msgs.count < self.pageCount) {
- self.isNoMoreMsg = YES;
- }
- if (uiMsgs.count != 0) {
- NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, uiMsgs.count)];
- [self insertUIMsgs:uiMsgs atIndexes:indexSet];
- }
- self.isLoadingData = NO;
- if (succeedBlock) {
- succeedBlock(self.isFirstLoad, self.isNoMoreMsg, uiMsgs);
- }
- self.isFirstLoad = NO;
- }];
- }
- - (void)preProcessMessage:(NSArray<TUIMessageCellData *> *)uiMsgs callback:(void (^)(void))callback {
- // Synchronous message processing: Messages can be preprocessed here, and complex and time-consuming operations are not recommended.
- [self processMessageSync:uiMsgs callback:callback];
- // Asynchronous processing of messages: Please handle complex time-consuming operations in this function and update them in the form of reload Cell.
- [self processMessageAsync:uiMsgs];
- }
- - (void)processMessageSync:(NSArray<TUIMessageCellData *> *)uiMsgs callback:(void (^)(void))callback {
- if (callback) {
- callback();
- }
- }
- - (void)processMessageAsync:(NSArray<TUIMessageCellData *> *)uiMsgs {
- __weak typeof(self) weakSelf = self;
- [self getReactFromMessage:uiMsgs];
- [self requestForAdditionalUserInfo:uiMsgs
- callback:^{
- dispatch_async(dispatch_get_main_queue(), ^{
- [weakSelf.dataSource dataProviderDataSourceWillChange:weakSelf];
- for (TUIMessageCellData *uiMsg in uiMsgs) {
- NSArray *userIDList = [weakSelf getUserIDListForAdditionalUserInfo:@[ uiMsg ]];
- if (userIDList.count == 0) {
- continue;
- }
- NSUInteger index = [weakSelf.uiMsgs indexOfObject:uiMsg];
- if (index != NSNotFound) {
- [weakSelf.dataSource dataProvider:weakSelf onRemoveHeightCache:uiMsg];
- [weakSelf.dataSource dataProviderDataSourceChange:weakSelf
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
- atIndex:index
- animation:YES];
- }
- }
- [weakSelf.dataSource dataProviderDataSourceDidChange:weakSelf];
- });
- [weakSelf processQuoteMessage:uiMsgs];
- }];
- }
- - (void)getReactFromMessage:(NSArray<TUIMessageCellData *> *)uiMsgs {
- if (uiMsgs.count == 0) {
- return;
- }
- // fetch react
- [[NSNotificationCenter defaultCenter] postNotificationName:@"TUIKitFetchReactNotification" object:uiMsgs];
- }
- - (void)requestForAdditionalUserInfo:(NSArray<TUIMessageCellData *> *)uiMsgs callback:(void (^)(void))callback {
- NSArray *userIDList = [self getUserIDListForAdditionalUserInfo:uiMsgs];
- if (userIDList.count == 0) {
- if (callback) {
- callback();
- }
- return;
- }
- [self requestForUserDetailsInfo:userIDList
- callback:^(NSDictionary<NSString *, TUIRelationUserModel *> *result) {
- for (TUIMessageCellData *cellData in uiMsgs) {
- NSMutableDictionary *additionalUserInfoResult = [NSMutableDictionary dictionary];
- NSArray *userIDList = [self getUserIDListForAdditionalUserInfo:@[ cellData ]];
- for (NSString *userID in userIDList) {
- TUIRelationUserModel *userInfo = [result objectForKey:userID];
- if (userID.length > 0 && userInfo) {
- additionalUserInfoResult[userID] = userInfo;
- }
- }
- cellData.additionalUserInfoResult = additionalUserInfoResult;
- }
- if (callback) {
- callback();
- }
- }];
- }
- - (void)requestForUserDetailsInfo:(NSArray *)userIDList callback:(void (^)(NSDictionary<NSString *, TUIRelationUserModel *> *))callback {
- if (callback == nil) {
- return;
- }
- NSMutableDictionary<NSString *, TUIRelationUserModel *> *result = [NSMutableDictionary dictionary];
- if (self.conversationModel.groupID.length > 0) {
- [[V2TIMManager sharedInstance] getGroupMembersInfo:self.conversationModel.groupID
- memberList:userIDList
- succ:^(NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
- [memberList enumerateObjectsUsingBlock:^(V2TIMGroupMemberFullInfo *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
- if (obj.userID.length > 0) {
- TUIRelationUserModel *userInfo = [[TUIRelationUserModel alloc] init];
- userInfo.userID = obj.userID;
- userInfo.nickName = obj.nickName;
- userInfo.friendRemark = obj.friendRemark;
- userInfo.nameCard = obj.nameCard;
- userInfo.faceURL = obj.faceURL;
- [result setObject:userInfo forKey:userInfo.userID];
- }
- }];
- callback(result);
- }
- fail:^(int code, NSString *desc) {
- callback(result);
- }];
- } else {
- [V2TIMManager.sharedInstance getFriendsInfo:userIDList
- succ:^(NSArray<V2TIMFriendInfoResult *> *resultList) {
- for (V2TIMFriendInfoResult *item in resultList) {
- if (item.friendInfo && item.friendInfo.userID.length > 0) {
- TUIRelationUserModel *userInfo = [[TUIRelationUserModel alloc] init];
- userInfo.userID = item.friendInfo.userID;
- userInfo.nickName = item.friendInfo.userFullInfo.nickName;
- userInfo.friendRemark = item.friendInfo.friendRemark;
- userInfo.faceURL = item.friendInfo.userFullInfo.faceURL;
- [result setObject:userInfo forKey:userInfo.userID];
- }
- }
- callback(result);
- }
- fail:^(int code, NSString *desc) {
- callback(result);
- }];
- }
- }
- - (NSArray<NSString *> *)getUserIDListForAdditionalUserInfo:(NSArray<TUIMessageCellData *> *)uiMsgs {
- NSMutableSet *userIDSet = [NSMutableSet set];
- // Built-in
- for (TUIMessageCellData *cellData in uiMsgs) {
- if (![cellData.messageModifyReplies isKindOfClass:NSArray.class] || cellData.messageModifyReplies.count == 0) {
- continue;
- }
- [cellData.messageModifyReplies enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
- if (obj && [obj isKindOfClass:NSDictionary.class]) {
- NSDictionary *dic = (NSDictionary *)obj;
- if (IS_NOT_EMPTY_NSSTRING(dic[@"messageSender"])) {
- [userIDSet addObject:dic[@"messageSender"]];
- }
- }
- }];
- }
- // Get userid from cellData which override the -requestForAdditionalUserInfo method
- for (TUIMessageCellData *cellData in uiMsgs) {
- if ([cellData respondsToSelector:@selector(requestForAdditionalUserInfo)]) {
- NSArray *array = [cellData requestForAdditionalUserInfo];
- if (array && array.count > 0) {
- [userIDSet addObjectsFromArray:array];
- }
- }
- }
- NSArray *userIDList = userIDSet.allObjects;
- return userIDList;
- }
- - (void)processQuoteMessage:(NSArray<TUIMessageCellData *> *)uiMsgs {
- // Subclasses implement this method
- return;
- }
- - (void)sendUIMsg:(TUIMessageCellData *)uiMsg
- toConversation:(TUIChatConversationModel *)conversationData
- willSendBlock:(void (^)(BOOL isReSend, TUIMessageCellData *dateUIMsg))willSendBlock
- SuccBlock:(nullable V2TIMSucc)succ
- FailBlock:(nullable V2TIMFail)fail {
- [self preProcessMessage:@[ uiMsg ]
- callback:^{
- [TUITool dispatchMainAsync:^{
- V2TIMMessage *imMsg = uiMsg.innerMessage;
- TUIMessageCellData *placeholderCellData = uiMsg.placeHolderCellData;
- TUIMessageCellData *dateMsg = nil;
- BOOL isReSent = NO;
- if (uiMsg.status == Msg_Status_Init) {
- // New message
- dateMsg = [self getSystemMsgFromDate:imMsg.timestamp];
- } else if (imMsg) {
- // Re-sent
- isReSent = YES;
- dateMsg = [self getSystemMsgFromDate:[NSDate date]];
- } else {
- if (fail) {
- fail(ERR_INVALID_PARAMETERS, @"Unknown message state");
- }
- return;
- }
- imMsg.isExcludedFromUnreadCount = [TUIConfig defaultConfig].isExcludedFromUnreadCount;
- imMsg.isExcludedFromLastMessage = [TUIConfig defaultConfig].isExcludedFromLastMessage;
- // Update sender
- uiMsg.identifier = [TUILogin getUserID];
- [self.dataSource dataProviderDataSourceWillChange:self];
- // Handle data
- if (isReSent) {
- NSInteger row = [self.uiMsgs indexOfObject:uiMsg];
- [self removeUImsgAtIndex:row];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeDelete
- atIndex:row
- animation:YES];
- }
- if (placeholderCellData) {
- NSInteger row = [self.uiMsgs indexOfObject:placeholderCellData];
- if (row != NSNotFound) {
- [self replaceUIMsg:uiMsg atIndex:row];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
- atIndex:row
- animation:NO];
- }
- }
- else {
- if (dateMsg) {
- [self addUIMsg:dateMsg];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
- atIndex:(self.uiMsgs.count - 1)
- animation:YES];
- }
- [self addUIMsg:uiMsg];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
- atIndex:(self.uiMsgs.count - 1)
- animation:YES];
- }
- [self.dataSource dataProviderDataSourceDidChange:self];
- if (willSendBlock) {
- willSendBlock(isReSent, dateMsg);
- }
- if (dateMsg) {
- self.msgForDate = imMsg;
- }
- TUISendMessageAppendParams *appendParams = [[TUISendMessageAppendParams alloc] init];
- appendParams.isSendPushInfo = YES;
- appendParams.isOnlineUserOnly = NO;
- appendParams.priority = V2TIM_PRIORITY_NORMAL;
- uiMsg.msgID = [self.class sendMessage:imMsg
- toConversation:conversationData
- appendParams:appendParams
- Progress:^(uint32_t progress) {
- [TUIMessageProgressManager.shareManager appendUploadProgress:uiMsg.msgID progress:progress];
- }
- SuccBlock:^{
- [TUIMessageProgressManager.shareManager appendUploadProgress:uiMsg.msgID progress:100];
- if (succ) {
- succ();
- }
- [TUIMessageProgressManager.shareManager notifyMessageSendingResult:uiMsg.msgID result:TUIMessageSendingResultTypeSucc];
- }
- FailBlock:^(int code, NSString *desc) {
- if (fail) {
- fail(code, desc);
- }
- [TUIMessageProgressManager.shareManager notifyMessageSendingResult:uiMsg.msgID result:TUIMessageSendingResultTypeFail];
- }];
- }];
- }];
- }
- - (void)revokeUIMsg:(TUIMessageCellData *)uiMsg SuccBlock:(nullable V2TIMSucc)succ FailBlock:(nullable V2TIMFail)fail {
- V2TIMMessage *imMsg = uiMsg.innerMessage;
- if (imMsg == nil) {
- if (fail) {
- fail(ERR_INVALID_PARAMETERS, @"cellData.innerMessage is nil");
- }
- return;
- }
- NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
- if (index == NSNotFound) {
- if (fail) {
- fail(ERR_INVALID_PARAMETERS, @"not found cellData in uiMsgs");
- }
- return;
- }
- @weakify(self);
- [self.class revokeMessage:imMsg
- succ:^{
- @strongify(self);
- if (succ) {
- succ();
- }
- }
- fail:fail];
- }
- - (void)deleteUIMsgs:(NSArray<TUIMessageCellData *> *)uiMsgs SuccBlock:(nullable V2TIMSucc)succ FailBlock:(nullable V2TIMFail)fail {
- }
- - (void)addUIMsg:(TUIMessageCellData *)cellData {
- [self.uiMsgs_ addObject:cellData];
- if (self.mergeAdjacentMsgsFromTheSameSender) {
- [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
- }
- }
- - (void)removeUIMsg:(TUIMessageCellData *)cellData {
- if (cellData) {
- [self.uiMsgs_ removeObject:cellData];
- if ([self.dataSource respondsToSelector:@selector(dataProvider:onRemoveHeightCache:)]) {
- [self.dataSource dataProvider:self onRemoveHeightCache:cellData];
- }
- if (self.mergeAdjacentMsgsFromTheSameSender) {
- [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
- }
- }
- }
- - (void)sendPlaceHolderUIMessage:(TUIMessageCellData *)placeHolderCellData {
- V2TIMMessage *imMsg = placeHolderCellData.innerMessage;
- TUIMessageCellData *dateMsg = nil;
- if (placeHolderCellData.status == Msg_Status_Init) {
- // New message
- dateMsg = [self getSystemMsgFromDate:imMsg.timestamp];
- }
- [self.dataSource dataProviderDataSourceWillChange:self];
- if (dateMsg) {
- [self addUIMsg:dateMsg];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
- atIndex:(self.uiMsgs.count - 1)
- animation:YES];
- }
-
- [self addUIMsg:placeHolderCellData];
- [self.dataSource dataProviderDataSourceChange:self
- withType:TUIMessageBaseDataProviderDataSourceChangeTypeInsert
- atIndex:(self.uiMsgs.count - 1)
- animation:YES];
- [self.dataSource dataProviderDataSourceDidChange:self];
- }
- - (void)insertUIMsgs:(NSArray<TUIMessageCellData *> *)uiMsgs atIndexes:(NSIndexSet *)indexes {
- [self.uiMsgs_ insertObjects:uiMsgs atIndexes:indexes];
- if (self.mergeAdjacentMsgsFromTheSameSender) {
- for (TUIMessageCellData *cellData in uiMsgs) {
- [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
- }
- }
- }
- - (void)addUIMsgs:(NSArray<TUIMessageCellData *> *)uiMsgs {
- [self.uiMsgs_ addObjectsFromArray:uiMsgs];
- if (self.mergeAdjacentMsgsFromTheSameSender) {
- for (TUIMessageCellData *cellData in uiMsgs) {
- [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
- }
- }
- }
- - (void)removeUIMsgList:(NSArray<TUIMessageCellData *> *)cellDatas {
- for (TUIMessageCellData *uiMsg in cellDatas) {
- [self removeUIMsg:uiMsg];
- }
- }
- - (void)removeUImsgAtIndex:(NSUInteger)index {
- if (index < self.uiMsgs.count) {
- TUIMessageCellData *msg = self.uiMsgs[index];
- [self removeUIMsg:msg];
- }
- }
- - (void)clearUIMsgList {
- NSArray *clearArray = [NSArray arrayWithArray:self.uiMsgs];
- [self removeUIMsgList:clearArray];
- self.msgForDate = nil;
- self.uiMsgs_ = nil;
- }
- - (void)replaceUIMsg:(TUIMessageCellData *)cellData atIndex:(NSUInteger)index {
- if (index < self.uiMsgs.count) {
- TUIMessageCellData *oldMsg = self.uiMsgs[index];
- if ([self.dataSource respondsToSelector:@selector(dataProvider:onRemoveHeightCache:)]) {
- [self.dataSource dataProvider:self onRemoveHeightCache:oldMsg];
- }
-
- [self.uiMsgs_ replaceObjectAtIndex:index withObject:cellData];
-
- if (self.mergeAdjacentMsgsFromTheSameSender) {
- [self.class updateUIMsgStatus:cellData uiMsgs:self.uiMsgs_];
- }
- }
- }
- - (void)sendLatestMessageReadReceipt {
- [self sendMessageReadReceiptAtIndexes:@[ @(self.uiMsgs.count - 1) ]];
- }
- - (void)sendMessageReadReceiptAtIndexes:(NSArray *)indexes {
- if (indexes.count == 0) {
- NSLog(@"sendMessageReadReceipt, but indexes is empty, ignore");
- return;
- }
- NSMutableArray *array = [NSMutableArray array];
- for (NSNumber *i in indexes) {
- if ([i intValue] < 0 || [i intValue] >= self.uiMsgs_.count) {
- continue;
- }
- TUIMessageCellData *data = self.uiMsgs_[[i intValue]];
- if (data.innerMessage.isSelf) {
- continue;
- }
- if (data.innerMessage == nil) {
- continue;
- }
- // Use Set to avoid sending duplicate element to SDK
- if (data.msgID.length > 0) {
- if ([self.sentReadGroupMsgSet containsObject:data.msgID]) {
- continue;
- } else {
- [self.sentReadGroupMsgSet addObject:data.msgID];
- }
- }
- // If needReadReceipt is NO, receiver won't send message read receipt
- if (!data.innerMessage.needReadReceipt) {
- continue;
- }
- [array addObject:data.innerMessage];
- }
- if (array.count == 0) {
- return;
- }
- [self.class sendMessageReadReceipts:array];
- }
- - (NSInteger)getIndexOfMessage:(NSString *)msgID {
- if (msgID.length == 0) {
- return -1;
- }
- for (int i = 0; i < self.uiMsgs.count; i++) {
- TUIMessageCellData *data = self.uiMsgs[i];
- if ([data.msgID isEqualToString:msgID]) {
- return i;
- }
- }
- return -1;
- }
- - (nullable TUIMessageCellData *)getSystemMsgFromDate:(NSDate *)date {
- if (self.msgForDate == nil || fabs([date timeIntervalSinceDate:self.msgForDate.timestamp]) > MaxDateMessageDelay) {
- TUIMessageCellData *system = [self.class getSystemMsgFromDate:date];
- return system;
- }
- return nil;
- }
- + (void)updateUIMsgStatus:(TUIMessageCellData *)cellData uiMsgs:(NSArray *)uiMsgs {
- if (![uiMsgs containsObject:cellData]) {
- return;
- }
- NSInteger index = [uiMsgs indexOfObject:cellData];
- TUIMessageCellData *data = uiMsgs[index];
- TUIMessageCellData *lastData = nil;
- if (index >= 1) {
- lastData = uiMsgs[index - 1];
- if (![lastData isKindOfClass:[TUISystemMessageCellData class]]) {
- if ([lastData.identifier isEqualToString:data.identifier] &&
- ![data isKindOfClass:[TUISystemMessageCellData class]] &&(lastData.direction == data.direction)) {
- lastData.sameToNextMsgSender = YES;
- lastData.showAvatar = NO;
- } else {
- lastData.sameToNextMsgSender = NO;
- lastData.showAvatar = (lastData.direction == MsgDirectionIncoming ? YES : NO);
- }
- }
- }
- TUIMessageCellData *nextData = nil;
- if (index < uiMsgs.count - 1) {
- nextData = uiMsgs[index + 1];
- if ([data.identifier isEqualToString:nextData.identifier] &&(data.direction == nextData.direction)) {
- data.sameToNextMsgSender = YES;
- data.showAvatar = NO;
- } else {
- data.sameToNextMsgSender = NO;
- data.showAvatar = (data.direction == MsgDirectionIncoming ? YES : NO);
- }
- }
- if (index == uiMsgs.count - 1) {
- data.showAvatar = (data.direction == MsgDirectionIncoming ? YES : NO);
- data.sameToNextMsgSender = NO;
- }
- }
- - (void)getPinMessageList {
- if (self.conversationModel.groupID.length > 0) {
- __weak typeof(self) weakSelf = self;
- [V2TIMManager.sharedInstance getPinnedGroupMessageList:self.conversationModel.groupID succ:^(NSArray<V2TIMMessage *> *messageList) {
- weakSelf.groupPinList = [NSMutableArray arrayWithArray:messageList];
- if (weakSelf.pinGroupMessageChanged) {
- weakSelf.pinGroupMessageChanged(weakSelf.groupPinList);
- }
- } fail:^(int code, NSString *desc) {
- weakSelf.groupPinList = [NSMutableArray array];
- if (weakSelf.pinGroupMessageChanged) {
- weakSelf.pinGroupMessageChanged(weakSelf.groupPinList);
- }
- }];
- }
- }
- - (void)loadGroupInfo:(dispatch_block_t)callback {
- if (self.conversationModel.groupID.length == 0) {
- if (callback) {
- callback();
- }
- return;
- }
- __weak typeof(self) weakSelf = self;
- [[V2TIMManager sharedInstance] getGroupsInfo:@[ self.conversationModel.groupID ]
- succ:^(NSArray<V2TIMGroupInfoResult *> *groupResultList) {
- if (groupResultList.count == 1) {
- V2TIMGroupInfo *info = groupResultList[0].info;
- weakSelf.groupInfo = info;
- }
- if (callback) {
- callback();
- }
- }
- fail:^(int code, NSString *msg) {
- [TUITool makeToastError:code msg:msg];
- }];
- }
- - (void)getSelfInfoInGroup:(dispatch_block_t)callback {
- NSString *loginUserID = [[V2TIMManager sharedInstance] getLoginUser];
- if (loginUserID.length == 0) {
- if (callback) {
- callback();
- }
- return;
- }
- if (!self.conversationModel.enableRoom) {
- if (callback) {
- callback();
- }
- return;
- }
- __weak typeof(self) weakSelf = self;
- [[V2TIMManager sharedInstance] getGroupMembersInfo:self.conversationModel.groupID
- memberList:@[ loginUserID ]
- succ:^(NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
- for (V2TIMGroupMemberFullInfo *item in memberList) {
- if ([item.userID isEqualToString:loginUserID]) {
- weakSelf.groupSelfInfo = item;
- if ([weakSelf.groupInfo.owner isEqualToString:loginUserID]) {
- weakSelf.changedRole = V2TIM_GROUP_MEMBER_ROLE_SUPER;
- }
- else {
- weakSelf.changedRole = item.role;
- }
- break;
- }
- }
- if (callback) {
- callback();
- }
- }
- fail:^(int code, NSString *desc) {
- [TUITool makeToastError:code msg:desc];
- if (callback) {
- callback();
- }
- }];
- }
- - (BOOL)isCurrentUserRoleSuperAdminInGroup {
- if (self.changedRole != V2TIM_GROUP_MEMBER_UNDEFINED) {
- return (self.changedRole == V2TIM_GROUP_MEMBER_ROLE_ADMIN || self.changedRole == V2TIM_GROUP_MEMBER_ROLE_SUPER);
- }
- return ([self.groupInfo.owner isEqualToString:[[V2TIMManager sharedInstance] getLoginUser]] ||self.groupSelfInfo.role == V2TIM_GROUP_MEMBER_ROLE_ADMIN || self.groupSelfInfo.role == V2TIM_GROUP_MEMBER_ROLE_SUPER) ;
- }
- - (BOOL)isCurrentMessagePin:(NSString *)msgID {
- BOOL isPin = NO;
- for (V2TIMMessage *msg in self.groupPinList) {
- if ([msg.msgID isEqualToString:msgID]) {
- isPin = YES;
- break;
- }
- }
- return isPin;
- }
- - (void)pinGroupMessage:(NSString *)groupID
- message:(V2TIMMessage *)message
- isPinned:(BOOL)isPinned
- succ:(V2TIMSucc)succ
- fail:(V2TIMFail)fail {
- __weak typeof(self) weakSelf = self;
- [V2TIMManager.sharedInstance pinGroupMessage:groupID message:message isPinned:isPinned succ:^{
- if (isPinned) {
- //del from changed
- }
- else {
- //add from changed
-
- }
-
- if (succ) {
- succ();
- }
- } fail:^(int code, NSString *desc) {
- if (fail) {
- fail(code,desc);
- }
- }];
- }
- - (void)onGroupMessagePinned:(NSString *)groupID message:(V2TIMMessage *)message isPinned:(BOOL)isPinned opUser:(V2TIMGroupMemberInfo *)opUser {
- if (![groupID isEqualToString:self.conversationModel.groupID]) {
- return;
- }
- if (isPinned) {
- //add
- [self.groupPinList addObject:message];
- }
- else {
- //del
- NSMutableArray *formatArray = [NSMutableArray arrayWithArray:self.groupPinList];
- for (V2TIMMessage *msg in formatArray) {
- if ([msg.msgID isEqualToString:message.msgID]) {
- [self.groupPinList removeObject:msg];
- break;
- }
- }
- }
- if (self.pinGroupMessageChanged) {
- self.pinGroupMessageChanged(self.groupPinList);
- }
- }
- - (void)onGroupInfoChanged:(NSString *)groupID changeInfoList:(NSArray<V2TIMGroupChangeInfo *> *)changeInfoList {
- if (![groupID isEqualToString:self.conversationModel.groupID]) {
- return;
- }
-
- for (V2TIMGroupChangeInfo *changeInfo in changeInfoList) {
- if (changeInfo.type == V2TIM_GROUP_INFO_CHANGE_TYPE_OWNER) {
- NSString *ownerID = changeInfo.value;
-
- if ([ownerID isEqualToString:[TUILogin getUserID]]) {
- self.changedRole = V2TIM_GROUP_MEMBER_ROLE_SUPER;
- }
- else {
- if (self.changedRole ==V2TIM_GROUP_MEMBER_ROLE_SUPER) {
- self.changedRole = V2TIM_GROUP_MEMBER_ROLE_MEMBER;
- }
- }
- return;
- }
- }
- }
- - (void)onGrantAdministrator:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray <V2TIMGroupMemberInfo *> *)memberList {
- if (![groupID isEqualToString:self.conversationModel.groupID]) {
- return;
- }
- for (V2TIMGroupMemberInfo *changeInfo in memberList) {
- if (changeInfo.userID == [TUILogin getUserID]) {
- self.changedRole = V2TIM_GROUP_MEMBER_ROLE_ADMIN;
- return;
- }
- }
- }
- - (void)onRevokeAdministrator:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray <V2TIMGroupMemberInfo *> *)memberList {
- if (![groupID isEqualToString:self.conversationModel.groupID]) {
- return;
- }
- for (V2TIMGroupMemberInfo *changeInfo in memberList) {
- if (changeInfo.userID == [TUILogin getUserID]) {
- self.changedRole = V2TIM_GROUP_MEMBER_ROLE_MEMBER;
- return;
- }
- }
- }
- @end
- @implementation TUIMessageBaseDataProvider (IMSDK)
- static const int kOfflinePushVersion = 1;
- + (NSString *)sendMessage:(V2TIMMessage *)message
- toConversation:(TUIChatConversationModel *)conversationData
- appendParams:(TUISendMessageAppendParams *)appendParams
- Progress:(nullable V2TIMProgress)progress
- SuccBlock:(nullable V2TIMSucc)succ
- FailBlock:(nullable V2TIMFail)fail {
- NSString *userID = conversationData.userID;
- NSString *groupID = conversationData.groupID;
- NSAssert(userID || groupID, @"userID and groupID cannot be null at same time");
- NSString *conversationID = @"";
- if (!appendParams) {
- NSLog(@"appendParams cannot be nil");
- }
- BOOL isSendPushInfo = appendParams.isSendPushInfo;
- BOOL isOnlineUserOnly = appendParams.isOnlineUserOnly;
- V2TIMMessagePriority priority = appendParams.priority;
- if (IS_NOT_EMPTY_NSSTRING(userID)) {
- conversationID = [NSString stringWithFormat:@"c2c_%@", userID];
- }
- if (IS_NOT_EMPTY_NSSTRING(groupID)) {
- conversationID = [NSString stringWithFormat:@"group_%@", groupID];
- }
- if (IS_NOT_EMPTY_NSSTRING(conversationData.conversationID)) {
- conversationID = conversationData.conversationID;
- }
- NSParameterAssert(message);
- V2TIMOfflinePushInfo *pushInfo = nil;
- if (isSendPushInfo) {
- pushInfo = [[V2TIMOfflinePushInfo alloc] init];
- BOOL isGroup = groupID.length > 0;
- NSString *senderId = isGroup ? (groupID) : ([TUILogin getUserID]);
- senderId = senderId ?: @"";
- NSString *nickName = isGroup ? (conversationData.title) : ([TUILogin getNickName] ?: [TUILogin getUserID]);
- nickName = nickName ?: @"";
- NSString * content = [self getDisplayString:message] ?: @"";
- OfflinePushExtInfo *extInfo = [[OfflinePushExtInfo alloc] init];
- OfflinePushExtBusinessInfo * entity = extInfo.entity;
- entity.action = 1;
- entity.content = content;
- entity.sender = senderId;
- entity.nickname = nickName;
- entity.faceUrl = [TUILogin getFaceUrl] ?: @"";
- entity.chatType = [isGroup ? @(V2TIM_GROUP) : @(V2TIM_C2C) integerValue];
- entity.version = kOfflinePushVersion;
- pushInfo.ext = [extInfo toReportExtString];
- if (content.length > 0) {
- pushInfo.desc = content;
- }
- if (nickName.length > 0) {
- pushInfo.title = nickName;
- }
- pushInfo.AndroidOPPOChannelID = @"tuikit";
- pushInfo.AndroidSound = TUIConfig.defaultConfig.enableCustomRing ? @"private_ring" : nil;
- pushInfo.AndroidHuaWeiCategory = @"IM";
- pushInfo.AndroidVIVOCategory = @"IM";
- pushInfo.AndroidHonorImportance = @"NORMAL";
- pushInfo.iOSInterruptionLevel = @"time-sensitive";
- pushInfo.enableIOSBackgroundNotification = NO;
- }
- if ([self isGroupCommunity:conversationData.groupType groupID:conversationData.groupID] ||
- [self isGroupAVChatRoom:conversationData.groupType]) {
- message.needReadReceipt = NO;
- }
- // Hidden conversation evokes the chat page from the address book entry - to send a message, the hidden flag needs to be cleared
- if (conversationID.length > 0) {
- [V2TIMManager.sharedInstance markConversation:@[ conversationID ] markType:@(V2TIM_CONVERSATION_MARK_TYPE_HIDE) enableMark:NO succ:nil fail:nil];
- }
- if (conversationData.userID.length > 0) {
- // C2C
- NSDictionary *cloudCustomDataDic = @{
- @"needTyping" : @1,
- @"version" : @1,
- };
- [message setCloudCustomData:cloudCustomDataDic forType:messageFeature];
- }
- return [V2TIMManager.sharedInstance sendMessage:message
- receiver:userID
- groupID:groupID
- priority:priority
- onlineUserOnly:isOnlineUserOnly
- offlinePushInfo:pushInfo
- progress:progress
- succ:^{
- succ();
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kNotification_SendMessage" object:nil];
- }
- fail:^(int code, NSString *desc) {
- if (code == ERR_SDK_INTERFACE_NOT_SUPPORT) {
- [TUITool postUnsupportNotificationOfService:TUIKitLocalizableString(TUIKitErrorUnsupportIntefaceMessageRead)];
- }
- fail(code, desc);
- }];
- }
- - (void)getLastMessage:(BOOL)isFromLocal succ:(void (^)(V2TIMMessage *message))succ fail:(V2TIMFail)fail; {
- V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];
- if (self.conversationModel.userID.length > 0) {
- option.userID = self.conversationModel.userID;
- }
- if (self.conversationModel.groupID.length > 0) {
- option.groupID = self.conversationModel.groupID;
- }
- option.getType = isFromLocal ? V2TIM_GET_LOCAL_OLDER_MSG : V2TIM_GET_CLOUD_OLDER_MSG;
- option.lastMsg = nil;
- option.count = 1;
- [[V2TIMManager sharedInstance] getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) {
- if (succ) {
- succ(msgs.count > 0 ? msgs.firstObject : nil);
- }
- } fail:^(int code, NSString *desc) {
- if (fail) {
- fail(code, desc);
- }
- }];
- }
- + (BOOL)isGroupCommunity:(NSString *)groupType groupID:(NSString *)groupID {
- return [groupType isEqualToString:@"Community"] || [groupID startsWith:@"@TGS#_"];
- }
- + (BOOL)isGroupAVChatRoom:(NSString *)groupType {
- return [groupType isEqualToString:@"AVChatRoom"];
- }
- + (void)markC2CMessageAsRead:(NSString *)userID succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
- NSString * conversationID = [NSString stringWithFormat:@"c2c_%@",userID];
- [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:succ fail:fail];
- }
- + (void)markGroupMessageAsRead:(NSString *)groupID succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
- NSString * conversationID = [NSString stringWithFormat:@"group_%@",groupID];
- [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:succ fail:fail];
- }
- + (void)markConversationAsUndead:(NSArray<NSString *> *)conversationIDList enableMark:(BOOL)enableMark {
- [V2TIMManager.sharedInstance markConversation:conversationIDList markType:@(V2TIM_CONVERSATION_MARK_TYPE_UNREAD) enableMark:enableMark succ:nil fail:nil];
- }
- + (void)revokeMessage:(V2TIMMessage *)msg succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
- [[V2TIMManager sharedInstance] revokeMessage:msg succ:succ fail:fail];
- }
- + (void)deleteMessages:(NSArray<V2TIMMessage *> *)msgList succ:(nullable V2TIMSucc)succ fail:(nullable V2TIMFail)fail {
- [[V2TIMManager sharedInstance] deleteMessages:msgList succ:succ fail:fail];
- }
- + (void)modifyMessage:(V2TIMMessage *)msg completion:(V2TIMMessageModifyCompletion)completion {
- [[V2TIMManager sharedInstance] modifyMessage:msg completion:completion];
- }
- + (void)sendMessageReadReceipts:(NSArray *)msgs {
- [[V2TIMManager sharedInstance] sendMessageReadReceipts:msgs
- succ:^{
- NSLog(@"sendMessageReadReceipts succeed");
- }
- fail:^(int code, NSString *desc) {
- if (code == ERR_SDK_INTERFACE_NOT_SUPPORT) {
- [TUITool postUnsupportNotificationOfService:TUIKitLocalizableString(TUIKitErrorUnsupportIntefaceMessageRead)];
- }
- }];
- }
- + (void)getReadMembersOfMessage:(V2TIMMessage *)msg
- filter:(V2TIMGroupMessageReadMembersFilter)filter
- nextSeq:(NSUInteger)nextSeq
- completion:(void (^)(int code, NSString *desc, NSArray *members, NSUInteger nextSeq, BOOL isFinished))block {
- [[V2TIMManager sharedInstance] getGroupMessageReadMemberList:msg
- filter:filter
- nextSeq:nextSeq
- count:100
- succ:^(NSMutableArray<V2TIMGroupMemberInfo *> *members, uint64_t nextSeq, BOOL isFinished) {
- if (block) {
- block(0, nil, members, nextSeq, isFinished);
- }
- }
- fail:^(int code, NSString *desc) {
- if (block) {
- block(code, desc, nil, 0, NO);
- }
- }];
- }
- + (void)getMessageReadReceipt:(NSArray *)messages succ:(nullable V2TIMMessageReadReceiptsSucc)succ fail:(nullable V2TIMFail)fail {
- if (messages.count == 0) {
- if (fail) {
- fail(-1, @"messages empty");
- }
- return;
- }
- [[V2TIMManager sharedInstance] getMessageReadReceipts:messages succ:succ fail:fail];
- }
- + (TUIMessageCellData *__nullable)getCellData:(V2TIMMessage *)message {
- // subclass override required
- return nil;
- }
- + (nullable TUIMessageCellData *)getSystemMsgFromDate:(NSDate *)date {
- // subclass override required
- return nil;
- }
- + (TUIMessageCellData *)getRevokeCellData:(V2TIMMessage *)message {
- // subclass override required
- return nil;
- }
- + (nullable NSString *)getDisplayString:(V2TIMMessage *)message {
- // subclass override required
- return nil;
- }
- + (NSString *)getRevokeDispayString:(V2TIMMessage *)message {
- return [self getRevokeDispayString:message operateUser:nil reason:nil];
- }
- + (NSString *)getRevokeDispayString:(V2TIMMessage *)message operateUser:(V2TIMUserFullInfo *)operateUser reason:(NSString *)reason {
- V2TIMUserFullInfo *revokerInfo = message.revokerInfo ? message.revokerInfo : operateUser;
- BOOL hasRiskContent = message.hasRiskContent;
- NSString *revoker = message.sender;
- NSString *messageSender = message.sender;
- if (revokerInfo) {
- revoker = revokerInfo.userID;
- }
- NSString *content = TIMCommonLocalizableString(TUIKitMessageTipsNormalRecallMessage);
- if ([revoker isEqualToString:messageSender]) {
- if (message.isSelf) {
- content = TIMCommonLocalizableString(TUIKitMessageTipsYouRecallMessage);
- } else {
- if (message.userID.length > 0) {
- // c2c
- content = TIMCommonLocalizableString(TUIKitMessageTipsOthersRecallMessage);
- } else if (message.groupID.length > 0) {
- NSString *userName = [self.class getShowName:message];
- content = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
- } else {
- // empty
- }
- }
- } else {
- NSString *userName = [self.class getShowName:message];
- if (revokerInfo) {
- userName = revokerInfo.showName;
- }
- content = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
- }
- return rtlString(content);
- }
- + (NSString *)getGroupTipsDisplayString:(V2TIMMessage *)message {
- V2TIMGroupTipsElem *tips = message.groupTipsElem;
- NSString *opUser = [self getOpUserName:tips.opMember];
- NSMutableArray<NSString *> *userList = [self getUserNameList:tips.memberList];
- NSString *str = nil;
- switch (tips.type) {
- case V2TIM_GROUP_TIPS_TYPE_JOIN: {
- if (opUser.length > 0) {
- if ((userList.count == 0) || (userList.count == 1 && [opUser isEqualToString:userList.firstObject])) {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsJoinGroupFormat), opUser];
- } else {
- NSString *users = [userList componentsJoinedByString:@"、"];
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsInviteJoinGroupFormat), opUser, users];
- }
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_INVITE: {
- if (userList.count > 0) {
- NSString *users = [userList componentsJoinedByString:@"、"];
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsInviteJoinGroupFormat), opUser, users];
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_QUIT: {
- if (opUser.length > 0) {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsLeaveGroupFormat), opUser];
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_KICKED: {
- if (userList.count > 0) {
- NSString *users = [userList componentsJoinedByString:@"、"];
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsKickoffGroupFormat), opUser, users];
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_SET_ADMIN: {
- if (userList.count > 0) {
- NSString *users = [userList componentsJoinedByString:@"、"];
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsSettAdminFormat), users];
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_CANCEL_ADMIN: {
- if (userList.count > 0) {
- NSString *users = [userList componentsJoinedByString:@"、"];
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsCancelAdminFormat), users];
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_GROUP_INFO_CHANGE: {
- str = [self opGroupInfoChagedFormatStr:opUser ofUserList:userList ofTips:tips];
- if (str.length > 0) {
- str = [str substringToIndex:str.length - 1];
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_MEMBER_INFO_CHANGE: {
- for (V2TIMGroupChangeInfo *info in tips.memberChangeInfoList) {
- if ([info isKindOfClass:V2TIMGroupMemberChangeInfo.class]) {
- NSString *userId = [(V2TIMGroupMemberChangeInfo *)info userID];
- int32_t muteTime = [(V2TIMGroupMemberChangeInfo *)info muteTime];
- NSString *myId = V2TIMManager.sharedInstance.getLoginUser;
- NSString *showName = [self.class getUserName:tips with:userId];
- str = [NSString stringWithFormat:@"%@ %@", [userId isEqualToString:myId] ? TIMCommonLocalizableString(You) : showName,
- muteTime == 0 ? TIMCommonLocalizableString(TUIKitMessageTipsUnmute)
- : TIMCommonLocalizableString(TUIKitMessageTipsMute)];
- break;
- }
- }
- } break;
- case V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_ADDED: {
- if (opUser.length > 0) {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsGroupPinMessage), opUser];
- }
- }
- break;
- case V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_DELETED: {
- if (opUser.length > 0) {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsGroupUnPinMessage), opUser];
- }
- }
- break;
- default:
- break;
- }
- return rtlString(str);
- }
- + (V2TIMMessage *)getCustomMessageWithJsonData:(NSData *)data {
- return [[V2TIMManager sharedInstance] createCustomMessage:data];
- }
- + (V2TIMMessage *)getCustomMessageWithJsonData:(NSData *)data desc:(NSString *)desc extension:(NSString *)extension {
- return [[V2TIMManager sharedInstance] createCustomMessage:data desc:desc extension:extension];
- }
- + (NSString *)opGroupInfoChagedFormatStr:(NSString *)opUser ofUserList:(NSMutableArray<NSString *> *)userList ofTips:(V2TIMGroupTipsElem *)tips{
- NSString *str = nil;
- str = [NSString stringWithFormat:@"%@", opUser];
- for (V2TIMGroupChangeInfo *info in tips.groupChangeInfoList) {
- switch (info.type) {
- case V2TIM_GROUP_INFO_CHANGE_TYPE_NAME: {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIkitMessageTipsEditGroupNameFormat), str, info.value];
- } break;
- case V2TIM_GROUP_INFO_CHANGE_TYPE_INTRODUCTION: {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupIntroFormat), str, info.value];
- } break;
- case V2TIM_GROUP_INFO_CHANGE_TYPE_NOTIFICATION: {
- if (info.value.length) {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAnnounceFormat), str, info.value];
- } else {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsDeleteGroupAnnounceFormat), str];
- }
- } break;
- case V2TIM_GROUP_INFO_CHANGE_TYPE_FACE: {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAvatarFormat), str];
- } break;
- case V2TIM_GROUP_INFO_CHANGE_TYPE_OWNER: {
- if (userList.count) {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupOwnerFormat), str, userList.firstObject];
- } else {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupOwnerFormat), str, info.value];
- }
- } break;
- case V2TIM_GROUP_INFO_CHANGE_TYPE_SHUT_UP_ALL: {
- if (info.boolValue) {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSetShutupAllFormat), opUser];
- } else {
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitCancelShutupAllFormat), opUser];
- }
- } break;
- case V2TIM_GROUP_INFO_CHANGE_TYPE_GROUP_ADD_OPT: {
- uint32_t addOpt = info.intValue;
- NSString *addOptDesc = @"unknown";
- if (addOpt == V2TIM_GROUP_ADD_FORBID) {
- addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileJoinDisable);
- } else if (addOpt == V2TIM_GROUP_ADD_AUTH) {
- addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAdminApprove);
- } else if (addOpt == V2TIM_GROUP_ADD_ANY) {
- addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAutoApproval);
- }
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupAddOptFormat), str, addOptDesc];
- } break;
- case V2TIM_GROUP_INFO_CHANGE_TYPE_GROUP_APPROVE_OPT: {
- uint32_t addOpt = info.intValue;
- NSString *addOptDesc = @"unknown";
- if (addOpt == V2TIM_GROUP_ADD_FORBID) {
- addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileInviteDisable);
- } else if (addOpt == V2TIM_GROUP_ADD_AUTH) {
- addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAdminApprove);
- } else if (addOpt == V2TIM_GROUP_ADD_ANY) {
- addOptDesc = TIMCommonLocalizableString(TUIKitGroupProfileAutoApproval);
- }
- str = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsEditGroupInviteOptFormat), str, addOptDesc];
- } break;
- default:
- break;
- }
- }
- return rtlString(str);
- }
- + (NSString *)getOpUserName:(V2TIMGroupMemberInfo *)info {
- NSString *opUser;
- if (info.nameCard.length > 0) {
- opUser = info.nameCard;
- } else if (info.nickName.length > 0) {
- opUser = info.nickName;
- } else {
- opUser = info.userID;
- }
- return opUser;
- }
- + (NSMutableArray *)getUserNameList:(NSArray<V2TIMGroupMemberInfo *> *)infoList {
- NSMutableArray<NSString *> *userNameList = [NSMutableArray array];
- for (V2TIMGroupMemberInfo *info in infoList) {
- if (info.nameCard.length > 0) {
- [userNameList addObject:info.nameCard];
- } else if (info.nickName.length > 0) {
- [userNameList addObject:info.nickName];
- } else {
- if (info.userID.length > 0) {
- [userNameList addObject:info.userID];
- }
- }
- }
- return userNameList;
- }
- + (NSMutableArray *)getUserIDList:(NSArray<V2TIMGroupMemberInfo *> *)infoList {
- NSMutableArray<NSString *> *userIDList = [NSMutableArray array];
- for (V2TIMGroupMemberInfo *info in infoList) {
- if (info.userID.length > 0) {
- [userIDList addObject:info.userID];
- }
- }
- return userIDList;
- }
- + (NSString *)getShowName:(V2TIMMessage *)message {
- NSString *showName = message.sender;
- if (message.nameCard.length > 0) {
- showName = message.nameCard;
- } else if (message.friendRemark.length > 0) {
- showName = message.friendRemark;
- } else if (message.nickName.length > 0) {
- showName = message.nickName;
- }
- return showName;
- }
- + (NSString *)getUserName:(V2TIMGroupTipsElem *)tips with:(NSString *)userId {
- NSString *str = @"";
- for (V2TIMGroupMemberInfo *info in tips.memberList) {
- if ([info.userID isEqualToString:userId]) {
- if (info.nameCard.length > 0) {
- str = info.nameCard;
- } else if (info.friendRemark.length > 0) {
- str = info.friendRemark;
- } else if (info.nickName.length > 0) {
- str = info.nickName;
- } else {
- str = userId;
- }
- break;
- }
- }
- return str;
- }
- @end
|