增加换肤功能
This commit is contained in:
754
TUIKit/TUIChat/BaseDataProvider/Impl/TUIMessageDataProvider.m
Normal file
754
TUIKit/TUIChat/BaseDataProvider/Impl/TUIMessageDataProvider.m
Normal file
@@ -0,0 +1,754 @@
|
||||
|
||||
// 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)];
|
||||
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
|
||||
Reference in New Issue
Block a user