Browse Source

禁言显示

Steven 10 months ago
parent
commit
3c8847bb50

+ 10 - 0
KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj

@@ -304,6 +304,8 @@
 		BC12639A28FF8E1700509E90 /* HomeNewMusicView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC12639928FF8E1700509E90 /* HomeNewMusicView.xib */; };
 		BC12639D28FF8E6D00509E90 /* HomeRecommendMusicView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC12639C28FF8E6D00509E90 /* HomeRecommendMusicView.m */; };
 		BC12639F28FF8E7400509E90 /* HomeRecommendMusicView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC12639E28FF8E7400509E90 /* HomeRecommendMusicView.xib */; };
+		BC1D02422C0490AB001F6A94 /* KSMuteTipsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC1D023F2C0490AB001F6A94 /* KSMuteTipsView.xib */; };
+		BC1D02432C0490AB001F6A94 /* KSMuteTipsView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1D02402C0490AB001F6A94 /* KSMuteTipsView.m */; };
 		BC27A06E280FF56C00F91E27 /* AccompanyEvaluateCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC27A06A280FF56B00F91E27 /* AccompanyEvaluateCell.xib */; };
 		BC27A06F280FF56C00F91E27 /* AccompanyStudentEvaCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC27A06B280FF56C00F91E27 /* AccompanyStudentEvaCell.m */; };
 		BC27A070280FF56C00F91E27 /* AccompanyStudentEvaCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC27A06C280FF56C00F91E27 /* AccompanyStudentEvaCell.xib */; };
@@ -1532,6 +1534,9 @@
 		BC12639B28FF8E6D00509E90 /* HomeRecommendMusicView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeRecommendMusicView.h; sourceTree = "<group>"; };
 		BC12639C28FF8E6D00509E90 /* HomeRecommendMusicView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeRecommendMusicView.m; sourceTree = "<group>"; };
 		BC12639E28FF8E7400509E90 /* HomeRecommendMusicView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeRecommendMusicView.xib; sourceTree = "<group>"; };
+		BC1D023F2C0490AB001F6A94 /* KSMuteTipsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = KSMuteTipsView.xib; sourceTree = "<group>"; };
+		BC1D02402C0490AB001F6A94 /* KSMuteTipsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSMuteTipsView.m; sourceTree = "<group>"; };
+		BC1D02412C0490AB001F6A94 /* KSMuteTipsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSMuteTipsView.h; sourceTree = "<group>"; };
 		BC255E822B29425F00A1FC27 /* SwiftImportHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftImportHeader.h; sourceTree = "<group>"; };
 		BC255E832B29425F00A1FC27 /* WebViewBaseConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewBaseConfig.h; sourceTree = "<group>"; };
 		BC27A068280FF56B00F91E27 /* AccompanyEvaluateCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccompanyEvaluateCell.h; sourceTree = "<group>"; };
@@ -4708,6 +4713,9 @@
 				BC43CAC62A88C9570011EB5D /* KSTXC2CChatViewController.m */,
 				BC43CAC82A88C9570011EB5D /* KSTXGroupChatViewController.h */,
 				BC43CAC52A88C9570011EB5D /* KSTXGroupChatViewController.m */,
+				BC1D02412C0490AB001F6A94 /* KSMuteTipsView.h */,
+				BC1D02402C0490AB001F6A94 /* KSMuteTipsView.m */,
+				BC1D023F2C0490AB001F6A94 /* KSMuteTipsView.xib */,
 			);
 			path = TXCustom;
 			sourceTree = "<group>";
@@ -6468,6 +6476,7 @@
 				BCC0F66F2A8CD8F500C4EFA4 /* TXClassRoomAlertView.xib in Resources */,
 				BC89AC102AB0843000B077AF /* TenantNewMusicView.xib in Resources */,
 				BC71D26A288804CD0010F14B /* img_19.png in Resources */,
+				BC1D02422C0490AB001F6A94 /* KSMuteTipsView.xib in Resources */,
 				BCC0F6032A8CD86C00C4EFA4 /* TX3ASettingView.xib in Resources */,
 				275FA1AD27E734C600CFEA2E /* KSImageAlert.xib in Resources */,
 				BC71D251288804CD0010F14B /* img_17.png in Resources */,
@@ -7048,6 +7057,7 @@
 				BC119234280ED97C00A716F7 /* CourseForLiveCell.m in Sources */,
 				BC106C382A9338A7000759A9 /* LiveRoomConfirmAlert.m in Sources */,
 				BCFE53E72812765600AD6786 /* HomeHotAlbumCell.m in Sources */,
+				BC1D02432C0490AB001F6A94 /* KSMuteTipsView.m in Sources */,
 				BC89AC092AB0840E00B077AF /* TenantRecommendMusicView.m in Sources */,
 				BC8A459B283DC33400094BBB /* CloudSongMessageModel.m in Sources */,
 				BC8A45B7283DC33500094BBB /* NoWiredTipsAlert.m in Sources */,

+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Conversation/mute_tips.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "mute_tips@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "mute_tips@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Conversation/mute_tips.imageset/mute_tips@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Conversation/mute_tips.imageset/mute_tips@3x.png


+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/TXCustom/KSMuteTipsView.h

@@ -0,0 +1,18 @@
+//
+//  KSMuteTipsView.h
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2024/5/21.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSMuteTipsView : UIView
+
++ (instancetype)shareInstance;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 24 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/TXCustom/KSMuteTipsView.m

@@ -0,0 +1,24 @@
+//
+//  KSMuteTipsView.m
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2024/5/21.
+//
+
+#import "KSMuteTipsView.h"
+
+@implementation KSMuteTipsView
+
++ (instancetype)shareInstance {
+    KSMuteTipsView *view = [[[NSBundle mainBundle] loadNibNamed:@"KSMuteTipsView" owner:nil options:nil] firstObject];
+    return view;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 53 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/TXCustom/KSMuteTipsView.xib

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="45"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="mute_tips" translatesAutoresizingMaskIntoConstraints="NO" id="pe5-GS-WtP">
+                    <rect key="frame" x="160" y="12.666666666666664" width="22" height="20"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="20" id="OAX-rX-PYH"/>
+                        <constraint firstAttribute="width" constant="22" id="sYH-E8-dkX"/>
+                    </constraints>
+                </imageView>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="禁言中" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sfe-Tx-y9r">
+                    <rect key="frame" x="187" y="13.666666666666664" width="46" height="18"/>
+                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
+                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="sfe-Tx-y9r" firstAttribute="leading" secondItem="pe5-GS-WtP" secondAttribute="trailing" constant="5" id="7vO-yp-H0i"/>
+                <constraint firstItem="sfe-Tx-y9r" firstAttribute="centerY" secondItem="pe5-GS-WtP" secondAttribute="centerY" id="90M-2j-OtE"/>
+                <constraint firstItem="sfe-Tx-y9r" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="DDP-QK-6ob"/>
+                <constraint firstItem="sfe-Tx-y9r" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" constant="13.5" id="I8M-DX-7gI"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <userDefinedRuntimeAttributes>
+                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                    <real key="value" value="6"/>
+                </userDefinedRuntimeAttribute>
+            </userDefinedRuntimeAttributes>
+            <point key="canvasLocation" x="35.877862595419849" y="-124.29577464788733"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="mute_tips" width="22" height="20"/>
+    </resources>
+</document>

+ 530 - 1
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/TXCustom/KSTXGroupChatViewController.m

@@ -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);
 }