|  | @@ -6,16 +6,545 @@
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #import "KSTXGroupChatViewController.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 "KSMuteTipsView.h"
 | 
	
		
			
				|  |  | +#import "CustomNavViewController.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -@interface KSTXGroupChatViewController ()
 | 
	
		
			
				|  |  | +@interface KSTXGroupChatViewController ()<V2TIMGroupListener>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@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) UIView *muteView;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@property (nonatomic, strong) dispatch_group_t requestGroup;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@property (nonatomic, assign) BOOL isGroupMute; // 是否群禁言
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@property (nonatomic, assign) BOOL isUserMute;  // 是否个人禁言
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@property (nonatomic, assign) BOOL isGroupManager; // 是否管理员
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@property (nonatomic, assign) BOOL isMute;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  @end
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  @implementation KSTXGroupChatViewController
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +- (void)setIsMute:(BOOL)isMute {
 | 
	
		
			
				|  |  | +    _isMute = isMute;
 | 
	
		
			
				|  |  | +    UIView *viewContainer = self.inputController.inputBar;
 | 
	
		
			
				|  |  | +    if (isMute) {
 | 
	
		
			
				|  |  | +        if ([viewContainer.subviews containsObject:self.muteView]) {
 | 
	
		
			
				|  |  | +            [viewContainer bringSubviewToFront:self.muteView];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else {
 | 
	
		
			
				|  |  | +            [viewContainer addSubview:self.muteView];
 | 
	
		
			
				|  |  | +            [self.muteView mas_makeConstraints:^(MASConstraintMaker *make) {
 | 
	
		
			
				|  |  | +                make.left.right.top.bottom.mas_equalTo(viewContainer);
 | 
	
		
			
				|  |  | +            }];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        @weakObj(self);
 | 
	
		
			
				|  |  | +        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 | 
	
		
			
				|  |  | +            @strongObj(self);
 | 
	
		
			
				|  |  | +            [self resetStatus];
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +        if ([viewContainer.subviews containsObject:self.muteView]) {
 | 
	
		
			
				|  |  | +            [self.muteView removeFromSuperview];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)resetStatus {
 | 
	
		
			
				|  |  | +    UIViewController *ctrl = [self theTopviewControler];
 | 
	
		
			
				|  |  | +    if ([ctrl isKindOfClass:NSClassFromString(@"KSGroupConversationController")] || [ctrl isKindOfClass:NSClassFromString(@"UIDocumentPickerViewController")]) {
 | 
	
		
			
				|  |  | +        // 重置键盘状态
 | 
	
		
			
				|  |  | +        [self.inputController reset];
 | 
	
		
			
				|  |  | +        [self.inputController exitReplyAndReference:nil];
 | 
	
		
			
				|  |  | +        [self.inputController.inputBar clearInput];
 | 
	
		
			
				|  |  | +        [self.inputController.inputBar.inputTextView resignFirstResponder];
 | 
	
		
			
				|  |  | +        [self removePopMemuView];
 | 
	
		
			
				|  |  | +        [self.messageController enableMultiSelectedMode:NO]; // 关闭选择
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (UIViewController *)theTopviewControler {
 | 
	
		
			
				|  |  | +    UIViewController *rootVC = [[UIApplication sharedApplication].delegate window].rootViewController;
 | 
	
		
			
				|  |  | +    UIViewController *parent = rootVC;
 | 
	
		
			
				|  |  | +    while ((parent = rootVC.presentedViewController) != nil) {
 | 
	
		
			
				|  |  | +        rootVC = parent;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    while ([rootVC isKindOfClass:[UINavigationController class]]) {
 | 
	
		
			
				|  |  | +        rootVC = [(UINavigationController *)rootVC topViewController];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    while ([rootVC isKindOfClass:[UITabBarController class]]) {
 | 
	
		
			
				|  |  | +        UITabBarController *tab = (UITabBarController *)rootVC;
 | 
	
		
			
				|  |  | +        CustomNavViewController *ctrl = (CustomNavViewController *)tab.selectedViewController;
 | 
	
		
			
				|  |  | +        if (ctrl.presentedViewController) {
 | 
	
		
			
				|  |  | +            rootVC = ctrl.presentedViewController;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else {
 | 
	
		
			
				|  |  | +            rootVC = [ctrl topViewController];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return rootVC;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +- (void)removePopMemuView {
 | 
	
		
			
				|  |  | +    for (UIView *view in self.messageController.tableView.subviews) {
 | 
	
		
			
				|  |  | +        if ([view isKindOfClass:NSClassFromString(@"TUIChatPopMenu")]) {
 | 
	
		
			
				|  |  | +            [view removeFromSuperview];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (dispatch_group_t)requestGroup {
 | 
	
		
			
				|  |  | +    if (!_requestGroup) {
 | 
	
		
			
				|  |  | +        _requestGroup = dispatch_group_create();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return _requestGroup;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (UIView *)muteView {
 | 
	
		
			
				|  |  | +    if (!_muteView) {
 | 
	
		
			
				|  |  | +        _muteView = [[UIView alloc] initWithFrame:CGRectZero];
 | 
	
		
			
				|  |  | +        _muteView.backgroundColor = HexRGB(0xEBF0F6);
 | 
	
		
			
				|  |  | +        KSMuteTipsView *tipsView = [KSMuteTipsView shareInstance];
 | 
	
		
			
				|  |  | +        [_muteView addSubview:tipsView];
 | 
	
		
			
				|  |  | +        [tipsView mas_makeConstraints:^(MASConstraintMaker *make) {
 | 
	
		
			
				|  |  | +            make.top.mas_equalTo(_muteView.mas_top).offset(10);
 | 
	
		
			
				|  |  | +            make.left.mas_equalTo(_muteView.mas_left).offset(12);
 | 
	
		
			
				|  |  | +            make.right.mas_equalTo(_muteView.mas_right).offset(-12);
 | 
	
		
			
				|  |  | +            make.height.mas_equalTo(36);
 | 
	
		
			
				|  |  | +        }];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return _muteView;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  - (void)viewDidLoad {
 | 
	
		
			
				|  |  |      [super viewDidLoad];
 | 
	
		
			
				|  |  |      // Do any additional setup after loading the view.
 | 
	
		
			
				|  |  | +    [self setupTipsView];
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    [[V2TIMManager sharedInstance] addGroupListener:self];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)viewWillAppear:(BOOL)animated {
 | 
	
		
			
				|  |  | +    [super viewWillAppear:animated];
 | 
	
		
			
				|  |  | +    [self getGroupAndMemberInfo];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)getGroupAndMemberInfo {
 | 
	
		
			
				|  |  | +    [self getGroupInfo];
 | 
	
		
			
				|  |  | +    [self getMineInfo];
 | 
	
		
			
				|  |  | +    dispatch_group_notify(self.requestGroup, dispatch_get_main_queue(), ^{
 | 
	
		
			
				|  |  | +        [self modifyMuteViewDisplay];
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)getMineInfo {
 | 
	
		
			
				|  |  | +    dispatch_group_enter(self.requestGroup);
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    [[V2TIMManager sharedInstance] getGroupMembersInfo:self.conversationData.groupID memberList:@[UserDefault(IM_USERID)] succ:^(NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
 | 
	
		
			
				|  |  | +        for (V2TIMGroupMemberFullInfo *memberInfo in memberList) {
 | 
	
		
			
				|  |  | +            uint64_t currentTime = [self getCurrentTime];
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            if (memberInfo.muteUntil > currentTime) { // 存在禁言时间
 | 
	
		
			
				|  |  | +                self.isUserMute = YES;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else {
 | 
	
		
			
				|  |  | +                self.isUserMute = NO;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        dispatch_group_leave(self.requestGroup);
 | 
	
		
			
				|  |  | +    } fail:^(int code, NSString *desc) {
 | 
	
		
			
				|  |  | +        dispatch_group_leave(self.requestGroup);
 | 
	
		
			
				|  |  | +    }];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (uint64_t)getCurrentTime {
 | 
	
		
			
				|  |  | +    return [[V2TIMManager sharedInstance] getServerTime];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)getGroupInfo {
 | 
	
		
			
				|  |  | +    dispatch_group_enter(self.requestGroup);
 | 
	
		
			
				|  |  | +    [[V2TIMManager sharedInstance] getGroupsInfo:@[self.conversationData.groupID] succ:^(NSArray<V2TIMGroupInfoResult *> *groupResultList) {
 | 
	
		
			
				|  |  | +        for (V2TIMGroupInfoResult *result in groupResultList) {
 | 
	
		
			
				|  |  | +            V2TIMGroupInfo *groupInfo = result.info;
 | 
	
		
			
				|  |  | +            if (groupInfo.role == 300 || groupInfo.role == 400) {
 | 
	
		
			
				|  |  | +                self.isGroupManager = YES;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else {
 | 
	
		
			
				|  |  | +                self.isGroupManager = NO;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            if (groupInfo.allMuted) { // 全员禁言
 | 
	
		
			
				|  |  | +                self.isGroupMute = YES;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else {
 | 
	
		
			
				|  |  | +                self.isGroupMute = NO;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        dispatch_group_leave(self.requestGroup);
 | 
	
		
			
				|  |  | +    } fail:^(int code, NSString *desc) {
 | 
	
		
			
				|  |  | +        dispatch_group_leave(self.requestGroup);
 | 
	
		
			
				|  |  | +    }];
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)modifyMuteViewDisplay {
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    if ((self.isGroupMute && self.isGroupManager == NO) || self.isUserMute) {
 | 
	
		
			
				|  |  | +        self.isMute = YES;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +        self.isMute = NO;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (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;
 | 
	
		
			
				|  |  | +            UIView *topView = [TUIGroupChatViewController customTopView];
 | 
	
		
			
				|  |  | +            self.tipsView.mm_top(topView ? topView.mm_h : 0);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            self.tipsView.alpha = 0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }];
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    [self getPendencyList];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (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) {
 | 
	
		
			
				|  |  | +            // 选择后不再进详情页了
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        @strongify(self);
 | 
	
		
			
				|  |  | +        [[V2TIMManager sharedInstance] getUsersInfo:@[ cell.pendencyData.fromUser ]
 | 
	
		
			
				|  |  | +                                               succ:^(NSArray<V2TIMUserFullInfo *> *profiles) {
 | 
	
		
			
				|  |  | +            // 显示用户资料 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;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else if (changeInfo.type == V2TIM_GROUP_INFO_CHANGE_TYPE_SHUT_UP_ALL) { // 群禁言
 | 
	
		
			
				|  |  | +            // 提示
 | 
	
		
			
				|  |  | +            BOOL mute = changeInfo.boolValue;
 | 
	
		
			
				|  |  | +            if (mute) {
 | 
	
		
			
				|  |  | +                self.isGroupMute = YES;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else {
 | 
	
		
			
				|  |  | +                self.isGroupMute = NO;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            // 刷新状态
 | 
	
		
			
				|  |  | +            [self modifyMuteViewDisplay];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else if (changeInfo.type == V2TIM_GROUP_INFO_CHANGE_TYPE_OWNER)  { // 群主变更
 | 
	
		
			
				|  |  | +            NSString *userID = changeInfo.value;
 | 
	
		
			
				|  |  | +            if ([userID isEqualToString:UserDefault(IM_USERID)]) {
 | 
	
		
			
				|  |  | +                self.isGroupManager = YES;
 | 
	
		
			
				|  |  | +                // 刷新状态
 | 
	
		
			
				|  |  | +                [self modifyMuteViewDisplay];
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +//searchGroupMembers
 | 
	
		
			
				|  |  | +- (void)onMemberInfoChanged:(NSString *)groupID changeInfoList:(NSArray<V2TIMGroupMemberChangeInfo *> *)changeInfoList {
 | 
	
		
			
				|  |  | +    for (V2TIMGroupMemberChangeInfo *memberChangeInfo in changeInfoList) {
 | 
	
		
			
				|  |  | +        if ([memberChangeInfo.userID isEqualToString:UserDefault(IM_USERID)]) {
 | 
	
		
			
				|  |  | +            if (memberChangeInfo.muteTime > 0) {
 | 
	
		
			
				|  |  | +                self.isUserMute = YES;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else {
 | 
	
		
			
				|  |  | +                self.isUserMute = NO;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // 刷新状态
 | 
	
		
			
				|  |  | +    [self modifyMuteViewDisplay];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// 指定管理员身份
 | 
	
		
			
				|  |  | +- (void)onGrantAdministrator:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray <V2TIMGroupMemberInfo *> *)memberList {
 | 
	
		
			
				|  |  | +    for (V2TIMGroupMemberInfo *memberInfo in memberList) {
 | 
	
		
			
				|  |  | +        if ([memberInfo.userID isEqualToString:UserDefault(IM_USERID)]) {
 | 
	
		
			
				|  |  | +            self.isGroupManager = YES;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // 刷新状态
 | 
	
		
			
				|  |  | +    [self modifyMuteViewDisplay];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// 取消管理员身份
 | 
	
		
			
				|  |  | +- (void)onRevokeAdministrator:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray <V2TIMGroupMemberInfo *> *)memberList {
 | 
	
		
			
				|  |  | +    for (V2TIMGroupMemberInfo *memberInfo in memberList) {
 | 
	
		
			
				|  |  | +        if ([memberInfo.userID isEqualToString:UserDefault(IM_USERID)]) {
 | 
	
		
			
				|  |  | +            self.isGroupManager = NO;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // 刷新状态
 | 
	
		
			
				|  |  | +    [self modifyMuteViewDisplay];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#pragma mark - TUIInputControllerDelegate
 | 
	
		
			
				|  |  | +- (void)inputController:(TUIInputController *)inputController didSendMessage:(V2TIMMessage *)msg {
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * 文本消息如果有 @ 用户,需要 createTextAtMessage
 | 
	
		
			
				|  |  | +     * 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;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        /**
 | 
	
		
			
				|  |  | +         * 消息发送完后 atUserList 要重置
 | 
	
		
			
				|  |  | +         * 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;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        __weak typeof(self) weakSelf = self;
 | 
	
		
			
				|  |  | +        NSMutableDictionary *param = [NSMutableDictionary dictionary];
 | 
	
		
			
				|  |  | +        param[TUICore_TUIGroupObjectFactory_SelectGroupMemberVC_GroupID] = self.conversationData.groupID;
 | 
	
		
			
				|  |  | +        param[TUICore_TUIGroupObjectFactory_SelectGroupMemberVC_Name] = TIMCommonLocalizableString(TUIKitAtSelectMemberTitle);
 | 
	
		
			
				|  |  | +        param[TUICore_TUIGroupObjectFactory_SelectGroupMemberVC_OptionalStyle] = @(1);
 | 
	
		
			
				|  |  | +        [self.navigationController
 | 
	
		
			
				|  |  | +         pushViewController:TUICore_TUIGroupObjectFactory_SelectGroupMemberVC_Classic
 | 
	
		
			
				|  |  | +         param:param
 | 
	
		
			
				|  |  | +         forResult:^(NSDictionary *_Nonnull param) {
 | 
	
		
			
				|  |  | +            NSArray<TUIUserModel *> *modelList = [param tui_objectForKey:TUICore_TUIGroupObjectFactory_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];
 | 
	
		
			
				|  |  | +                if (i == 0) {
 | 
	
		
			
				|  |  | +                    [atText appendString:[NSString stringWithFormat:@"%@ ", model.name]];
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    [atText appendString:[NSString stringWithFormat:@"@%@ ", model.name]];
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            NSAttributedString *spaceString = [[NSAttributedString alloc]
 | 
	
		
			
				|  |  | +                                               initWithString:atText
 | 
	
		
			
				|  |  | +                                               attributes:@{NSFontAttributeName : kTUIInputNoramlFont, NSForegroundColorAttributeName : kTUIInputNormalTextColor}];
 | 
	
		
			
				|  |  | +            NSRange range = weakSelf.inputController.inputBar.inputTextView.selectedRange;
 | 
	
		
			
				|  |  | +            [weakSelf.inputController.inputBar.inputTextView.textStorage insertAttributedString:spaceString atIndex:range.location + range.length];
 | 
	
		
			
				|  |  | +            [weakSelf.inputController.inputBar updateTextViewFrame];
 | 
	
		
			
				|  |  | +        }];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (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 (self.isMute) {
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    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.name;
 | 
	
		
			
				|  |  | +        [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.inputTextView.textStorage insertAttributedString:spaceString
 | 
	
		
			
				|  |  | +                                                                                atIndex:self.inputController.inputBar.inputTextView.textStorage.length];
 | 
	
		
			
				|  |  | +        [self.inputController.inputBar.inputTextView becomeFirstResponder];
 | 
	
		
			
				|  |  | +        self.inputController.inputBar.inputTextView.selectedRange =
 | 
	
		
			
				|  |  | +        NSMakeRange(spaceString.length + self.inputController.inputBar.inputTextView.textStorage.length, 0);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)messageController:(TUIBaseMessageController *)controller onSelectMessageMenu:(NSInteger)menuType withData:(TUIMessageCellData *)data {
 | 
	
		
			
				|  |  | +    if (self.isMute) {
 | 
	
		
			
				|  |  | +        [self.messageController enableMultiSelectedMode:NO]; // 关闭选择
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    [self onSelectMessageMenu:menuType withData:data];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)messageController:(TUIBaseMessageController *)controller onRelyMessage:(TUIMessageCellData *)data {
 | 
	
		
			
				|  |  | +    if (self.isMute) {
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    [super messageController:controller onRelyMessage:data];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)messageController:(TUIBaseMessageController *)controller onReferenceMessage:(TUIMessageCellData *)data {
 | 
	
		
			
				|  |  | +    if (self.isMute) {
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    [super messageController:controller onReferenceMessage:data];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)messageController:(TUIBaseMessageController *)controller modifyMessage:(nonnull TUIMessageCellData *)cellData reactEmoji:(NSString *)emojiName {
 | 
	
		
			
				|  |  | +    if (self.isMute) {
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    [super messageController:controller modifyMessage:cellData reactEmoji:emojiName];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- (void)messageController:(TUIBaseMessageController *)controller onReEditMessage:(TUIMessageCellData *)data {
 | 
	
		
			
				|  |  | +    if (self.isMute) {
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    [super messageController:controller onReEditMessage:data];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#pragma mark - Override Methods
 | 
	
		
			
				|  |  | +- (NSString *)forwardTitleWithMyName:(NSString *)nameStr {
 | 
	
		
			
				|  |  | +    return TIMCommonLocalizableString(TUIKitRelayGroupChatHistory);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 |