// // TUISelectGroupMemberViewController.m // TXIMSDK_TUIKit_iOS // // Created by xiangzhang on 2020/7/6. // Copyright © 2023 Tencent. All rights reserved. // #import "TUISelectGroupMemberViewController_Minimalist.h" #import #import #import #import #import "ReactiveObjC/ReactiveObjC.h" #import "TUIMemberPanelCell.h" #import "TUISelectGroupMemberCell.h" #define kUserBorder 44.0 #define kUserSpacing 2 #define kUserPanelLeftSpacing 15 @interface TUISelectGroupMemberViewController_Minimalist () @property(nonatomic, strong) UIButton *cancelBtn; @property(nonatomic, strong) UIButton *doneBtn; @property(nonatomic, strong) UICollectionView *userPanel; @property(nonatomic, strong) UITableView *selectTable; @property(nonatomic, strong) UIActivityIndicatorView *indicatorView; @property(nonatomic, strong) NSMutableArray *selectedUsers; @property(nonatomic, assign) CGFloat topStartPosition; @property(nonatomic, assign) CGFloat userPanelWidth; @property(nonatomic, assign) CGFloat userPanelHeight; @property(nonatomic, assign) CGFloat realSpacing; @property(nonatomic, assign) NSInteger userPanelColumnCount; @property(nonatomic, assign) NSInteger userPanelRowCount; @property(nonatomic, strong) NSMutableArray *memberList; @property(nonatomic, assign) NSInteger pageIndex; @property(nonatomic, assign) BOOL isNoData; @end @implementation TUISelectGroupMemberViewController_Minimalist { UICollectionView *_userPanel; UITableView *_selectTable; UIButton *_cancelBtn; UIButton *_doneBtn; } - (void)viewDidLoad { [super viewDidLoad]; UILabel *titleLabel = [[UILabel alloc] init]; titleLabel.text = self.name ?: TIMCommonLocalizableString(Make_a_call); titleLabel.font = [UIFont boldSystemFontOfSize:17.0]; titleLabel.textColor = TIMCommonDynamicColor(@"nav_title_text_color", @"#000000"); [titleLabel sizeToFit]; self.navigationItem.titleView = titleLabel; self.view.backgroundColor = TIMCommonDynamicColor(@"controller_bg_color", @"#F2F3F5"); UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:self.cancelBtn]; self.navigationItem.leftBarButtonItem = item; UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithCustomView:self.doneBtn]; self.navigationItem.rightBarButtonItem = item2; CGFloat topPadding = 44.f; if (@available(iOS 11.0, *)) { UIWindow *window = [UIApplication sharedApplication].keyWindow; topPadding = window.safeAreaInsets.top; } topPadding = MAX(26, topPadding); CGFloat navBarHeight = self.navigationController.navigationBar.bounds.size.height; self.topStartPosition = topPadding + (navBarHeight > 0 ? navBarHeight : 44); CGRect rect = self.view.bounds; self.memberList = [NSMutableArray array]; self.selectedUsers = [NSMutableArray array]; self.indicatorView.frame = CGRectMake(0, 0, self.view.bounds.size.width, TMessageController_Header_Height); self.selectTable.tableFooterView = self.indicatorView; [self getMembers]; } #pragma mark UI - (UIButton *)cancelBtn { if (!_cancelBtn.superview) { _cancelBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)]; [_cancelBtn setTitle:TIMCommonLocalizableString(Cancel) forState:UIControlStateNormal]; [_cancelBtn setTitleColor:TIMCommonDynamicColor(@"nav_title_text_color", @"#000000") forState:UIControlStateNormal]; [_cancelBtn addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; } return _cancelBtn; } - (UIButton *)doneBtn { if (!_doneBtn.superview) { _doneBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)]; [_doneBtn setTitle:TIMCommonLocalizableString(Done) forState:UIControlStateNormal]; [_doneBtn setAlpha:0.5]; [_doneBtn setTitleColor:TIMCommonDynamicColor(@"nav_title_text_color", @"#000000") forState:UIControlStateNormal]; [_doneBtn addTarget:self action:@selector(onNext) forControlEvents:UIControlEventTouchUpInside]; } return _doneBtn; } - (UICollectionView *)userPanel { if (!_userPanel.superview) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; layout.scrollDirection = UICollectionViewScrollDirectionVertical; _userPanel = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; _userPanel.backgroundColor = [UIColor clearColor]; [_userPanel registerClass:[TUIMemberPanelCell class] forCellWithReuseIdentifier:@"TUIMemberPanelCell"]; if (@available(iOS 10.0, *)) { _userPanel.prefetchingEnabled = YES; } else { // Fallback on earlier versions } _userPanel.showsVerticalScrollIndicator = NO; _userPanel.showsHorizontalScrollIndicator = NO; _userPanel.contentMode = UIViewContentModeScaleAspectFit; _userPanel.scrollEnabled = NO; _userPanel.delegate = self; _userPanel.dataSource = self; [self.view addSubview:_userPanel]; } return _userPanel; } - (UITableView *)selectTable { if (!_selectTable.superview) { _selectTable = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; _selectTable.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero]; [_selectTable registerClass:[TUISelectGroupMemberCell class] forCellReuseIdentifier:@"TUISelectGroupMemberCell"]; if (@available(iOS 15.0, *)) { _selectTable.sectionHeaderTopPadding = 0; } _selectTable.delegate = self; _selectTable.dataSource = self; [self.view addSubview:_selectTable]; _selectTable.mm_width(self.view.mm_w).mm_top(self.topStartPosition + 10).mm_flexToBottom(0); } return _selectTable; } - (UIActivityIndicatorView *)indicatorView { if (_indicatorView == nil) { _indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; _indicatorView.hidesWhenStopped = YES; } return _indicatorView; } - (void)updateUserPanel { self.userPanel.mm_height(self.userPanelHeight).mm_left(kUserPanelLeftSpacing).mm_flexToRight(0).mm_top(self.topStartPosition); self.selectTable.mm_width(self.view.mm_w).mm_top(self.userPanel.mm_maxY).mm_flexToBottom(0); @weakify(self); [self.userPanel performBatchUpdates:^{ @strongify(self); [self.userPanel reloadSections:[NSIndexSet indexSetWithIndex:0]]; } completion:nil]; [self.selectTable reloadData]; self.doneBtn.alpha = (self.selectedUsers.count == 0 ? 0.5 : 1); } #pragma mark action - (void)onNext { if (self.selectedUsers.count == 0) { return; } NSMutableArray *users = [NSMutableArray array]; for (TUIUserModel *model in self.selectedUsers) { [users addObject:[model copy]]; } if (self.selectedFinished) { [self cancel]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.selectedFinished(users); }); } if (self.optionalStyle == TUISelectMemberOptionalStyleTransferOwner) { [self cancel]; return; } [self cancel]; NSDictionary *result = @{TUICore_TUIGroupObjectFactory_SelectGroupMemberVC_ResultUserList : users}; if (self.navigateValueCallback) { self.navigateValueCallback(result); } } - (void)cancel { if (self.isModal) { [self dismissViewControllerAnimated:YES completion:nil]; } else { [self.navigationController popViewControllerAnimated:YES]; } } - (BOOL)isModal { NSArray *viewControllers = self.navigationController.viewControllers; if (viewControllers.count > 1 && [viewControllers.lastObject isEqual:self]) { return NO; } return YES; } #pragma mark UITableViewDelegate - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.memberList.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"TUISelectGroupMemberCell"; TUISelectGroupMemberCell *cell = (TUISelectGroupMemberCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (!cell) { cell = [[TUISelectGroupMemberCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; } if (indexPath.row < self.memberList.count) { TUIUserModel *model = self.memberList[indexPath.row]; BOOL isSelect = [self isUserSelected:model]; [cell fillWithData:model isSelect:isSelect]; } return cell; } - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section { UITableViewHeaderFooterView *footer = (UITableViewHeaderFooterView *)view; footer.textLabel.textColor = [UIColor d_systemGrayColor]; footer.textLabel.font = [UIFont systemFontOfSize:14]; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { return TIMCommonLocalizableString(TUIKitGroupProfileMember); } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { return 44; } - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return YES; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { BOOL isSelected = NO; TUIUserModel *userSelected = [[TUIUserModel alloc] init]; if (indexPath.row < self.memberList.count) { TUIUserModel *user = self.memberList[indexPath.row]; isSelected = [self isUserSelected:user]; userSelected = [user copy]; } if (userSelected.userId.length == 0) { return; } if ([userSelected.userId isEqualToString:kImSDK_MesssageAtALL]) { [self.selectedUsers removeAllObjects]; [self.selectedUsers addObject:userSelected]; [self onNext]; return; } if (self.optionalStyle == TUISelectMemberOptionalStyleTransferOwner) { [self.selectedUsers removeAllObjects]; } if (isSelected) { for (TUIUserModel *user in self.selectedUsers) { if ([user.userId isEqualToString:userSelected.userId]) { [self.selectedUsers removeObject:user]; break; } } } else { [self.selectedUsers addObject:userSelected]; } [self updateUserPanel]; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (scrollView.contentOffset.y > 0 && (scrollView.contentOffset.y >= scrollView.bounds.origin.y)) { if (self.indicatorView.isAnimating) { return; } [self.indicatorView startAnimating]; @weakify(self); [self loadData:^(BOOL success, NSString *desc, NSArray *datas) { @strongify(self); [self.indicatorView stopAnimating]; if (!success) { return; } [self.memberList addObjectsFromArray:datas]; [self.selectTable reloadData]; [self.selectTable layoutIfNeeded]; if (datas.count == 0) { [self.selectTable setContentOffset:CGPointMake(0, scrollView.contentOffset.y - TMessageController_Header_Height) animated:YES]; } }]; } } #pragma mark UICollectionViewDelegate - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 1; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.selectedUsers.count; } - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"TUIMemberPanelCell"; TUIMemberPanelCell *cell = (TUIMemberPanelCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; if (indexPath.row < self.selectedUsers.count) { [cell fillWithData:self.selectedUsers[indexPath.row]]; } return cell; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return CGSizeMake(kUserBorder, kUserBorder); } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [collectionView deselectItemAtIndexPath:indexPath animated:NO]; if (indexPath.row < self.selectedUsers.count) { // to do } } #pragma mark data - (NSInteger)userPanelColumnCount { if (self.selectedUsers.count == 0) { return 0; } CGFloat totalWidth = self.view.mm_w - kUserPanelLeftSpacing; int columnCount = (int)(totalWidth / (kUserBorder + kUserSpacing)); return columnCount; } - (CGFloat)realSpacing { CGFloat totalWidth = self.view.mm_w - kUserPanelLeftSpacing; if (self.userPanelColumnCount == 0 || self.userPanelColumnCount == 1) { return 0; } return (totalWidth - (CGFloat)self.userPanelColumnCount * kUserBorder) / ((CGFloat)self.userPanelColumnCount - 1); } - (NSInteger)userPanelRowCount { NSInteger userCount = self.selectedUsers.count; NSInteger columnCount = MAX(self.userPanelColumnCount, 1); NSInteger rowCount = userCount / columnCount; if (userCount % columnCount != 0) { rowCount += 1; } return rowCount; } - (CGFloat)userPanelWidth { return (CGFloat)self.userPanelColumnCount * kUserBorder + ((CGFloat)self.userPanelColumnCount - 1) * self.realSpacing; } - (CGFloat)userPanelHeight { return (CGFloat)self.userPanelRowCount * kUserBorder + ((CGFloat)self.userPanelRowCount - 1) * self.realSpacing; } - (void)getMembers { @weakify(self); [self getMembersWithOptionalStyle]; [self loadData:^(BOOL success, NSString *desc, NSArray *datas) { @strongify(self); if (!success) { return; } [self.memberList addObjectsFromArray:datas]; [self.selectTable reloadData]; }]; } - (void)loadData:(void (^)(BOOL, NSString *, NSArray *))completion { if (self.isNoData) { if (completion) { completion(YES, @"there is no more data", @[]); } return; } __weak typeof(self) weakSelf = self; [[V2TIMManager sharedInstance] getGroupMemberList:self.groupId filter:V2TIM_GROUP_MEMBER_FILTER_ALL nextSeq:self.pageIndex succ:^(uint64_t nextSeq, NSArray *memberList) { weakSelf.pageIndex = nextSeq; weakSelf.isNoData = (nextSeq == 0); NSMutableArray *arrayM = [NSMutableArray array]; for (V2TIMGroupMemberFullInfo *info in memberList) { if ([info.userID isEqualToString:[[V2TIMManager sharedInstance] getLoginUser]]) { continue; } if (weakSelf.optionalStyle & TUISelectMemberOptionalStylePublicMan) { BOOL isSuper = (info.role == V2TIM_GROUP_MEMBER_ROLE_SUPER); BOOL isAdMin = (info.role == V2TIM_GROUP_MEMBER_ROLE_ADMIN); if (isSuper || isAdMin) { continue; } } if (self.selectedUserIDList && [self.selectedUserIDList containsObject:info.userID]) { continue; } TUIUserModel *model = [[TUIUserModel alloc] init]; model.userId = info.userID; if (info.nameCard.length > 0) { model.name = info.nameCard; } else if (info.friendRemark.length > 0) { model.name = info.friendRemark; } else if (info.nickName.length > 0) { model.name = info.nickName; } else { model.name = info.userID; } if (info.faceURL != nil) { model.avatar = info.faceURL; } [arrayM addObject:model]; } if (completion) { completion(YES, nil, [NSArray arrayWithArray:arrayM]); } } fail:^(int code, NSString *desc) { if (completion) { completion(NO, desc, @[]); } }]; } - (void)getMembersWithOptionalStyle { if (!NSThread.isMainThread) { __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf getMembersWithOptionalStyle]; }); return; } if (self.optionalStyle == TUISelectMemberOptionalStyleNone) { return; } if (self.optionalStyle & TUISelectMemberOptionalStyleAtAll) { TUIUserModel *model = [[TUIUserModel alloc] init]; model.userId = kImSDK_MesssageAtALL; model.name = TIMCommonLocalizableString(All); [self.memberList addObject:model]; } } - (BOOL)isUserSelected:(TUIUserModel *)user { BOOL isSelected = NO; for (TUIUserModel *selectUser in self.selectedUsers) { if ([selectUser.userId isEqualToString:user.userId] && ![selectUser.userId isEqualToString:[[V2TIMManager sharedInstance] getLoginUser]]) { isSelected = YES; break; } } return isSelected; } @end