482 lines
18 KiB
Objective-C
482 lines
18 KiB
Objective-C
//
|
|
// TUISelectGroupMemberViewController.m
|
|
// TXIMSDK_TUIKit_iOS
|
|
//
|
|
// Created by xiangzhang on 2020/7/6.
|
|
// Copyright © 2023 Tencent. All rights reserved.
|
|
//
|
|
|
|
#import "TUISelectGroupMemberViewController_Minimalist.h"
|
|
#import <TUICore/TUICore.h>
|
|
#import <TUICore/TUIDarkModel.h>
|
|
#import <TUICore/TUIGlobalization.h>
|
|
#import <TUICore/TUIThemeManager.h>
|
|
#import "ReactiveObjC/ReactiveObjC.h"
|
|
#import "TUIMemberPanelCell.h"
|
|
#import "TUISelectGroupMemberCell.h"
|
|
|
|
#define kUserBorder 44.0
|
|
#define kUserSpacing 2
|
|
#define kUserPanelLeftSpacing 15
|
|
|
|
@interface TUISelectGroupMemberViewController_Minimalist () <UICollectionViewDelegate,
|
|
UICollectionViewDataSource,
|
|
UICollectionViewDelegateFlowLayout,
|
|
UITableViewDelegate,
|
|
UITableViewDataSource>
|
|
@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<TUIUserModel *> *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_TUIContactObjectFactory_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<TUIUserModel *> *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<TUIUserModel *> *datas) {
|
|
@strongify(self);
|
|
if (!success) {
|
|
return;
|
|
}
|
|
[self.memberList addObjectsFromArray:datas];
|
|
[self.selectTable reloadData];
|
|
}];
|
|
}
|
|
|
|
- (void)loadData:(void (^)(BOOL, NSString *, NSArray<TUIUserModel *> *))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<V2TIMGroupMemberFullInfo *> *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
|