329 lines
14 KiB
Objective-C
329 lines
14 KiB
Objective-C
//
|
|
// TUIEmojiExtensionObserver.m
|
|
// TUIEmojiPlugin
|
|
//
|
|
// Created by cologne on 2023/11/22.
|
|
//
|
|
|
|
#import "TUIEmojiExtensionObserver.h"
|
|
|
|
#import <TIMCommon/TIMPopActionProtocol.h>
|
|
#import <TIMCommon/TUIMessageCell.h>
|
|
#import <TUIChat/TUIChatPopMenu.h>
|
|
#import <TUICore/TUICore.h>
|
|
#import <TUICore/TUIDefine.h>
|
|
#import <TUICore/UIView+TUILayout.h>
|
|
#import <TUICore/TUILogin.h>
|
|
#import "TUIReactPopRecentView.h"
|
|
#import "TUIReactPopEmojiView.h"
|
|
#import "TUIReactPreview.h"
|
|
#import "TUIReactModel.h"
|
|
#import "TUIEmojiReactDataProvider.h"
|
|
#import "TUIMessageCellData+Reaction.h"
|
|
#import "TUIReactPreview_Minimalist.h"
|
|
#import "TUIReactMembersController.h"
|
|
#import "TUIReactPopContextRecentView.h"
|
|
#import <TUIChat/TUIChatPopContextController.h>
|
|
#import "TUIEmojiMessageReactPreLoadProvider.h"
|
|
#import "TUIReactUtil.h"
|
|
|
|
@interface TUIEmojiExtensionObserver () <TUIExtensionProtocol>
|
|
|
|
@property(nonatomic, weak) UINavigationController *navVC;
|
|
@property(nonatomic, weak) TUICommonTextCellData *cellData;
|
|
|
|
@end
|
|
|
|
@implementation TUIEmojiExtensionObserver
|
|
|
|
static id gShareInstance = nil;
|
|
|
|
+ (void)load {
|
|
|
|
// UI extensions in pop menu when message is long pressed.
|
|
|
|
[TUICore registerExtension:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_ClassicExtensionID object:TUIEmojiExtensionObserver.shareInstance];
|
|
[TUICore registerExtension:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_MinimalistExtensionID object:TUIEmojiExtensionObserver.shareInstance];
|
|
|
|
[TUICore registerExtension:TUICore_TUIChatExtension_ChatPopMenuReactDetailView_ClassicExtensionID object:TUIEmojiExtensionObserver.shareInstance];
|
|
[TUICore registerExtension:TUICore_TUIChatExtension_ChatPopMenuReactDetailView_MinimalistExtensionID object:TUIEmojiExtensionObserver.shareInstance];
|
|
|
|
|
|
[TUICore registerExtension:TUICore_TUIChatExtension_ChatMessageReactPreview_ClassicExtensionID object:TUIEmojiExtensionObserver.shareInstance];
|
|
[TUICore registerExtension:TUICore_TUIChatExtension_ChatMessageReactPreview_MinimalistExtensionID object:TUIEmojiExtensionObserver.shareInstance];
|
|
}
|
|
|
|
+ (instancetype)shareInstance {
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
gShareInstance = [[self alloc] init];
|
|
});
|
|
return gShareInstance;
|
|
}
|
|
|
|
- (instancetype)init {
|
|
if (self = [super init]) {
|
|
[self setupNotify];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)setupNotify {
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(fetchReactListByCellDatas:)
|
|
name:@"TUIKitFetchReactNotification"
|
|
object:nil];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onLoginSucceeded) name:TUILoginSuccessNotification object:nil];
|
|
|
|
}
|
|
#pragma mark - TUIKitFetchReactNotification
|
|
|
|
- (void)fetchReactListByCellDatas:(NSNotification *)notification {
|
|
NSArray<TUIMessageCellData *> *uiMsgs = notification.object;
|
|
TUIEmojiMessageReactPreLoadProvider *preLoadProvider = [[TUIEmojiMessageReactPreLoadProvider alloc] init];
|
|
NSInteger batchSize = 20;
|
|
NSInteger totalBatches = (uiMsgs.count + batchSize - 1) / batchSize;
|
|
for (NSInteger batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
|
|
NSRange batchRange = NSMakeRange(batchIndex * batchSize, MIN(batchSize, uiMsgs.count - batchIndex * batchSize));
|
|
NSArray<TUIMessageCellData *> *batchMsgs = [uiMsgs subarrayWithRange:batchRange];
|
|
[preLoadProvider getMessageReactions:batchMsgs maxUserCountPerReaction:5 succ:^{
|
|
for (TUIMessageCellData *cellData in batchMsgs) {
|
|
if (cellData.msgID) {
|
|
if (cellData.reactValueChangedCallback) {
|
|
cellData.reactValueChangedCallback(cellData.reactdataProvider.reactArray);
|
|
}
|
|
}
|
|
}
|
|
} fail:^(int code, NSString *desc) {
|
|
NSLog(@"Error fetching reactions for batch %ld: %d - %@", (long)batchIndex, code, desc);
|
|
}];
|
|
}
|
|
}
|
|
#pragma mark - TUIExtensionProtocol
|
|
- (BOOL)onRaiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param {
|
|
if ([extensionID isEqualToString:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_ClassicExtensionID]) {
|
|
TUIChatPopMenu *delegateView = [param objectForKey:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_Delegate];
|
|
if (![parentView isKindOfClass:UIView.class]) {
|
|
return NO;
|
|
}
|
|
|
|
TUIReactPopRecentView * emojiRecentView = [[TUIReactPopRecentView alloc] initWithFrame:CGRectZero];
|
|
[parentView addSubview:emojiRecentView];
|
|
emojiRecentView.frame = CGRectMake(0, 0, parentView.mm_w, 44);
|
|
emojiRecentView.backgroundColor = TUIChatDynamicColor(@"chat_pop_menu_bg_color", @"#FFFFFF");
|
|
emojiRecentView.needShowbottomLine = YES;
|
|
if ([delegateView isKindOfClass:TUIChatPopMenu.class]) {
|
|
emojiRecentView.delegateView = delegateView;
|
|
}
|
|
return YES;
|
|
}
|
|
else if ([extensionID isEqualToString:TUICore_TUIChatExtension_ChatPopMenuReactDetailView_ClassicExtensionID]) {
|
|
|
|
TUIChatPopMenu *delegateView = [param objectForKey:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_Delegate];
|
|
if (![parentView isKindOfClass:UIView.class]) {
|
|
return NO;
|
|
}
|
|
|
|
TUIReactPopEmojiView *emojiAdvanceView = [[TUIReactPopEmojiView alloc] initWithFrame:CGRectMake(0, 44 - 0.5, parentView.mm_w, TChatEmojiView_CollectionHeight + 10 + TChatEmojiView_Page_Height)];
|
|
[parentView addSubview:emojiAdvanceView];
|
|
[emojiAdvanceView setData:(id)[TIMConfig defaultConfig].chatPopDetailGroups];
|
|
if (delegateView) {
|
|
emojiAdvanceView.delegateView = delegateView;
|
|
}
|
|
emojiAdvanceView.alpha = 0;
|
|
emojiAdvanceView.faceCollectionView.scrollEnabled = YES;
|
|
emojiAdvanceView.faceCollectionView.delaysContentTouches = NO;
|
|
emojiAdvanceView.backgroundColor = TUIChatDynamicColor(@"chat_pop_menu_bg_color", @"#FFFFFF");
|
|
emojiAdvanceView.faceCollectionView.backgroundColor = emojiAdvanceView.backgroundColor;
|
|
|
|
return YES;
|
|
}
|
|
else if ([extensionID isEqualToString:TUICore_TUIChatExtension_ChatMessageReactPreview_ClassicExtensionID]) {
|
|
|
|
TUIMessageCell *delegateView = [param objectForKey:TUICore_TUIChatExtension_ChatMessageReactPreview_Delegate];
|
|
NSMutableDictionary *cacheMap = parentView.tui_extValueObj;
|
|
TUIReactPreview *cacheView = nil;
|
|
if (!cacheMap){
|
|
cacheMap = [NSMutableDictionary dictionaryWithCapacity:3];
|
|
}
|
|
else if ([cacheMap isKindOfClass:NSDictionary.class]) {
|
|
cacheView = [cacheMap objectForKey:NSStringFromClass(TUIReactPreview.class)];
|
|
}
|
|
else {
|
|
//cacheMap is not a dic ;
|
|
}
|
|
if (cacheView) {
|
|
[cacheView removeFromSuperview];
|
|
cacheView = nil;
|
|
}
|
|
TUIReactPreview *tagView = [[TUIReactPreview alloc] init];
|
|
[parentView addSubview:tagView];
|
|
[cacheMap setObject:tagView forKey:NSStringFromClass(TUIReactPreview.class)];
|
|
parentView.tui_extValueObj = cacheMap;
|
|
|
|
__weak typeof(self) weakSelf = self;
|
|
__weak typeof(tagView) weakTagView = tagView;
|
|
|
|
if (delegateView) {
|
|
tagView.delegateCell = (id)delegateView;
|
|
if (!delegateView.messageData.reactdataProvider) {
|
|
[delegateView.messageData setupReactDataProvider];
|
|
}
|
|
delegateView.messageData.reactValueChangedCallback = ^(NSArray<TUIReactModel *> * _Nonnull tagsArray) {
|
|
if (weakTagView) {
|
|
[weakTagView refreshByArray:(id)tagsArray];
|
|
}
|
|
};
|
|
}
|
|
|
|
if (delegateView.messageData.reactdataProvider.reactArray.count > 0) {
|
|
weakTagView.listArrM = [NSMutableArray arrayWithArray:delegateView.messageData.reactdataProvider.reactArray];
|
|
[weakTagView updateView];
|
|
if (!CGSizeEqualToSize(CGSizeZero, delegateView.messageData.messageContainerAppendSize)) {
|
|
delegateView.messageData.messageContainerAppendSize = weakTagView.frame.size;
|
|
[weakTagView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
make.bottom.mas_equalTo(parentView);
|
|
make.leading.mas_equalTo(parentView);
|
|
make.width.mas_equalTo(parentView);
|
|
make.height.mas_equalTo(delegateView.messageData.messageContainerAppendSize);
|
|
}];
|
|
}
|
|
else{
|
|
delegateView.messageData.messageContainerAppendSize = weakTagView.frame.size;
|
|
[weakTagView notifyReactionChanged];
|
|
}
|
|
}
|
|
else {
|
|
//When invisible, the height should be reset if there is a change in response
|
|
if (!CGSizeEqualToSize(CGSizeZero, delegateView.messageData.messageContainerAppendSize)) {
|
|
delegateView.messageData.messageContainerAppendSize = CGSizeZero;
|
|
[weakTagView notifyReactionChanged];
|
|
}
|
|
}
|
|
|
|
tagView.emojiClickCallback = ^(TUIReactModel *_Nonnull model) {
|
|
[weakSelf emojiClick:parentView ReactMessage:delegateView.messageData faceList:weakTagView.listArrM];
|
|
};
|
|
|
|
tagView.userClickCallback = ^(TUIReactModel * _Nonnull model) {
|
|
[weakSelf emojiClick:parentView ReactMessage:delegateView.messageData faceList:weakTagView.listArrM];
|
|
};
|
|
|
|
return YES;
|
|
}
|
|
|
|
//Minimalist
|
|
else if ([extensionID isEqualToString:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_MinimalistExtensionID]) {
|
|
|
|
TUIChatPopContextController *delegateVC = [param objectForKey:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_Delegate];
|
|
if (![parentView isKindOfClass:UIView.class]) {
|
|
return NO;
|
|
}
|
|
if (![TUIChatConfig defaultConfig].enablePopMenuEmojiReactAction) {
|
|
return NO;
|
|
}
|
|
|
|
TUIReactPopContextRecentView * emojiRecentView = [[TUIReactPopContextRecentView alloc] initWithFrame:CGRectZero];
|
|
[parentView addSubview:emojiRecentView];
|
|
emojiRecentView.frame = CGRectMake(0, 0,MAX(kTIMDefaultEmojiSize.width *8,parentView.mm_w), parentView.mm_h);
|
|
emojiRecentView.backgroundColor = [UIColor whiteColor];
|
|
emojiRecentView.needShowbottomLine = YES;
|
|
if ([delegateVC isKindOfClass:TUIChatPopContextController.class]) {
|
|
emojiRecentView.delegateVC = delegateVC;
|
|
}
|
|
return YES;
|
|
}
|
|
else if ([extensionID isEqualToString:TUICore_TUIChatExtension_ChatMessageReactPreview_MinimalistExtensionID]) {
|
|
|
|
TUIMessageCell *delegateView = [param objectForKey:TUICore_TUIChatExtension_ChatMessageReactPreview_Delegate];
|
|
NSMutableDictionary *cacheMap = parentView.tui_extValueObj;
|
|
TUIReactPreview_Minimalist *cacheView = nil;
|
|
if (!cacheMap){
|
|
cacheMap = [NSMutableDictionary dictionaryWithCapacity:3];
|
|
}
|
|
else if ([cacheMap isKindOfClass:NSDictionary.class]) {
|
|
cacheView = [cacheMap objectForKey:NSStringFromClass(TUIReactPreview_Minimalist.class)];
|
|
}
|
|
else {
|
|
//cacheMap is not a dic ;
|
|
}
|
|
if (cacheView) {
|
|
[cacheView removeFromSuperview];
|
|
cacheView = nil;
|
|
}
|
|
|
|
TUIReactPreview_Minimalist *tagView = [[TUIReactPreview_Minimalist alloc] init];
|
|
[parentView addSubview:tagView];
|
|
[cacheMap setObject:tagView forKey:NSStringFromClass(TUIReactPreview_Minimalist.class)];
|
|
parentView.tui_extValueObj = cacheMap;
|
|
|
|
__weak typeof(self) weakSelf = self;
|
|
__weak typeof(tagView) weakTagView = tagView;
|
|
|
|
if (delegateView) {
|
|
tagView.delegateCell = (id)delegateView;
|
|
if (!delegateView.messageData.reactdataProvider) {
|
|
[delegateView.messageData setupReactDataProvider];
|
|
}
|
|
delegateView.messageData.reactValueChangedCallback = ^(NSArray<TUIReactModel *> * _Nonnull tagsArray) {
|
|
if (weakTagView) {
|
|
[weakTagView refreshByArray:(id)tagsArray];
|
|
}
|
|
};
|
|
}
|
|
|
|
if (delegateView.messageData.reactdataProvider.reactArray.count > 0) {
|
|
weakTagView.reactlistArr = [NSMutableArray arrayWithArray:delegateView.messageData.reactdataProvider.reactArray];
|
|
[weakTagView updateView];
|
|
[weakTagView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
if (delegateView.messageData.direction == MsgDirectionIncoming) {
|
|
make.leading.mas_greaterThanOrEqualTo(delegateView.container).mas_offset(kScale390(16));
|
|
} else {
|
|
make.trailing.mas_lessThanOrEqualTo(delegateView.container).mas_offset(-kScale390(16));
|
|
}
|
|
make.width.mas_equalTo(delegateView.container);
|
|
make.top.mas_equalTo(delegateView.container.mas_bottom).mas_offset(-4);
|
|
make.height.mas_equalTo(20);
|
|
}];
|
|
if (CGSizeEqualToSize(CGSizeZero, delegateView.messageData.messageContainerAppendSize)) {
|
|
if (weakTagView) {
|
|
[weakTagView refreshByArray:delegateView.messageData.reactdataProvider.reactArray];
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//When invisible, the height should be reset if there is a change in response
|
|
if (!CGSizeEqualToSize(CGSizeZero, delegateView.messageData.messageContainerAppendSize)) {
|
|
delegateView.messageData.messageContainerAppendSize = CGSizeZero;
|
|
[weakTagView notifyReactionChanged];
|
|
}
|
|
}
|
|
|
|
tagView.emojiClickCallback = ^(TUIReactModel *_Nonnull model) {
|
|
// goto detailPage
|
|
[weakSelf emojiClick:parentView ReactMessage:delegateView.messageData faceList:weakTagView.reactlistArr];
|
|
};
|
|
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (void)emojiClick:(UIView *)view
|
|
ReactMessage:(TUIMessageCellData *)data
|
|
faceList:(NSArray<TUIReactModel *> *)listModel {
|
|
TUIReactMembersController *detailController = [[TUIReactMembersController alloc] init];
|
|
detailController.modalPresentationStyle = UIModalPresentationCustom;
|
|
detailController.tagsArray = listModel;
|
|
detailController.originData = data;
|
|
[view.mm_viewController presentViewController:detailController animated:YES completion:nil];
|
|
}
|
|
|
|
- (void)onLoginSucceeded {
|
|
[TUIReactUtil checkCommercialAbility];
|
|
}
|
|
|
|
@end
|