1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-02 09:27:55 +01:00
Telegram/Telegraph/TGChannelMembersController.m
2016-02-25 01:03:51 +01:00

1025 lines
52 KiB
Objective-C

#import "TGChannelMembersController.h"
#import "TGTelegraph.h"
#import "TGConversation.h"
#import "TGUser.h"
#import "TGDatabase.h"
#import "TGTelegramNetworking.h"
#import "TGButtonCollectionItem.h"
#import "TGGroupInfoUserCollectionItem.h"
#import "TGSelectContactController.h"
#import "TGChannelManagementSignals.h"
#import "TGProgressWindow.h"
#import "ActionStage.h"
#import "TGBotUserInfoController.h"
#import "TGTelegraphUserInfoController.h"
#import "TGGroupInfoShareLinkController.h"
#import "TGCommentCollectionItem.h"
#import "TGGroupInfoSelectContactController.h"
#import "TGNavigationController.h"
#import "TGNavigationBar.h"
#import "TGAlertView.h"
#import "TGChannelModeratorController.h"
#import "TGChannelMembersControllerEmptyView.h"
#import "TGVariantCollectionItem.h"
#import "TGHeaderCollectionItem.h"
#import "TGActionSheet.h"
@interface TGChannelMembersController () <ASWatcher, TGGroupInfoSelectContactControllerDelegate> {
TGConversation *_conversation;
TGChannelMembersMode _mode;
id<SDisposable> _channelMembersDisposable;
NSString *_privateLink;
TGCollectionMenuSection *_adminSection;
TGCollectionMenuSection *_usersSection;
int _usersSectionPaddingTop;
int _usersSectionPaddingBottom;
TGCollectionMenuSection *_inviteControlSection;
TGVariantCollectionItem *_inviteControlItem;
TGCommentCollectionItem *_inviteControlComment;
NSArray *_users;
NSDictionary *_memberDatas;
UIActivityIndicatorView *_activityIndicator;
bool _editing;
id<SDisposable> _cachedDataDisposable;
TGChannelMembersControllerEmptyView *_emptyView;
}
@property (nonatomic, strong) ASHandle *actionHandle;
@end
@implementation TGChannelMembersController
- (instancetype)initWithConversation:(TGConversation *)conversation mode:(TGChannelMembersMode)mode {
self = [super init];
if (self != nil) {
_conversation = conversation;
_mode = mode;
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true];
switch (mode) {
case TGChannelMembersModeMembers:
self.title = TGLocalized(@"Channel.Members.Title");
break;
case TGChannelMembersModeBlacklist:
self.title = TGLocalized(@"Channel.BlackList.Title");
break;
case TGChannelMembersModeAdmins:
self.title = TGLocalized(@"Channel.Management.Title");
break;
}
if (mode == TGChannelMembersModeAdmins && _conversation.isChannelGroup && _conversation.channelRole == TGChannelRoleCreator) {
_inviteControlItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"ChannelMembers.WhoCanAddMembers") action:@selector(whoCanAddMembersPressed)];
_inviteControlItem.deselectAutomatically = true;
if (_conversation.everybodyCanAddMembers) {
_inviteControlItem.variant = TGLocalized(@"ChannelMembers.WhoCanAddMembers.AllMembers");
} else {
_inviteControlItem.variant = TGLocalized(@"ChannelMembers.WhoCanAddMembers.Admins");
}
_inviteControlComment = [[TGCommentCollectionItem alloc] initWithText:@""];
if (_conversation.everybodyCanAddMembers) {
_inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAllHelp");
} else {
_inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAdminsHelp");
}
_inviteControlSection = [[TGCollectionMenuSection alloc] initWithItems:@[_inviteControlItem, _inviteControlComment]];
[self.menuSections addSection:_inviteControlSection];
}
TGButtonCollectionItem *addMemberItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Members.AddMembers") action:@selector(addMembersPressed)];
NSMutableArray *adminSectionItems = [[NSMutableArray alloc] init];
[adminSectionItems addObject:addMemberItem];
if (_conversation.username.length == 0) {
TGButtonCollectionItem *linkItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Members.InviteLink") action:@selector(linkPressed)];
[adminSectionItems addObject:linkItem];
}
TGCommentCollectionItem *addMemberHelpItem = [[TGCommentCollectionItem alloc] initWithFormattedText:TGLocalized(@"Channel.Members.AddMembersHelp")];
[adminSectionItems addObject:addMemberHelpItem];
TGHeaderCollectionItem *adminsTitleItem = [[TGHeaderCollectionItem alloc] initWithTitle:_conversation.isChannelGroup ? TGLocalized(@"ChannelMembers.GroupAdminsTitle") : TGLocalized(@"ChannelMembers.ChannelAdminsTitle")];
TGButtonCollectionItem *addModeratorItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Management.AddModerator") action:@selector(addModeratorPressed)];
addModeratorItem.leftInset = 65.0f;
addModeratorItem.icon = [UIImage imageNamed:@"GroupInfoIconAddMember.png"];
addModeratorItem.titleColor = TGAccentColor();
addModeratorItem.deselectAutomatically = true;
TGCommentCollectionItem *commentItem = [[TGCommentCollectionItem alloc] initWithFormattedText:_conversation.isChannelGroup ? TGLocalized(@"Group.Management.AddModeratorHelp") : TGLocalized(@"Channel.Management.AddModeratorHelp")];
_adminSection = [[TGCollectionMenuSection alloc] initWithItems:adminSectionItems];
switch (mode) {
case TGChannelMembersModeMembers: {
if (conversation.channelRole == TGChannelRoleCreator) {
[self.menuSections addSection:_adminSection];
}
break;
}
case TGChannelMembersModeAdmins: {
break;
}
default:
break;
}
NSMutableArray *usersSectionItems = [[NSMutableArray alloc] init];
if (_mode == TGChannelMembersModeAdmins && conversation.channelRole == TGChannelRoleCreator) {
[usersSectionItems addObject:adminsTitleItem];
[usersSectionItems addObject:addModeratorItem];
[usersSectionItems addObject:commentItem];
_usersSectionPaddingTop = 1;
_usersSectionPaddingBottom = 2;
}
_usersSection = [[TGCollectionMenuSection alloc] initWithItems:usersSectionItems];
[self.menuSections addSection:_usersSection];
TGCollectionMenuSection *topSection = self.menuSections.sections.firstObject;
UIEdgeInsets topSectionInsets = topSection.insets;
topSectionInsets.top = 32.0f;
topSection.insets = topSectionInsets;
SSignal *signal = nil;
switch (_mode) {
case TGChannelMembersModeMembers: {
SSignal *cachedSignal = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] take:1] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
if (cachedData.generalMembers.count == 0) {
return [SSignal complete];
} else {
NSMutableArray *users = [[NSMutableArray alloc] init];
NSMutableDictionary *memberDatas = [[NSMutableDictionary alloc] init];
for (TGCachedConversationMember *member in cachedData.generalMembers) {
TGUser *user = [TGDatabaseInstance() loadUser:member.uid];
if (user != nil) {
[users addObject:user];
memberDatas[@(member.uid)] = member;
}
}
return [SSignal single:@{@"users": users, @"memberDatas": memberDatas}];
}
}];
signal = [cachedSignal then:[[TGChannelManagementSignals channelMembers:conversation.conversationId accessHash:conversation.accessHash offset:0 count:128] onNext:^(NSDictionary *dict) {
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data updateGeneralMembers:[dict[@"memberDatas"] allValues]];
}];
}]];
break;
}
case TGChannelMembersModeBlacklist: {
SSignal *cachedSignal = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] take:1] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
if (cachedData.blacklistMembers.count == 0) {
return [SSignal single:@{@"users": @[], @"memberDatas": @{}}];
} else {
NSMutableArray *users = [[NSMutableArray alloc] init];
NSMutableDictionary *memberDatas = [[NSMutableDictionary alloc] init];
for (TGCachedConversationMember *member in cachedData.blacklistMembers) {
TGUser *user = [TGDatabaseInstance() loadUser:member.uid];
if (user != nil) {
[users addObject:user];
memberDatas[@(member.uid)] = member;
}
}
return [SSignal single:@{@"users": users, @"memberDatas": memberDatas}];
}
}];
signal = [cachedSignal then:[[[TGChannelManagementSignals channelBlacklistMembers:conversation.conversationId accessHash:conversation.accessHash offset:0 count:128] onNext:^(NSDictionary *dict) {
NSMutableArray *userIds = [[NSMutableArray alloc] init];
for (TGUser *user in dict[@"users"]) {
[userIds addObject:@(user.uid)];
}
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data updateBlacklistMembers:[dict[@"memberDatas"] allValues]];
}];
}] map:^id(NSDictionary *dict) {
NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
updatedDict[@"final"] = @(true);
return updatedDict;
}]];
break;
}
case TGChannelMembersModeAdmins: {
SSignal *cachedSignal = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] take:1] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
if (cachedData.managementMembers.count == 0) {
return [SSignal complete];
} else {
NSMutableArray *users = [[NSMutableArray alloc] init];
NSMutableDictionary *memberDatas = [[NSMutableDictionary alloc] init];
for (TGCachedConversationMember *member in cachedData.managementMembers) {
TGUser *user = [TGDatabaseInstance() loadUser:member.uid];
if (user != nil) {
[users addObject:user];
memberDatas[@(member.uid)] = member;
}
}
return [SSignal single:@{@"users": users, @"memberDatas": memberDatas}];
}
}];
signal = [cachedSignal then:[[TGChannelManagementSignals channelAdmins:conversation.conversationId accessHash:conversation.accessHash offset:0 count:128] onNext:^(NSDictionary *dict) {
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data updateManagementMembers:[dict[@"memberDatas"] allValues]];
}];
}]];
break;
}
}
__weak TGChannelMembersController *weakSelf = self;
_channelMembersDisposable = [[signal deliverOn:[SQueue mainQueue]] startWithNext:^(NSDictionary *dict) {
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
[self setUsers:dict[@"users"] memberDatas:dict[@"memberDatas"] isFinal:[dict[@"final"] boolValue]];
}
}];
_cachedDataDisposable = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] deliverOn:[SQueue mainQueue]] startWithNext:^(TGCachedConversationData *cachedData) {
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
strongSelf->_privateLink = cachedData.privateLink;
}
}];
}
return self;
}
- (void)dealloc {
[_channelMembersDisposable dispose];
[_actionHandle reset];
[ActionStageInstance() removeWatcher:self];
}
- (void)updateEmptyState:(bool)empty {
if (empty && _mode == TGChannelMembersModeBlacklist) {
if (_emptyView == nil) {
_emptyView = [[TGChannelMembersControllerEmptyView alloc] initWithText:TGLocalized(@"ChannelMembers.Blacklist.EmptyText")];
}
_emptyView.frame = self.view.bounds;
_emptyView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:_emptyView];
} else {
[_emptyView removeFromSuperview];
_emptyView = nil;
}
}
- (void)editPressed {
_editing = true;
[self enterEditingMode:true];
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Done") style:UIBarButtonItemStyleDone target:self action:@selector(donePressed)] animated:true];
[self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@" " style:UIBarButtonItemStylePlain target:self action:@selector(noAction)] animated:true];
}
- (void)noAction {
}
- (void)donePressed {
_editing = false;
[self leaveEditingMode:true];
[self setLeftBarButtonItem:nil animated:true];
if (_users.count != 0) {
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Edit") style:UIBarButtonItemStylePlain target:self action:@selector(editPressed)] animated:true];
}
}
- (void)setUsers:(NSArray *)users memberDatas:(NSDictionary *)memberDatas isFinal:(bool)isFinal {
TGDispatchOnMainThread(^{
_users = [users sortedArrayUsingComparator:^NSComparisonResult(TGUser *user1, TGUser *user2) {
if (user1.uid == TGTelegraphInstance.clientUserId) {
return NSOrderedAscending;
} else if (user2.uid == TGTelegraphInstance.clientUserId) {
return NSOrderedDescending;
}
TGCachedConversationMember *member1 = memberDatas[@(user1.uid)];
TGCachedConversationMember *member2 = memberDatas[@(user2.uid)];
switch (_mode) {
case TGChannelMembersModeBlacklist: {
if (member1.timestamp > member2.timestamp) {
return NSOrderedAscending;
} else if (member1.timestamp < member2.timestamp) {
return NSOrderedDescending;
}
return user1.uid < user2.uid;
}
case TGChannelMembersModeAdmins: {
return member1.role > member2.role ? NSOrderedAscending : NSOrderedDescending;
}
default: {
if (user1.botKind != user2.botKind) {
return user1.botKind < user2.botKind ? NSOrderedAscending : NSOrderedDescending;
}
if (user1.kind != user2.kind) {
return user1.kind < user2.kind ? NSOrderedAscending : NSOrderedDescending;
}
if (user1.presence.online != user2.presence.online)
return user1.presence.online ? NSOrderedAscending : NSOrderedDescending;
if ((user1.presence.lastSeen < 0) != (user2.presence.lastSeen < 0))
return user1.presence.lastSeen >= 0 ? NSOrderedAscending : NSOrderedDescending;
if (user1.presence.online) {
return member1.timestamp > member2.timestamp ? NSOrderedAscending : NSOrderedDescending;
}
if (user1.presence.lastSeen < 0) {
return member1.timestamp > member2.timestamp ? NSOrderedAscending : NSOrderedDescending;
}
return user1.presence.lastSeen > user2.presence.lastSeen ? NSOrderedAscending : NSOrderedDescending;
}
}
return NSOrderedSame;
}];
_memberDatas = memberDatas;
[self updateEditing];
self.collectionView.hidden = false;
[_activityIndicator removeFromSuperview];
_activityIndicator = nil;
if (isFinal || true) {
[self updateEmptyState:_users.count == 0];
}
while (_usersSection.items.count > (NSUInteger)(_usersSectionPaddingTop + _usersSectionPaddingBottom)) {
[_usersSection deleteItemAtIndex:_usersSectionPaddingTop];
}
bool canDeleteUsers = _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRolePublisher;
switch (_mode) {
case TGChannelMembersModeMembers: {
break;
}
case TGChannelMembersModeAdmins: {
canDeleteUsers = _conversation.channelRole == TGChannelRoleCreator;
break;
}
case TGChannelMembersModeBlacklist: {
break;
}
}
for (TGUser *user in _users) {
TGGroupInfoUserCollectionItem *userItem = [[TGGroupInfoUserCollectionItem alloc] init];
userItem.interfaceHandle = _actionHandle;
bool disabled = false;
userItem.selectable = user.uid != TGTelegraphInstance.clientUserId && !disabled;
bool canEditInPrinciple = user.uid != TGTelegraphInstance.clientUserId && canDeleteUsers;
bool canEdit = userItem.selectable && canEditInPrinciple;
[userItem setCanEdit:canEdit];
[userItem setUser:user];
[userItem setDisabled:disabled];
TGCachedConversationMember *member = memberDatas[@(user.uid)];
if (member != nil) {
if (_mode == TGChannelMembersModeAdmins) {
switch (member.role) {
case TGChannelRoleCreator:
[userItem setCustomStatus:TGLocalized(@"Channel.Management.LabelCreator")];
break;
case TGChannelRoleModerator:
[userItem setCustomStatus:TGLocalized(@"Channel.Management.LabelModerator")];
break;
case TGChannelRolePublisher:
[userItem setCustomStatus:TGLocalized(@"Channel.Management.LabelEditor")];
break;
default:
break;
}
}
}
NSString *optionTitle = nil;
switch (_mode) {
case TGChannelMembersModeMembers: {
optionTitle = TGLocalized(@"Channel.Members.Kick");
break;
}
case TGChannelMembersModeBlacklist: {
optionTitle = TGLocalized(@"Channel.Management.Remove");
break;
}
case TGChannelMembersModeAdmins: {
optionTitle = TGLocalized(@"Channel.Management.Remove");
break;
}
}
userItem.optionTitle = optionTitle;
[_usersSection insertItem:userItem atIndex:_usersSectionPaddingTop + _usersSection.items.count - _usersSectionPaddingTop - _usersSectionPaddingBottom];
}
[self.collectionView reloadData];
});
}
- (void)updateEditing {
bool canEdit = false;
for (int i = _usersSectionPaddingTop; i < (int)_usersSection.items.count - _usersSectionPaddingBottom; i++) {
TGGroupInfoUserCollectionItem *item = _usersSection.items[i];
if (item.user.uid != TGTelegraphInstance.clientUserId) {
canEdit = true;
}
}
if (canEdit) {
switch (_mode) {
case TGChannelMembersModeAdmins:
canEdit = _conversation.channelRole == TGChannelRoleCreator;
break;
case TGChannelMembersModeBlacklist:
canEdit = _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRoleModerator;
case TGChannelMembersModeMembers:
canEdit = _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRoleModerator;
}
}
if (canEdit) {
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Edit") style:UIBarButtonItemStylePlain target:self action:@selector(editPressed)]];
} else {
[self setLeftBarButtonItem:nil animated:false];
[self setRightBarButtonItem:nil animated:false];
if (_editing) {
[self leaveEditingMode:true];
}
}
}
- (void)loadView {
[super loadView];
if (_users == nil) {
self.collectionView.hidden = true;
[_activityIndicator removeFromSuperview];
_activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_activityIndicator.frame = CGRectMake(CGFloor((self.view.bounds.size.width - _activityIndicator.frame.size.width) / 2.0f), CGFloor((self.view.bounds.size.height - _activityIndicator.frame.size.height) / 2.0f), _activityIndicator.frame.size.width, _activityIndicator.frame.size.height);
_activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[self.view addSubview:_activityIndicator];
[_activityIndicator startAnimating];
}
}
- (void)addMembersPressed {
TGSelectContactController *selectController = [[TGSelectContactController alloc] initWithCreateGroup:false createEncrypted:false createBroadcast:false createChannel:false inviteToChannel:true showLink:false];
selectController.ignoreBots = true;
selectController.channelConversation = _conversation;
selectController.deselectAutomatically = true;
NSMutableArray *existingUsers = [[NSMutableArray alloc] init];
for (TGUser *user in _users) {
[existingUsers addObject:@(user.uid)];
}
selectController.disabledUsers = existingUsers;
__weak TGChannelMembersController *weakSelf = self;
selectController.onChannelMembersInvited = ^(NSArray *users) {
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
for (TGUser *user in users) {
if (updatedMemberDatas[@(user.uid)] != nil) {
continue;
}
updatedMemberDatas[@(user.uid)] = [[TGCachedConversationMember alloc] initWithUid:user.uid role:TGChannelRoleMember timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
[updatedUsers addObject:user];
}
[strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas isFinal:true];
}
};
TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[selectController]];
[self presentViewController:navigationController animated:true completion:nil];
}
- (void)actionStageActionRequested:(NSString *)action options:(id)options {
if ([action isEqualToString:@"deleteUser"])
{
int32_t uid = [options[@"uid"] int32Value];
if (uid != 0)
[self _commitDeleteParticipant:uid];
}
else if ([action isEqualToString:@"openUser"])
{
int32_t uid = [options[@"uid"] int32Value];
if (uid != 0)
{
TGUser *user = [TGDatabaseInstance() loadUser:uid];
switch (_mode) {
case TGChannelMembersModeAdmins: {
/*TGChannelModeratorController *controller = [[TGChannelModeratorController alloc] initWithConversation:_conversation user:user member:_memberDatas[@(user.uid)]];
__weak TGChannelMembersController *weakSelf = self;
TGConversation *conversation = _conversation;
controller.done = ^(TGCachedConversationMember *member) {
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
if (member == nil) {
SSignal *signal = [[TGChannelManagementSignals channelChangeRole:_conversation.conversationId accessHash:_conversation.accessHash user:user role:TGChannelRoleMember] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data removeManagementMember:user.uid];
}];
}];
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
[progressWindow show:true];
[[[signal deliverOn:[SQueue mainQueue]] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] startWithNext:nil completed:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
NSUInteger index = 0;
for (TGUser *user in updatedUsers) {
if (user.uid == uid) {
[updatedUsers removeObjectAtIndex:index];
[updatedMemberDatas removeObjectForKey:@(user.uid)];
[strongSelf->_usersSection deleteItemAtIndex:index];
strongSelf->_users = updatedUsers;
strongSelf->_memberDatas = updatedMemberDatas;
[strongSelf updateEditing];
[strongSelf.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:[strongSelf indexForSection:strongSelf->_usersSection]]]];
[strongSelf updateItemPositions];
break;
}
index++;
}
[strongSelf.navigationController popToViewController:strongSelf animated:true];
}
}];
} else if (member.role != ((TGCachedConversationMember *)strongSelf->_memberDatas[@(user.uid)]).role) {
SSignal *signal = [[TGChannelManagementSignals channelChangeRole:_conversation.conversationId accessHash:_conversation.accessHash user:user role:member.role] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data addManagementMember:member];
}];
}];
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
[progressWindow show:true];
[[[signal deliverOn:[SQueue mainQueue]] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] startWithNext:nil completed:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
updatedMemberDatas[@(uid)] = [[TGCachedConversationMember alloc] initWithUid:uid role:member.role timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
[strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas];
[strongSelf.navigationController popToViewController:strongSelf animated:true];
}
}];
} else {
[strongSelf.navigationController popToViewController:strongSelf animated:true];
}
}
};
[self.navigationController pushViewController:controller animated:true];
break;*/
}
default: {
if (user.kind == TGUserKindBot || user.kind == TGUserKindSmartBot) {
TGBotUserInfoController *userInfoController = [[TGBotUserInfoController alloc] initWithUid:uid sendCommand:nil];
[self.navigationController pushViewController:userInfoController animated:true];
}
else {
TGTelegraphUserInfoController *userInfoController = [[TGTelegraphUserInfoController alloc] initWithUid:uid];
[self.navigationController pushViewController:userInfoController animated:true];
}
break;
}
}
}
}
}
- (void)_commitDeleteParticipant:(int32_t)userId {
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
[progressWindow showWithDelay:0.5];
TGUser *user = [TGDatabaseInstance() loadUser:userId];
TGConversation *conversation = _conversation;
SSignal *signal = nil;
switch (_mode) {
case TGChannelMembersModeMembers: {
signal = [[TGChannelManagementSignals channelChangeMemberKicked:_conversation.conversationId accessHash:_conversation.accessHash user:user kicked:true] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data blacklistMember:userId timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
}];
}];
break;
}
case TGChannelMembersModeBlacklist: {
signal = [[TGChannelManagementSignals channelChangeMemberKicked:_conversation.conversationId accessHash:_conversation.accessHash user:user kicked:false] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data unblacklistMember:userId timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
}];
}];
break;
}
case TGChannelMembersModeAdmins: {
signal = [[TGChannelManagementSignals channelChangeRole:_conversation.conversationId accessHash:_conversation.accessHash user:user role:TGChannelRoleMember] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data removeManagementMember:userId];
}];
}];
break;
}
}
__weak TGChannelMembersController *weakSelf = self;
[[[signal deliverOn:[SQueue mainQueue]] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] startWithNext:nil completed:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
NSUInteger index = 0;
for (TGUser *user in updatedUsers) {
if (user.uid == userId) {
[updatedUsers removeObjectAtIndex:index];
[updatedMemberDatas removeObjectForKey:@(user.uid)];
[strongSelf->_usersSection deleteItemAtIndex:strongSelf->_usersSectionPaddingTop + index];
strongSelf->_users = updatedUsers;
strongSelf->_memberDatas = updatedMemberDatas;
[strongSelf updateEditing];
[strongSelf.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:strongSelf->_usersSectionPaddingTop + index inSection:[strongSelf indexForSection:strongSelf->_usersSection]]]];
[strongSelf updateItemPositions];
break;
}
index++;
}
}
}];
}
- (void)linkPressed {
TGGroupInfoShareLinkController *controller = [[TGGroupInfoShareLinkController alloc] initWithPeerId:_conversation.conversationId accessHash:_conversation.accessHash currentLink:_privateLink];
[self.navigationController pushViewController:controller animated:true];
}
- (void)addModeratorPressed {
int contactsMode = TGContactsModeRegistered | TGContactsModeManualFirstSection;
contactsMode |= TGContactsModeIgnorePrivateBots;
TGGroupInfoSelectContactController *selectContactController = [[TGGroupInfoSelectContactController alloc] initWithContactsMode:contactsMode];
selectContactController.deselectAutomatically = true;
selectContactController.delegate = self;
NSMutableArray *disabledUsers = [[NSMutableArray alloc] init];
NSMutableArray *userIds = [[NSMutableArray alloc] init];
for (TGUser *user in _users) {
[userIds addObject:@(user.uid)];
}
[disabledUsers addObjectsFromArray:userIds];
selectContactController.disabledUsers = disabledUsers;
TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[selectContactController] navigationBarClass:[TGWhiteNavigationBar class]];
if ([self inPopover]) {
navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
navigationController.presentationStyle = TGNavigationControllerPresentationStyleChildInPopover;
}
[self presentViewController:navigationController animated:true completion:nil];
}
- (SSignal *)modifyMemberRole:(TGUser *)user role:(TGChannelRole)role {
__weak TGChannelMembersController *weakSelf = self;
TGConversation *conversation = _conversation;
return [[SSignal defer:^SSignal *{
SSignal *changeSignal = [[TGChannelManagementSignals channelChangeRole:conversation.conversationId accessHash:conversation.accessHash user:user role:role] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data addManagementMember:[[TGCachedConversationMember alloc] initWithUid:user.uid role:role timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]]];
}];
}];
__block TGProgressWindow *progressWindow = nil;
return [[[[[changeSignal deliverOn:[SQueue mainQueue]] onStart:^{
progressWindow = [[TGProgressWindow alloc] init];
[progressWindow show:true];
}] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] onCompletion:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
if (updatedMemberDatas[@(user.uid)] == nil) {
[updatedUsers addObject:user];
}
updatedMemberDatas[@(user.uid)] = [[TGCachedConversationMember alloc] initWithUid:user.uid role:role timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
[strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas isFinal:true];
[strongSelf updateEditing];
}
}] onError:^(id error) {
TGDispatchOnMainThread(^{
NSString *errorType = [[TGTelegramNetworking instance] extractNetworkErrorType:error];
NSString *errorText = TGLocalized(@"Profile.CreateEncryptedChatError");
if ([errorType isEqual:@"USER_BLOCKED"]) {
errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddBlocked") : TGLocalized(@"Channel.ErrorAddBlocked");
} else if ([errorType isEqual:@"USERS_TOO_MUCH"]) {
errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddTooMuch") : TGLocalized(@"Channel.ErrorAddTooMuch");
} else if ([errorType isEqual:@"USER_NOT_MUTUAL_CONTACT"]) {
errorText = TGLocalized(@"Group.ErrorNotMutualContact");
} else if ([errorType isEqual:@"ADMINS_TOO_MUCH"]) {
errorText = TGLocalized(@"Group.ErrorAddTooMuchAdmins");
} else if ([errorType isEqual:@"USER_PRIVACY_RESTRICTED"]) {
NSString *format = conversation.isChannelGroup ? TGLocalized(@"Privacy.GroupsAndChannels.InviteToGroupError") : TGLocalized(@"Privacy.GroupsAndChannels.InviteToChannelError");
errorText = [[NSString alloc] initWithFormat:format, user.displayFirstName, user.displayFirstName];
}
[[[TGAlertView alloc] initWithTitle:nil message:errorText cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:nil] show];
});
}];
}] startOn:[SQueue mainQueue]];
}
- (SSignal *)memberRole:(TGUser *)user {
TGConversation *conversation = _conversation;
return [[SSignal defer:^SSignal *{
SSignal *roleSignal = [TGChannelManagementSignals channelRole:conversation.conversationId accessHash:conversation.accessHash user:user];
__block TGProgressWindow *progressWindow = nil;
return [[[roleSignal deliverOn:[SQueue mainQueue]] onStart:^{
progressWindow = [[TGProgressWindow alloc] init];
[progressWindow show:true];
}] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}];
}] startOn:[SQueue mainQueue]];
}
- (SSignal *)addManagementMember:(TGUser *)user role:(TGChannelRole)role {
if (user.kind == TGUserKindGeneric) {
__weak TGChannelMembersController *weakSelf = self;
return [[self memberRole:user] mapToSignal:^SSignal *(TGCachedConversationMember *member) {
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
if (member == nil) {
SPipe *pipe = [[SPipe alloc] init];
[[[TGAlertView alloc] initWithTitle:nil message:[[NSString alloc] initWithFormat: TGLocalized(@"Channel.Management.ErrorNotMember"), user.displayFirstName] cancelButtonTitle:TGLocalized(@"Common.Cancel") okButtonTitle:TGLocalized(@"Common.OK") completionBlock:^(bool okButtonPressed) {
if (okButtonPressed) {
pipe.sink([[strongSelf addMember:user] then:[strongSelf modifyMemberRole:user role:role]]);
} else {
pipe.sink([SSignal fail:nil]);
}
}] show];
return [[pipe.signalProducer() take:1] switchToLatest];
} else {
return [strongSelf modifyMemberRole:user role:role];
}
} else {
return [SSignal fail:nil];
}
}];
} else {
return [self modifyMemberRole:user role:role];
}
}
- (SSignal *)addMember:(TGUser *)user {
__weak TGChannelMembersController *weakSelf = self;
TGConversation *conversation = _conversation;
return [[SSignal defer:^SSignal *{
SSignal *addSignal = [[[TGChannelManagementSignals inviteUsers:conversation.conversationId accessHash:conversation.accessHash users:@[user]] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data addMembers:@[@(user.uid)] timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
}];
}] onError:^(id error) {
TGDispatchOnMainThread(^{
NSString *errorType = [[TGTelegramNetworking instance] extractNetworkErrorType:error];
NSString *errorText = TGLocalized(@"Profile.CreateEncryptedChatError");
if ([errorType isEqual:@"USER_BLOCKED"]) {
errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddBlocked") : TGLocalized(@"Channel.ErrorAddBlocked");
} else if ([errorType isEqual:@"USERS_TOO_MUCH"]) {
errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddTooMuch") : TGLocalized(@"Channel.ErrorAddTooMuch");
} else if ([errorType isEqual:@"USER_NOT_MUTUAL_CONTACT"]) {
errorText = TGLocalized(@"Group.ErrorNotMutualContact");
} else if ([errorType isEqual:@"ADMINS_TOO_MUCH"]) {
errorText = TGLocalized(@"Group.ErrorAddTooMuchAdmins");
} else if ([errorType isEqualToString:@"USER_PRIVACY_RESTRICTED"]) {
NSString *format = conversation.isChannelGroup ? TGLocalized(@"Privacy.GroupsAndChannels.InviteToGroupError") : TGLocalized(@"Privacy.GroupsAndChannels.InviteToChannelError");
errorText = [[NSString alloc] initWithFormat:format, user.displayFirstName, user.displayFirstName];
}
[[[TGAlertView alloc] initWithTitle:nil message:errorText cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:nil] show];
});
}];
__block TGProgressWindow *progressWindow = nil;
return [[[[addSignal deliverOn:[SQueue mainQueue]] onStart:^{
progressWindow = [[TGProgressWindow alloc] init];
[progressWindow show:true];
}] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] onCompletion:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
if (strongSelf->_mode == TGChannelMembersModeMembers) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
[updatedUsers addObject:user];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
updatedMemberDatas[@(user.uid)] = [[TGCachedConversationMember alloc] initWithUid:user.uid role:TGChannelRoleMember timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
[strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas isFinal:true];
[strongSelf updateEditing];
}
}
}];
}] startOn:[SQueue mainQueue]];
}
- (void)selectContactControllerDidSelectUser:(TGUser *)user {
if (user == nil) {
[self dismissViewControllerAnimated:true completion:nil];
return;
}
__weak TGChannelMembersController *weakSelf = self;
if (_conversation.username.length == 0 || true) {
[[self addManagementMember:user role:TGChannelRolePublisher] startWithNext:nil completed:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf dismissViewControllerAnimated:true completion:nil];
}
}];
} else {
__unused TGChannelModeratorController *controller = [[TGChannelModeratorController alloc] initWithConversation:_conversation user:user member:nil];
__weak TGChannelMembersController *weakSelf = self;
controller.done = ^(TGCachedConversationMember *member) {
if (member == nil) {
member = [[TGCachedConversationMember alloc] initWithUid:user.uid role:TGChannelRoleModerator timestamp:0];
}
[[self addManagementMember:user role:member.role] startWithNext:nil completed:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf dismissViewControllerAnimated:true completion:nil];
}
}];
};
if ([self.presentedViewController isKindOfClass:[TGNavigationController class]]) {
[(UINavigationController *)self.presentedViewController pushViewController:controller animated:true];
}
}
}
- (void)whoCanAddMembersPressed {
__weak TGChannelMembersController *weakSelf = self;
[[[TGActionSheet alloc] initWithTitle:nil actions:@[
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"ChannelMembers.WhoCanAddMembers.AllMembers") action:@"all"],
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"ChannelMembers.WhoCanAddMembers.Admins") action:@"admins"],
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]
] actionBlock:^(__unused id target, NSString *action) {
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
if ([action isEqualToString:@"all"]) {
[strongSelf updateWhoCanAddMembers:true];
} else if ([action isEqualToString:@"admins"]) {
[strongSelf updateWhoCanAddMembers:false];
}
}
} target:self] showInView:self.view];
}
- (void)updateWhoCanAddMembers:(bool)allMembers {
if (allMembers != _conversation.everybodyCanAddMembers) {
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
[progressWindow showWithDelay:0.2];
__weak TGChannelMembersController *weakSelf = self;
[[[[TGChannelManagementSignals toggleChannelEverybodyCanInviteMembers:_conversation.conversationId accessHash:_conversation.accessHash enabled:allMembers] deliverOn:[SQueue mainQueue]] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] startWithNext:nil completed:^{
__strong TGChannelMembersController *strongSelf = weakSelf;
if (strongSelf != nil) {
strongSelf->_conversation.everybodyCanAddMembers = allMembers;
}
}];
_inviteControlItem.variant = allMembers ? TGLocalized(@"ChannelMembers.WhoCanAddMembers.AllMembers") : TGLocalized(@"ChannelMembers.WhoCanAddMembers.Admins");
if (allMembers) {
_inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAllHelp");
} else {
_inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAdminsHelp");
}
}
}
@end