| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616 |
- // 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();
- }
- 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
|