Files
midi_ios/TUIKit/TUIChat/BaseDataProvider/Impl/TUIMessageDataProvider.m
2025-09-11 18:25:41 +08:00

768 lines
33 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Created by Tencent on 2023/06/09.
// Copyright © 2023 Tencent. All rights reserved.
#import "TUIMessageDataProvider.h"
#import <AVFoundation/AVFoundation.h>
#import <TIMCommon/TUIRelationUserModel.h>
#import <TIMCommon/TUISystemMessageCellData.h>
#import <TUICore/TUILogin.h>
#import "TUIChatCallingDataProvider.h"
#import "TUICloudCustomDataTypeCenter.h"
#import "TUIFaceMessageCellData.h"
#import "TUIFileMessageCellData.h"
#import "TUIImageMessageCellData.h"
#import "TUIJoinGroupMessageCellData.h"
#import "TUIMergeMessageCellData.h"
#import "TUIMessageDataProvider+MessageDeal.h"
#import "TUIMessageProgressManager.h"
#import "TUIReplyMessageCellData.h"
#import "TUITextMessageCellData.h"
#import "TUIVideoMessageCellData.h"
#import "TUIVoiceMessageCellData.h"
/**
* The maximum editable time after the message is recalled, default is (2 * 60)
*/
#define MaxReEditMessageDelay 2 * 60
#define kIsCustomMessageFromPlugin @"kIsCustomMessageFromPlugin"
static Class<TUIMessageDataProviderDataSource> gDataSourceClass = nil;
@implementation TUIMessageDataProvider
#pragma mark - Life cycle
- (void)dealloc {
gCallingDataProvider = nil;
}
+ (void)setDataSourceClass:(Class<TUIMessageDataProviderDataSource>)dataSourceClass {
gDataSourceClass = dataSourceClass;
}
#pragma mark - TUIMessageCellData parser
+ (nullable TUIMessageCellData *)getCellData:(V2TIMMessage *)message {
// 1 Parse cell data
TUIMessageCellData *data = [self parseMessageCellDataFromMessageStatus:message];
if (data == nil) {
data = [self parseMessageCellDataFromMessageCustomData:message];
}
if (data == nil) {
data = [self parseMessageCellDataFromMessageElement:message];
}
// 2 Fill in property if needed
if (data) {
[self fillPropertyToCellData:data ofMessage:message];
} else {
NSLog(@"current message will be ignored in chat page, msg:%@", message);
}
return data;
}
+ (nullable TUIMessageCellData *)parseMessageCellDataFromMessageStatus:(V2TIMMessage *)message {
TUIMessageCellData *data = nil;
if (message.status == V2TIM_MSG_STATUS_LOCAL_REVOKED) {
data = [TUIMessageDataProvider getRevokeCellData:message];
}
return data;
}
+ (nullable TUIMessageCellData *)parseMessageCellDataFromMessageCustomData:(V2TIMMessage *)message {
TUIMessageCellData *data = nil;
if ([message isContainsCloudCustomOfDataType:TUICloudCustomDataType_MessageReply]) {
/**
* Determine whether to include "reply-message"
*/
data = [TUIReplyMessageCellData getCellData:message];
} else if ([message isContainsCloudCustomOfDataType:TUICloudCustomDataType_MessageReference]) {
/**
* Determine whether to include "quote-message"
*/
data = [TUIReferenceMessageCellData getCellData:message];
}
return data;
}
+ (nullable TUIMessageCellData *)parseMessageCellDataFromMessageElement:(V2TIMMessage *)message {
TUIMessageCellData *data = nil;
switch (message.elemType) {
case V2TIM_ELEM_TYPE_TEXT: {
data = [TUITextMessageCellData getCellData:message];
} break;
case V2TIM_ELEM_TYPE_IMAGE: {
data = [TUIImageMessageCellData getCellData:message];
} break;
case V2TIM_ELEM_TYPE_SOUND: {
data = [TUIVoiceMessageCellData getCellData:message];
} break;
case V2TIM_ELEM_TYPE_VIDEO: {
data = [TUIVideoMessageCellData getCellData:message];
} break;
case V2TIM_ELEM_TYPE_FILE: {
data = [TUIFileMessageCellData getCellData:message];
} break;
case V2TIM_ELEM_TYPE_FACE: {
data = [TUIFaceMessageCellData getCellData:message];
} break;
case V2TIM_ELEM_TYPE_GROUP_TIPS: {
data = [self getSystemCellData:message];
} break;
case V2TIM_ELEM_TYPE_MERGER: {
data = [TUIMergeMessageCellData getCellData:message];
} break;
case V2TIM_ELEM_TYPE_CUSTOM: {
data = [self getCustomMessageCellData:message];
} break;
default:
data = [self getUnsupportedCellData:message];
break;
}
return data;
}
+ (void)fillPropertyToCellData:(TUIMessageCellData *)data ofMessage:(V2TIMMessage *)message {
data.innerMessage = message;
if (message.groupID.length > 0 && !message.isSelf && ![data isKindOfClass:[TUISystemMessageCellData class]]) {
data.showName = YES;
}
switch (message.status) {
case V2TIM_MSG_STATUS_SEND_SUCC:
data.status = Msg_Status_Succ;
break;
case V2TIM_MSG_STATUS_SEND_FAIL:
data.status = Msg_Status_Fail;
break;
case V2TIM_MSG_STATUS_SENDING:
data.status = Msg_Status_Sending_2;
break;
default:
break;
}
/**
* Update progress of message uploading/downloading
*/
{
NSInteger uploadProgress = [TUIMessageProgressManager.shareManager uploadProgressForMessage:message.msgID];
NSInteger downloadProgress = [TUIMessageProgressManager.shareManager downloadProgressForMessage:message.msgID];
if ([data conformsToProtocol:@protocol(TUIMessageCellDataFileUploadProtocol)]) {
((id<TUIMessageCellDataFileUploadProtocol>)data).uploadProgress = uploadProgress;
}
if ([data conformsToProtocol:@protocol(TUIMessageCellDataFileDownloadProtocol)]) {
((id<TUIMessageCellDataFileDownloadProtocol>)data).downladProgress = downloadProgress;
((id<TUIMessageCellDataFileDownloadProtocol>)data).isDownloading = (downloadProgress != 0) && (downloadProgress != 100);
}
}
/**
* Determine whether to include "replies-message"
*/
if ([message isContainsCloudCustomOfDataType:TUICloudCustomDataType_MessageReplies]) {
[message doThingsInContainsCloudCustomOfDataType:TUICloudCustomDataType_MessageReplies
callback:^(BOOL isContains, id obj) {
if (isContains) {
if ([data isKindOfClass:TUISystemMessageCellData.class] ||
[data isKindOfClass:TUIJoinGroupMessageCellData.class]) {
data.showMessageModifyReplies = NO;
} else {
data.showMessageModifyReplies = YES;
}
if (obj && [obj isKindOfClass:NSDictionary.class]) {
NSDictionary *dic = (NSDictionary *)obj;
NSString *typeStr =
[TUICloudCustomDataTypeCenter convertType2String:TUICloudCustomDataType_MessageReplies];
NSDictionary *messageReplies = [dic valueForKey:typeStr];
NSArray *repliesArr = [messageReplies valueForKey:@"replies"];
if ([repliesArr isKindOfClass:NSArray.class]) {
data.messageModifyReplies = repliesArr.copy;
}
}
}
}];
}
}
+ (nullable TUIMessageCellData *)getCustomMessageCellData:(V2TIMMessage *)message {
// ************************************************************************************
// ************************************************************************************
// **The compatible processing logic of TUICallKit will be removed after***************
// **TUICallKit is connected according to the standard process. ***********************
// ************************************************************************************
// ************************************************************************************
TUIMessageCellData *data = nil;
id<TUIChatCallingInfoProtocol> callingInfo = nil;
if ([self.callingDataProvider isCallingMessage:message callingInfo:&callingInfo]) {
// Voice-video-call message
if (callingInfo) {
// Supported voice-video-call message
if (callingInfo.excludeFromHistory) {
// This message will be ignore in chat page
data = nil;
} else {
data = [self getCallingCellData:callingInfo];
if (data == nil) {
data = [self getUnsupportedCellData:message];
}
}
} else {
// Unsupported voice-video-call message
data = [self getUnsupportedCellData:message];
}
return data;
}
// ************************************************************************************
// ************************************************************************************
// ************************************************************************************
// ************************************************************************************
NSString *businessID = nil;
BOOL excludeFromHistory = NO;
V2TIMSignalingInfo *signalingInfo = [V2TIMManager.sharedInstance getSignallingInfo:message];
if (signalingInfo) {
// This message is signaling message
BOOL isOnlineOnly = NO;
@try {
isOnlineOnly = [[message valueForKeyPath:@"message.IsOnlineOnly"] boolValue];
} @catch (NSException *exception) {
isOnlineOnly = NO;
}
excludeFromHistory = isOnlineOnly || (message.isExcludedFromLastMessage && message.isExcludedFromUnreadCount);
businessID = [self getSignalingBusinessID:signalingInfo];
} else {
// This message is normal custom message
excludeFromHistory = NO;
businessID = [self getCustomBusinessID:message];
}
if (excludeFromHistory) {
// Return nil means not display in the chat page
return nil;
}
if (businessID.length > 0) {
Class cellDataClass = nil;
if (gDataSourceClass && [gDataSourceClass respondsToSelector:@selector(onGetCustomMessageCellDataClass:)]) {
cellDataClass = [gDataSourceClass onGetCustomMessageCellDataClass:businessID];
}
if (cellDataClass && [cellDataClass respondsToSelector:@selector(getCellData:)]) {
TUIMessageCellData *data = [cellDataClass getCellData:message];
if (data.shouldHide) {
return nil;
} else {
data.reuseId = businessID;
return data;
}
}
// In CustomerService scenarios, unsupported messages are not displayed directly.
if ([businessID tui_containsString:BussinessID_CustomerService]) {
return nil;
}
return [self getUnsupportedCellData:message];
} else {
return [self getUnsupportedCellData:message];
}
}
+ (TUIMessageCellData *)getUnsupportedCellData:(V2TIMMessage *)message {
TUITextMessageCellData *cellData = [[TUITextMessageCellData alloc] initWithDirection:(message.isSelf ? MsgDirectionOutgoing : MsgDirectionIncoming)];
if ([message.userID isEqualToString:@"@RBT#u88"]) {
V2TIMCustomElem *el = message.customElem;
NSError *error = nil;
// 将 JSON 数据转换为字典
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:el.data options:kNilOptions error:&error];
NSArray *arr = dictionary[@"chunks"];
NSString*str = @"";
for (NSString*s in arr) {
str = [str stringByAppendingFormat:@"%@",s];
}
cellData.content = str;
}else{
cellData.content = TIMCommonLocalizableString(TUIKitNotSupportThisMessage);
}
cellData.reuseId = TTextMessageCell_ReuseId;
return cellData;
}
+ (nullable TUISystemMessageCellData *)getSystemCellData:(V2TIMMessage *)message {
V2TIMGroupTipsElem *tip = message.groupTipsElem;
NSString *opUserName = [self getOpUserName:tip.opMember];
NSMutableArray<NSString *> *userNameList = [self getUserNameList:tip.memberList];
NSMutableArray<NSString *> *userIDList = [self getUserIDList:tip.memberList];
if (tip.type == V2TIM_GROUP_TIPS_TYPE_JOIN || tip.type == V2TIM_GROUP_TIPS_TYPE_INVITE || tip.type == V2TIM_GROUP_TIPS_TYPE_KICKED ||
tip.type == V2TIM_GROUP_TIPS_TYPE_GROUP_INFO_CHANGE || tip.type == V2TIM_GROUP_TIPS_TYPE_QUIT ||
tip.type == V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_ADDED || tip.type == V2TIM_GROUP_TIPS_TYPE_PINNED_MESSAGE_DELETED) {
TUIJoinGroupMessageCellData *joinGroupData = [[TUIJoinGroupMessageCellData alloc] initWithDirection:MsgDirectionIncoming];
joinGroupData.content = [self getDisplayString:message];
joinGroupData.opUserName = opUserName;
joinGroupData.opUserID = tip.opMember.userID;
joinGroupData.userNameList = userNameList;
joinGroupData.userIDList = userIDList;
joinGroupData.reuseId = TJoinGroupMessageCell_ReuseId;
return joinGroupData;
} else {
TUISystemMessageCellData *sysdata = [[TUISystemMessageCellData alloc] initWithDirection:MsgDirectionIncoming];
sysdata.content = [self getDisplayString:message];
sysdata.reuseId = TSystemMessageCell_ReuseId;
if (sysdata.content.length) {
return sysdata;
}
}
return nil;
}
+ (nullable TUISystemMessageCellData *)getRevokeCellData:(V2TIMMessage *)message {
TUISystemMessageCellData *revoke = [[TUISystemMessageCellData alloc] initWithDirection:(message.isSelf ? MsgDirectionOutgoing : MsgDirectionIncoming)];
revoke.reuseId = TSystemMessageCell_ReuseId;
revoke.content = [self getRevokeDispayString:message];
revoke.innerMessage = message;
V2TIMUserFullInfo *revokerInfo = message.revokerInfo;
if (message.isSelf) {
if (message.elemType == V2TIM_ELEM_TYPE_TEXT && fabs([[NSDate date] timeIntervalSinceDate:message.timestamp]) < MaxReEditMessageDelay) {
if (revokerInfo && ![revokerInfo.userID isEqualToString:message.sender]) {
// Super User revoke
revoke.supportReEdit = NO;
} else {
revoke.supportReEdit = YES;
}
}
} else if (message.groupID.length > 0) {
/**
* For the name display of group messages, the group business card is displayed first, the nickname has the second priority, and the user ID has the
* lowest priority.
*/
NSString *userName = [TUIMessageDataProvider getShowName:message];
TUIJoinGroupMessageCellData *joinGroupData = [[TUIJoinGroupMessageCellData alloc] initWithDirection:MsgDirectionIncoming];
joinGroupData.content = [self getRevokeDispayString:message];
joinGroupData.opUserID = message.sender;
joinGroupData.opUserName = userName;
joinGroupData.reuseId = TJoinGroupMessageCell_ReuseId;
return joinGroupData;
}
return revoke;
}
+ (nullable TUISystemMessageCellData *)getSystemMsgFromDate:(NSDate *)date {
TUISystemMessageCellData *system = [[TUISystemMessageCellData alloc] initWithDirection:MsgDirectionOutgoing];
system.content = [TUITool convertDateToStr:date];
system.reuseId = TSystemMessageCell_ReuseId;
system.type = TUISystemMessageTypeDate;
return system;
}
#pragma mark - Last message parser
+ (void)asyncGetDisplayString:(NSArray<V2TIMMessage *> *)messageList callback:(void (^)(NSDictionary<NSString *, NSString *> *))callback {
if (!callback) {
return;
}
NSMutableDictionary *originDisplayMap = [NSMutableDictionary dictionary];
NSMutableArray *cellDataList = [NSMutableArray array];
for (V2TIMMessage *message in messageList) {
TUIMessageCellData *cellData = [self getCellData:message];
if (cellData) {
[cellDataList addObject:cellData];
}
NSString *displayString = [self getDisplayString:message];
if (displayString && message.msgID) {
originDisplayMap[message.msgID] = displayString;
}
}
if (cellDataList.count == 0) {
callback(@{});
return;
}
TUIMessageDataProvider *provider = [[TUIMessageDataProvider alloc] init];
NSArray *additionUserIDList = [provider getUserIDListForAdditionalUserInfo:cellDataList];
if (additionUserIDList.count == 0) {
callback(@{});
return;
}
NSMutableDictionary *result = [NSMutableDictionary dictionary];
[provider
requestForAdditionalUserInfo:cellDataList
callback:^{
for (TUIMessageCellData *cellData in cellDataList) {
[cellData.additionalUserInfoResult
enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, TUIRelationUserModel *_Nonnull obj, BOOL *_Nonnull stop) {
NSString *str = [NSString stringWithFormat:@"{%@}", key];
NSString *showName = obj.userID;
if (obj.nameCard.length > 0) {
showName = obj.nameCard;
} else if (obj.friendRemark.length > 0) {
showName = obj.friendRemark;
} else if (obj.nickName.length > 0) {
showName = obj.nickName;
}
NSString *displayString = [originDisplayMap objectForKey:cellData.msgID];
if (displayString && [displayString containsString:str]) {
displayString = [displayString stringByReplacingOccurrencesOfString:str withString:showName];
result[cellData.msgID] = displayString;
}
callback(result);
}];
}
}];
}
+ (nullable NSString *)getDisplayString:(V2TIMMessage *)message {
BOOL hasRiskContent = message.hasRiskContent;
BOOL isRevoked = (message.status == V2TIM_MSG_STATUS_LOCAL_REVOKED);
if (hasRiskContent && !isRevoked) {
return TIMCommonLocalizableString(TUIKitMessageDisplayRiskContent);
}
NSString *str = [self parseDisplayStringFromMessageStatus:message];
if (str == nil) {
str = [self parseDisplayStringFromMessageElement:message];
}
if (str == nil) {
NSLog(@"current message will be ignored in chat page or conversation list page, msg:%@", message);
}
return str;
}
+ (nullable NSString *)parseDisplayStringFromMessageStatus:(V2TIMMessage *)message {
NSString *str = nil;
if (message.status == V2TIM_MSG_STATUS_LOCAL_REVOKED) {
str = [self getRevokeDispayString:message];
}
return str;
}
+ (nullable NSString *)parseDisplayStringFromMessageElement:(V2TIMMessage *)message {
NSString *str = nil;
switch (message.elemType) {
case V2TIM_ELEM_TYPE_TEXT: {
str = [TUITextMessageCellData getDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_IMAGE: {
str = [TUIImageMessageCellData getDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_SOUND: {
str = [TUIVoiceMessageCellData getDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_VIDEO: {
str = [TUIVideoMessageCellData getDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_FILE: {
str = [TUIFileMessageCellData getDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_FACE: {
str = [TUIFaceMessageCellData getDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_MERGER: {
str = [TUIMergeMessageCellData getDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_GROUP_TIPS: {
str = [self getGroupTipsDisplayString:message];
} break;
case V2TIM_ELEM_TYPE_CUSTOM: {
str = [self getCustomDisplayString:message];
} break;
default:
str = TIMCommonLocalizableString(TUIKitMessageTipsUnsupportCustomMessage);
break;
}
return str;
}
+ (nullable NSString *)getCustomDisplayString:(V2TIMMessage *)message {
// ************************************************************************************
// ************************************************************************************
// ************** TUICallKit TUICallKit *************
// ************************************************************************************
// ************************************************************************************
NSString *str = nil;
id<TUIChatCallingInfoProtocol> callingInfo = nil;
if ([self.callingDataProvider isCallingMessage:message callingInfo:&callingInfo]) {
// Voice-video-call message
if (callingInfo) {
// Supported voice-video-call message
if (callingInfo.excludeFromHistory) {
// This message will be ignore in chat page
str = nil;
} else {
// Get display text
str = callingInfo.content ?: TIMCommonLocalizableString(TUIKitMessageTipsUnsupportCustomMessage);
}
} else {
// Unsupported voice-video-call message
str = TIMCommonLocalizableString(TUIKitMessageTipsUnsupportCustomMessage);
}
return str;
}
// ************************************************************************************
// ************************************************************************************
// ************************************************************************************
// ************************************************************************************
NSString *businessID = nil;
BOOL excludeFromHistory = NO;
V2TIMSignalingInfo *signalingInfo = [V2TIMManager.sharedInstance getSignallingInfo:message];
if (signalingInfo) {
// This message is signaling message
excludeFromHistory = message.isExcludedFromLastMessage && message.isExcludedFromUnreadCount;
businessID = [self getSignalingBusinessID:signalingInfo];
} else {
// This message is normal custom message
excludeFromHistory = NO;
businessID = [self getCustomBusinessID:message];
}
if (excludeFromHistory) {
// Return nil means not display int the chat page
return nil;
}
if (businessID.length > 0) {
Class cellDataClass = nil;
if (gDataSourceClass && [gDataSourceClass respondsToSelector:@selector(onGetCustomMessageCellDataClass:)]) {
cellDataClass = [gDataSourceClass onGetCustomMessageCellDataClass:businessID];
}
if (cellDataClass && [cellDataClass respondsToSelector:@selector(getDisplayString:)]) {
return [cellDataClass getDisplayString:message];
}
// In CustomerService scenarios, unsupported messages are not displayed directly.
if ([businessID tui_containsString:BussinessID_CustomerService]) {
return nil;
}
return TIMCommonLocalizableString(TUIKitMessageTipsUnsupportCustomMessage);
} else {
return TIMCommonLocalizableString(TUIKitMessageTipsUnsupportCustomMessage);
}
}
#pragma mark - Data source operate
- (void)processQuoteMessage:(NSArray<TUIMessageCellData *> *)uiMsgs {
if (uiMsgs.count == 0) {
return;
}
@weakify(self);
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, concurrentQueue, ^{
for (TUIMessageCellData *cellData in uiMsgs) {
if (![cellData isKindOfClass:TUIReplyMessageCellData.class]) {
continue;
}
TUIReplyMessageCellData *myData = (TUIReplyMessageCellData *)cellData;
__weak typeof(myData) weakMyData = myData;
myData.onFinish = ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSUInteger index = [self.uiMsgs indexOfObject:weakMyData];
if (index != NSNotFound) {
// if messageData exist In datasource, reload this data.
[UIView performWithoutAnimation:^{
@strongify(self);
[self.dataSource dataProviderDataSourceWillChange:self];
[self.dataSource dataProviderDataSourceChange:self
withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
atIndex:index
animation:NO];
[self.dataSource dataProviderDataSourceDidChange:self];
}];
}
});
};
dispatch_group_enter(group);
[self loadOriginMessageFromReplyData:myData
dealCallback:^{
dispatch_group_leave(group);
dispatch_async(dispatch_get_main_queue(), ^{
NSUInteger index = [self.uiMsgs indexOfObject:weakMyData];
if (index != NSNotFound) {
// if messageData exist In datasource, reload this data.
[UIView performWithoutAnimation:^{
@strongify(self);
[self.dataSource dataProviderDataSourceWillChange:self];
[self.dataSource dataProvider:self onRemoveHeightCache:weakMyData];
[self.dataSource dataProviderDataSourceChange:self
withType:TUIMessageBaseDataProviderDataSourceChangeTypeReload
atIndex:index
animation:NO];
[self.dataSource dataProviderDataSourceDidChange:self];
}];
}
});
}];
}
});
dispatch_group_notify(group, dispatch_get_main_queue(),
^{
// complete
});
}
- (void)deleteUIMsgs:(NSArray<TUIMessageCellData *> *)uiMsgs SuccBlock:(nullable V2TIMSucc)succ FailBlock:(nullable V2TIMFail)fail {
NSMutableArray *uiMsgList = [NSMutableArray array];
NSMutableArray *imMsgList = [NSMutableArray array];
for (TUIMessageCellData *uiMsg in uiMsgs) {
if ([self.uiMsgs containsObject:uiMsg]) {
// Check content cell
[uiMsgList addObject:uiMsg];
[imMsgList addObject:uiMsg.innerMessage];
// Check time cell which also need to be deleted
NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
index--;
if (index >= 0 && index < self.uiMsgs.count && [[self.uiMsgs objectAtIndex:index] isKindOfClass:TUISystemMessageCellData.class]) {
TUISystemMessageCellData *systemCellData = (TUISystemMessageCellData *)[self.uiMsgs objectAtIndex:index];
if (systemCellData.type == TUISystemMessageTypeDate) {
[uiMsgList addObject:systemCellData];
}
}
}
}
if (imMsgList.count == 0) {
if (fail) {
fail(ERR_INVALID_PARAMETERS, @"not found uiMsgs");
}
return;
}
@weakify(self);
[self.class deleteMessages:imMsgList
succ:^{
@strongify(self);
[self.dataSource dataProviderDataSourceWillChange:self];
for (TUIMessageCellData *uiMsg in uiMsgList) {
NSInteger index = [self.uiMsgs indexOfObject:uiMsg];
[self.dataSource dataProviderDataSourceChange:self
withType:TUIMessageBaseDataProviderDataSourceChangeTypeDelete
atIndex:index
animation:YES];
}
[self removeUIMsgList:uiMsgList];
[self.dataSource dataProviderDataSourceDidChange:self];
if (succ) {
succ();
}
}
fail:fail];
}
- (void)removeUIMsgList:(NSArray<TUIMessageCellData *> *)cellDatas {
for (TUIMessageCellData *uiMsg in cellDatas) {
[self removeUIMsg:uiMsg];
}
}
#pragma mark - Utils
+ (nullable NSString *)getCustomBusinessID:(V2TIMMessage *)message {
if (message == nil || message.customElem.data == nil) {
return nil;
}
NSError *error = nil;
NSDictionary *param = [NSJSONSerialization JSONObjectWithData:message.customElem.data options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(@"parse customElem data error: %@", error);
return nil;
}
if (!param || ![param isKindOfClass:[NSDictionary class]]) {
return nil;
}
NSString *businessID = param[BussinessID];
if ([businessID isKindOfClass:[NSString class]] && businessID.length > 0) {
return businessID;
} else {
if ([param.allKeys containsObject:BussinessID_CustomerService]) {
NSString *src = param[BussinessID_Src_CustomerService];
if (src.length > 0 && [src isKindOfClass:[NSString class]]) {
return [NSString stringWithFormat:@"%@%@", BussinessID_CustomerService, src];
}
}
return nil;
}
}
+ (nullable NSString *)getSignalingBusinessID:(V2TIMSignalingInfo *)signalInfo {
if (signalInfo.data == nil) {
return nil;
}
NSError *error = nil;
NSDictionary *param = [NSJSONSerialization JSONObjectWithData:[signalInfo.data dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingAllowFragments
error:&error];
if (error) {
NSLog(@"parse customElem data error: %@", error);
return nil;
}
if (!param || ![param isKindOfClass:[NSDictionary class]]) {
return nil;
}
NSString *businessID = param[BussinessID];
if (!businessID || ![businessID isKindOfClass:[NSString class]]) {
return nil;
}
return businessID;
}
#pragma mark - TUICallKit
static TUIChatCallingDataProvider *gCallingDataProvider;
+ (TUIChatCallingDataProvider *)callingDataProvider {
if (gCallingDataProvider == nil) {
gCallingDataProvider = [[TUIChatCallingDataProvider alloc] init];
}
return gCallingDataProvider;
}
+ (TUIMessageCellData *)getCallingCellData:(id<TUIChatCallingInfoProtocol>)callingInfo {
TMsgDirection direction = MsgDirectionIncoming;
if (callingInfo.direction == TUICallMessageDirectionIncoming) {
direction = MsgDirectionIncoming;
} else if (callingInfo.direction == TUICallMessageDirectionOutgoing) {
direction = MsgDirectionOutgoing;
}
if (callingInfo.participantType == TUICallParticipantTypeC2C) {
TUITextMessageCellData *cellData = [[TUITextMessageCellData alloc] initWithDirection:direction];
if (callingInfo.streamMediaType == TUICallStreamMediaTypeVoice) {
cellData.isAudioCall = YES;
} else if (callingInfo.streamMediaType == TUICallStreamMediaTypeVideo) {
cellData.isVideoCall = YES;
} else {
cellData.isAudioCall = NO;
cellData.isVideoCall = NO;
}
cellData.content = callingInfo.content;
cellData.isCaller = (callingInfo.participantRole == TUICallParticipantRoleCaller);
cellData.showUnreadPoint = callingInfo.showUnreadPoint;
cellData.isUseMsgReceiverAvatar = callingInfo.isUseReceiverAvatar;
cellData.reuseId = TTextMessageCell_ReuseId;
return cellData;
} else if (callingInfo.participantType == TUICallParticipantTypeGroup) {
TUISystemMessageCellData *cellData = [[TUISystemMessageCellData alloc] initWithDirection:direction];
cellData.content = callingInfo.content;
cellData.replacedUserIDList = callingInfo.participantIDList;
cellData.reuseId = TSystemMessageCell_ReuseId;
return cellData;
} else {
return nil;
}
}
@end