| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- //
- // TUIGroupChatViewController.m
- // TXIMSDK_TUIKit_iOS
- //
- // Created by kayev on 2021/6/17.
- // Copyright © 2023 Tencent. All rights reserved.
- //
- #import "ReactiveObjC/ReactiveObjC.h"
- #import <TIMCommon/NSString+TUIEmoji.h>
- #import <TIMCommon/TIMCommonModel.h>
- #import <TIMCommon/TIMDefine.h>
- #import <TUICore/NSDictionary+TUISafe.h>
- #import <TUICore/TUICore.h>
- #import <TUICore/TUILogin.h>
- #import "TUIBaseChatViewController+ProtectedAPI.h"
- #import "TUIGroupChatViewController.h"
- #import "TUIGroupPendencyController.h"
- #import "TUIGroupPendencyDataProvider.h"
- #import "TUILinkCellData.h"
- #import "TUIMessageDataProvider.h"
- #import "TUITextMessageCellData.h"
- #import "TUIChatFlexViewController.h"
- #import "TUIMessageController.h"
- #import "TUIGroupPinCell.h"
- #import "TUIGroupPinPageViewController.h"
- @interface TUIGroupChatViewController () <V2TIMGroupListener>
- //@property (nonatomic, strong) UIButton *atBtn;
- @property(nonatomic, strong) UIView *tipsView;
- @property(nonatomic, strong) UILabel *pendencyLabel;
- @property(nonatomic, strong) UIButton *pendencyBtn;
- @property(nonatomic, strong) TUIGroupPendencyDataProvider *pendencyViewModel;
- @property(nonatomic, strong) NSMutableArray<TUIUserModel *> *atUserList;
- @property(nonatomic, assign) BOOL responseKeyboard;
- @property(nonatomic, strong) TUIGroupPinCellView *oneGroupPinView;
- @property(nonatomic, strong) NSArray *groupPinList;
- @property(nonatomic, strong) TUIGroupPinPageViewController *pinPageVC;
- @end
- @implementation TUIGroupChatViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view.
- [self setupTipsView];
- [self setupGroupPinTips];
- [[V2TIMManager sharedInstance] addGroupListener:self];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(refreshTipsView)
- name:TUICore_TUIChatExtension_ChatViewTopArea_ChangedNotification
- object:nil];
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- [self refreshTipsView];
- }
- - (void)dealloc {
- [TUICore unRegisterEventByObject:self];
- }
- - (void)setupTipsView {
- self.tipsView = [[UIView alloc] initWithFrame:CGRectZero];
- self.tipsView.backgroundColor = RGB(246, 234, 190);
- [self.view addSubview:self.tipsView];
- self.tipsView.mm_height(24).mm_width(self.view.mm_w);
- self.pendencyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
- [self.tipsView addSubview:self.pendencyLabel];
- self.pendencyLabel.font = [UIFont systemFontOfSize:12];
- self.pendencyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
- [self.tipsView addSubview:self.pendencyBtn];
- [self.pendencyBtn setTitle:TIMCommonLocalizableString(TUIKitChatPendencyTitle) forState:UIControlStateNormal];
- [self.pendencyBtn.titleLabel setFont:[UIFont systemFontOfSize:12]];
- [self.pendencyBtn addTarget:self action:@selector(openPendency:) forControlEvents:UIControlEventTouchUpInside];
- [self.pendencyBtn sizeToFit];
- self.tipsView.alpha = 0;
- @weakify(self);
- [RACObserve(self.pendencyViewModel, unReadCnt) subscribeNext:^(NSNumber *unReadCnt) {
- @strongify(self);
- if ([unReadCnt intValue]) {
- self.pendencyLabel.text = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitChatPendencyRequestToJoinGroupFormat), unReadCnt];
- [self.pendencyLabel sizeToFit];
- CGFloat gap = (self.tipsView.mm_w - self.pendencyLabel.mm_w - self.pendencyBtn.mm_w - 8) / 2;
- self.pendencyLabel.mm_left(gap).mm__centerY(self.tipsView.mm_h / 2);
- self.pendencyBtn.mm_hstack(8);
- self.tipsView.alpha = 1;
- [self refreshTipsView];
- } else {
- self.tipsView.alpha = 0;
- }
- }];
- [self getPendencyList];
- }
- - (void)refreshTipsView {
- UIView *topView = [TUIGroupChatViewController topAreaBottomView];
- CGRect transRect = [topView convertRect:topView.bounds toView:self.view];
- self.tipsView.frame = CGRectMake(0, transRect.origin.y + transRect.size.height, self.tipsView.frame.size.width, self.tipsView.frame.size.height);
- }
- - (void)setupGroupPinTips {
- self.oneGroupPinView = [[TUIGroupPinCellView alloc] init];
- CGFloat margin = 0 ;
- self.oneGroupPinView.frame = CGRectMake(0, margin, self.view.frame.size.width, 62);
- UIView *topView = [TUIGroupChatViewController groupPinTopView];
- for (UIView *subview in topView.subviews) {
- [subview removeFromSuperview];
- }
- topView.frame = CGRectMake(0, 0, self.view.mm_w, 0);
- [topView addSubview:self.oneGroupPinView];
- @weakify(self);
- self.oneGroupPinView.isFirstPage = YES;
- self.oneGroupPinView.onClickCellView = ^(V2TIMMessage *originMessage) {
- @strongify(self);
- if (self.groupPinList.count >= 2) {
- [self gotoDetailPopPinPage];
- }
- else {
- [self jump2GroupPinHighlightLine:originMessage];
- }
- };
- self.oneGroupPinView.onClickRemove = ^(V2TIMMessage *originMessage) {
- @strongify(self);
- [self.messageController unPinGroupMessage:originMessage];
- };
- self.messageController.pinGroupMessageChanged = ^(NSArray * _Nonnull groupPinList) {
- @strongify(self);
- if (groupPinList.count > 0 ) {
- if (!self.oneGroupPinView.superview) {
- [topView addSubview:self.oneGroupPinView];
- }
- TUIMessageCellData * cellData = [TUIMessageDataProvider getCellData:[groupPinList lastObject]];
- [self.oneGroupPinView fillWithData:cellData];
- if (groupPinList.count >= 2) {
- [self.oneGroupPinView showMultiAnimation];
- topView.frame = CGRectMake(0, 0, self.view.mm_w, self.oneGroupPinView.frame.size.height +20 + margin);
- self.oneGroupPinView.removeButton.hidden = YES;
- }
- else {
- [self.oneGroupPinView hiddenMultiAnimation];
- topView.frame = CGRectMake(0, 0, self.view.mm_w, self.oneGroupPinView.frame.size.height + margin);
- if ([self.messageController isCurrentUserRoleSuperAdminInGroup]) {
- self.oneGroupPinView.removeButton.hidden = NO;
- }
- else {
- self.oneGroupPinView.removeButton.hidden = YES;
- }
- }
- }
- else {
- [self.oneGroupPinView removeFromSuperview];
- topView.frame = CGRectMake(0, 0, self.view.mm_w, 0);
- }
- self.groupPinList = groupPinList;
- [[NSNotificationCenter defaultCenter] postNotificationName:TUICore_TUIChatExtension_ChatViewTopArea_ChangedNotification object:nil];
- if (self.pinPageVC) {
- NSMutableArray *formatGroupPinList = [NSMutableArray arrayWithArray:groupPinList.reverseObjectEnumerator.allObjects];
- self.pinPageVC.groupPinList = formatGroupPinList;
- self.pinPageVC.canRemove = [self.messageController isCurrentUserRoleSuperAdminInGroup];
- if (groupPinList.count > 0) {
- [self reloadPopPinPage];
- }
- else {
- [self.pinPageVC dismissViewControllerAnimated:NO completion:nil];
- }
- }
- };
-
- self.messageController.groupRoleChanged = ^(V2TIMGroupMemberRole role) {
- @strongify(self);
- self.messageController.pinGroupMessageChanged(self.groupPinList);
- if (self.pinPageVC) {
- self.pinPageVC.canRemove = [self.messageController isCurrentUserRoleSuperAdminInGroup];
- [self.pinPageVC.tableview reloadData];
- }
- };
- }
- - (void)gotoDetailPopPinPage {
- TUIGroupPinPageViewController *vc = [[TUIGroupPinPageViewController alloc] init];
- self.pinPageVC = vc;
- NSMutableArray *formatGroupPinList = [NSMutableArray arrayWithArray:self.groupPinList.reverseObjectEnumerator.allObjects];
- vc.groupPinList = formatGroupPinList;
- vc.canRemove = [self.messageController isCurrentUserRoleSuperAdminInGroup];
- vc.view.frame = self.view.frame;
- CGFloat cellHight = (62);
- CGFloat maxOnePage = 4;
- float height = (self.groupPinList.count) * cellHight;
- height = MIN(cellHight * maxOnePage , height);
- UIView *topView = [TUIGroupChatViewController groupPinTopView];
- CGRect transRect = [topView convertRect:topView.bounds toView:[UIApplication sharedApplication].delegate.window];
- vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
- @weakify(self);
- [self presentViewController:vc animated:NO completion:^{
- vc.tableview.frame = CGRectMake(0, CGRectGetMinY(transRect), self.view.frame.size.width, 60);
- vc.customArrowView.frame = CGRectMake(0, CGRectGetMaxY(vc.tableview.frame), vc.tableview.frame.size.width, 0);
- vc.bottomShadow.frame = CGRectMake(0, CGRectGetMaxY(vc.customArrowView.frame), vc.tableview.frame.size.width, 0);
- [UIView animateWithDuration:0.3 animations:^{
- vc.tableview.frame = CGRectMake(0, CGRectGetMinY(transRect), self.view.frame.size.width, height);
- vc.customArrowView.frame = CGRectMake(0, CGRectGetMaxY(vc.tableview.frame), vc.tableview.frame.size.width, 40);
- vc.bottomShadow.frame = CGRectMake(0, CGRectGetMaxY(vc.customArrowView.frame),
- vc.tableview.frame.size.width,
- self.view.frame.size.height);
- UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:vc.customArrowView.bounds
- byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight)
- cornerRadii:CGSizeMake(10.0, 10.0)];
- CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
- maskLayer.frame = vc.customArrowView.bounds;
- maskLayer.path = maskPath.CGPath;
- vc.customArrowView.layer.mask = maskLayer;
- }];
- }];
-
- vc.onClickRemove = ^(V2TIMMessage *originMessage) {
- @strongify(self);
- [self.messageController unPinGroupMessage:originMessage];
- };
-
- vc.onClickCellView = ^(V2TIMMessage *originMessage) {
- @strongify(self);
- [self jump2GroupPinHighlightLine:originMessage];
- };
-
- }
- - (void)jump2GroupPinHighlightLine:(V2TIMMessage *)originMessage {
- TUIMessageController *msgVC = (TUIMessageController *)self.messageController;
- NSString * originMsgID = originMessage.msgID;
- [msgVC findMessages:@[originMsgID ?: @""] callback:^(BOOL success, NSString * _Nonnull desc, NSArray<V2TIMMessage *> * _Nonnull messages) {
- if (success) {
- V2TIMMessage *message = messages.firstObject;
- if (message && message.status == V2TIM_MSG_STATUS_SEND_SUCC ) {
- [msgVC locateAssignMessage:originMessage matchKeyWord:@""];
- }
- else {
- [TUITool makeToast:TIMCommonLocalizableString(TUIKitReplyMessageNotFoundOriginMessage)];
- }
- }
- }];
- }
- - (void)reloadPopPinPage {
- CGFloat cellHight = (62);
- CGFloat maxOnePage = 4;
- float height = (self.groupPinList.count) * cellHight;
- height = MIN(cellHight * maxOnePage , height);
- self.pinPageVC.tableview.frame = CGRectMake(0, self.pinPageVC.tableview.frame.origin.y, self.view.frame.size.width, height);
- self.pinPageVC.customArrowView.frame = CGRectMake(0, CGRectGetMaxY(self.pinPageVC.tableview.frame), self.pinPageVC.tableview.frame.size.width, 40);
- self.pinPageVC.bottomShadow.frame = CGRectMake(0, CGRectGetMaxY(self.pinPageVC.customArrowView.frame),
- self.pinPageVC.tableview.frame.size.width,
- self.view.frame.size.height);
- [self.pinPageVC.tableview reloadData];
- }
- - (void)getPendencyList {
- if (self.conversationData.groupID.length > 0) [self.pendencyViewModel loadData];
- }
- - (void)openPendency:(id)sender {
- TUIGroupPendencyController *vc = [[TUIGroupPendencyController alloc] init];
- @weakify(self);
- vc.cellClickBlock = ^(TUIGroupPendencyCell *_Nonnull cell) {
- if (cell.pendencyData.isRejectd || cell.pendencyData.isAccepted) {
- // After selecting, you will no longer enter the details page.
- return;
- }
- @strongify(self);
- [[V2TIMManager sharedInstance] getUsersInfo:@[ cell.pendencyData.fromUser ]
- succ:^(NSArray<V2TIMUserFullInfo *> *profiles) {
- // Show user profile VC
- NSDictionary *param = @{
- TUICore_TUIContactObjectFactory_UserProfileController_UserProfile : profiles.firstObject,
- TUICore_TUIContactObjectFactory_UserProfileController_PendencyData : cell.pendencyData,
- TUICore_TUIContactObjectFactory_UserProfileController_ActionType : @(3)
- };
- [self.navigationController pushViewController:TUICore_TUIContactObjectFactory_UserProfileController_Classic
- param:param
- forResult:nil];
- }
- fail:nil];
- };
- vc.viewModel = self.pendencyViewModel;
- [self.navigationController pushViewController:vc animated:YES];
- }
- - (void)setConversationData:(TUIChatConversationModel *)conversationData {
- [super setConversationData:conversationData];
- if (self.conversationData.groupID.length > 0) {
- _pendencyViewModel = [TUIGroupPendencyDataProvider new];
- _pendencyViewModel.groupId = conversationData.groupID;
- }
- self.atUserList = [NSMutableArray array];
- }
- #pragma mark - V2TIMGroupListener
- - (void)onReceiveJoinApplication:(NSString *)groupID member:(V2TIMGroupMemberInfo *)member opReason:(NSString *)opReason {
- [self getPendencyList];
- }
- - (void)onGroupInfoChanged:(NSString *)groupID changeInfoList:(NSArray<V2TIMGroupChangeInfo *> *)changeInfoList {
- if (![groupID isEqualToString:self.conversationData.groupID]) {
- return;
- }
- for (V2TIMGroupChangeInfo *changeInfo in changeInfoList) {
- if (changeInfo.type == V2TIM_GROUP_INFO_CHANGE_TYPE_NAME) {
- self.conversationData.title = changeInfo.value;
- return;
- }
- }
- }
- #pragma mark - TUIInputControllerDelegate
- - (void)inputController:(TUIInputController *)inputController didSendMessage:(V2TIMMessage *)msg {
- /**
- * If the text message has @ user, createTextAtMessage is required
- */
- if (msg.elemType == V2TIM_ELEM_TYPE_TEXT) {
- NSMutableArray *atUserList = [NSMutableArray array];
- for (TUIUserModel *model in self.atUserList) {
- if (model.userId) {
- [atUserList addObject:model.userId];
- }
- }
- if (atUserList.count > 0) {
- NSData *cloudCustomData = msg.cloudCustomData;
- msg = [[V2TIMManager sharedInstance] createTextAtMessage:msg.textElem.text atUserList:atUserList];
- msg.cloudCustomData = cloudCustomData;
- }
- /**
- * After the message is sent, the atUserList need to be reset
- */
- [self.atUserList removeAllObjects];
- }
- [super inputController:inputController didSendMessage:msg];
- }
- - (void)inputControllerDidInputAt:(TUIInputController *)inputController {
- [super inputControllerDidInputAt:inputController];
- /**
- * Input of @ character detected
- */
- if (self.conversationData.groupID.length > 0) {
- if ([self.navigationController.topViewController isKindOfClass:NSClassFromString(@"TUISelectGroupMemberViewController")]) {
- return;
- }
- //When pushing a new VC, the keyboard needs to be hidden.
- [self.inputController reset];
- __weak typeof(self) weakSelf = self;
- NSMutableDictionary *param = [NSMutableDictionary dictionary];
- param[TUICore_TUIContactObjectFactory_SelectGroupMemberVC_GroupID] = self.conversationData.groupID;
- param[TUICore_TUIContactObjectFactory_SelectGroupMemberVC_Name] = TIMCommonLocalizableString(TUIKitAtSelectMemberTitle);
- param[TUICore_TUIContactObjectFactory_SelectGroupMemberVC_OptionalStyle] = @(1);
- [self.navigationController
- pushViewController:TUICore_TUIContactObjectFactory_SelectGroupMemberVC_Classic
- param:param
- forResult:^(NSDictionary *_Nonnull param) {
- NSArray<TUIUserModel *> *modelList = [param tui_objectForKey:TUICore_TUIContactObjectFactory_SelectGroupMemberVC_ResultUserList
- asClass:NSArray.class];
- NSMutableString *atText = [[NSMutableString alloc] init];
- for (int i = 0; i < modelList.count; i++) {
- TUIUserModel *model = modelList[i];
- if (![model isKindOfClass:TUIUserModel.class]) {
- NSAssert(NO, @"Error data-type in modelList");
- continue;
- }
- [weakSelf.atUserList addObject:model];
- [atText appendString:[NSString stringWithFormat:@"@%@ ", model.name]];
- }
- NSAttributedString *spaceString = [[NSAttributedString alloc]
- initWithString:atText
- attributes:@{NSFontAttributeName : kTUIInputNoramlFont, NSForegroundColorAttributeName : kTUIInputNormalTextColor}];
- [weakSelf.inputController.inputBar addWordsToInputBar:spaceString ];
- }];
- }
- }
- - (void)inputController:(TUIInputController *)inputController didDeleteAt:(NSString *)atText {
- [super inputController:inputController didDeleteAt:atText];
- for (TUIUserModel *user in self.atUserList) {
- if ([atText rangeOfString:user.name].location != NSNotFound) {
- [self.atUserList removeObject:user];
- break;
- }
- }
- }
- - (void)inputController:(TUIInputController *)inputController didSelectMoreCell:(TUIInputMoreCell *)cell {
- [super inputController:inputController didSelectMoreCell:cell];
- }
- #pragma mark - TUIBaseMessageControllerDelegate
- - (void)messageController:(TUIBaseMessageController *)controller onLongSelectMessageAvatar:(TUIMessageCell *)cell {
- if (!cell || !cell.messageData || !cell.messageData.identifier) {
- return;
- }
- if ([cell.messageData.identifier isEqualToString:[TUILogin getUserID]]) {
- return;
- }
- BOOL atUserExist = NO;
- for (TUIUserModel *model in self.atUserList) {
- if ([model.userId isEqualToString:cell.messageData.identifier]) {
- atUserExist = YES;
- break;
- }
- }
- if (!atUserExist) {
- TUIUserModel *user = [[TUIUserModel alloc] init];
- user.userId = cell.messageData.identifier;
- user.name = cell.messageData.senderName;
- [self.atUserList addObject:user];
- NSString *nameString = [NSString stringWithFormat:@"@%@ ", user.name];
- UIFont *textFont = kTUIInputNoramlFont;
- NSAttributedString *spaceString = [[NSAttributedString alloc] initWithString:nameString attributes:@{NSFontAttributeName : textFont}];
- [self.inputController.inputBar addWordsToInputBar:spaceString ];
- }
- }
- #pragma mark - Override Methods
- - (NSString *)forwardTitleWithMyName:(NSString *)nameStr {
- return TIMCommonLocalizableString(TUIKitRelayGroupChatHistory);
- }
- @end
|