mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
516 lines
19 KiB
Objective-C
516 lines
19 KiB
Objective-C
#import "TGSelectContactController.h"
|
|
|
|
#import "TGAppDelegate.h"
|
|
#import "TGRootController.h"
|
|
|
|
#import "TGToolbarButton.h"
|
|
|
|
#import "TGUser.h"
|
|
#import "TGInterfaceManager.h"
|
|
|
|
#import "SGraphObjectNode.h"
|
|
|
|
#import "TGMessage+Telegraph.h"
|
|
|
|
#import "TGDatabase.h"
|
|
#import "TGTelegraph.h"
|
|
|
|
#import "TGProgressWindow.h"
|
|
|
|
#import "TGCreateGroupController.h"
|
|
|
|
#import "TGImageUtils.h"
|
|
#import "TGFont.h"
|
|
|
|
#import "TGAlertView.h"
|
|
#import "TGApplicationFeatures.h"
|
|
|
|
#import "TGChannelManagementSignals.h"
|
|
|
|
#import "TGTelegramNetworking.h"
|
|
|
|
#import "TGGroupInfoContactListCreateLinkCell.h"
|
|
|
|
@interface TGSelectContactController ()
|
|
{
|
|
UIView *_titleContainer;
|
|
UILabel *_titleLabel;
|
|
UILabel *_counterLabel;
|
|
|
|
int _displayUserCountLimit;
|
|
}
|
|
|
|
@property (nonatomic, strong) TGCreateGroupController *createGroupController;
|
|
|
|
@property (nonatomic) bool createEncrypted;
|
|
@property (nonatomic) bool createBroadcast;
|
|
@property (nonatomic) bool createChannel;
|
|
@property (nonatomic) bool inviteToChannel;
|
|
|
|
@property (nonatomic, strong) TGProgressWindow *progressWindow;
|
|
|
|
@property (nonatomic) TGUser *currentEncryptedUser;
|
|
|
|
@end
|
|
|
|
@implementation TGSelectContactController
|
|
|
|
- (id)initWithCreateGroup:(bool)createGroup createEncrypted:(bool)createEncrypted createBroadcast:(bool)createBroadcast createChannel:(bool)createChannel inviteToChannel:(bool)inviteToChannel showLink:(bool)showLink
|
|
{
|
|
int contactsMode = TGContactsModeRegistered;
|
|
if (createEncrypted)
|
|
{
|
|
_createEncrypted = true;
|
|
}
|
|
else
|
|
{
|
|
_createBroadcast = createBroadcast;
|
|
_createChannel = createChannel;
|
|
_inviteToChannel = inviteToChannel;
|
|
|
|
if (createGroup)
|
|
contactsMode |= TGContactsModeCompose;
|
|
else if (createChannel || inviteToChannel) {
|
|
contactsMode |= (TGContactsModeCompose | TGContactsModeSearchGlobal);
|
|
if (showLink) {
|
|
contactsMode |= TGContactsModeCreateGroupLink | TGContactsModeManualFirstSection;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
contactsMode |= TGContactsModeCreateGroupOption;
|
|
}
|
|
|
|
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
|
|
{
|
|
[self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Close") style:UIBarButtonItemStylePlain target:self action:@selector(closePressed)]];
|
|
}
|
|
}
|
|
|
|
self = [super initWithContactsMode:contactsMode];
|
|
if (self)
|
|
{
|
|
if (createChannel || inviteToChannel) {
|
|
self.usersSelectedLimit = 0;
|
|
self.composePlaceholder = TGLocalized(@"Compose.ChannelTokenListPlaceholder");
|
|
} else {
|
|
self.usersSelectedLimit = 199;
|
|
|
|
NSData *data = [TGDatabaseInstance() customProperty:@"maxChatParticipants"];
|
|
if (data.length >= 4)
|
|
{
|
|
int32_t maxChatParticipants = 0;
|
|
[data getBytes:&maxChatParticipants length:4];
|
|
if (maxChatParticipants == 0)
|
|
self.usersSelectedLimit = 99;
|
|
else
|
|
self.usersSelectedLimit = MAX(0, maxChatParticipants - 1);
|
|
}
|
|
|
|
#if TARGET_IPHONE_SIMULATOR
|
|
//self.usersSelectedLimit = 10;
|
|
#endif
|
|
|
|
_displayUserCountLimit = self.usersSelectedLimit + 1;
|
|
|
|
data = [TGDatabaseInstance() customProperty:@"maxChannelGroupMembers"];
|
|
if (data.length >= 4)
|
|
{
|
|
int32_t maxChannelGroupMembers = 0;
|
|
[data getBytes:&maxChannelGroupMembers length:4];
|
|
if (maxChannelGroupMembers != 0) {
|
|
_displayUserCountLimit = MAX(_displayUserCountLimit, maxChannelGroupMembers);
|
|
}
|
|
}
|
|
|
|
self.usersSelectedLimitAlert = TGLocalized(@"CreateGroup.SoftUserLimitAlert");
|
|
|
|
self.composePlaceholder = TGLocalized(@"Compose.TokenListPlaceholder");
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)closePressed
|
|
{
|
|
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
|
|
{
|
|
[TGAppDelegateInstance.rootController clearContentControllers];
|
|
}
|
|
}
|
|
|
|
- (void)backPressed
|
|
{
|
|
[self.navigationController popViewControllerAnimated:true];
|
|
}
|
|
|
|
- (void)channelNextPressed {
|
|
NSArray *users = [self selectedComposeUsers];
|
|
if (users.count == 0) {
|
|
[[TGInterfaceManager instance] navigateToConversationWithId:_channelConversation.conversationId conversation:_channelConversation];
|
|
} else {
|
|
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
|
|
[progressWindow show:true];
|
|
|
|
[[[[TGChannelManagementSignals inviteUsers:_channelConversation.conversationId accessHash:_channelConversation.accessHash users:users] deliverOn:[SQueue mainQueue]] onDispose:^{
|
|
TGDispatchOnMainThread(^{
|
|
[progressWindow dismiss:true];
|
|
|
|
TGConversation *conversation = [TGDatabaseInstance() loadChannels:@[@(_channelConversation.conversationId)]][@(_channelConversation.conversationId)];
|
|
|
|
[[TGInterfaceManager instance] navigateToConversationWithId:conversation.conversationId conversation:conversation];
|
|
});
|
|
}] startWithNext:nil completed:nil];
|
|
}
|
|
}
|
|
|
|
- (void)cancelPressed {
|
|
[self.presentingViewController dismissViewControllerAnimated:true completion:nil];
|
|
}
|
|
|
|
- (void)inviteChannelNextPressed {
|
|
NSArray *users = [self selectedComposeUsers];
|
|
if (users.count == 0) {
|
|
[self cancelPressed];
|
|
} else {
|
|
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
|
|
[progressWindow show:true];
|
|
|
|
TGConversation *conversation = _channelConversation;
|
|
__weak TGSelectContactController *weakSelf = self;
|
|
[[[[[[TGChannelManagementSignals inviteUsers:_channelConversation.conversationId accessHash:_channelConversation.accessHash users:users] onCompletion:^ {
|
|
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
|
|
if (data == nil) {
|
|
data = [[TGCachedConversationData alloc] init];
|
|
}
|
|
|
|
NSMutableArray *userIds = [[NSMutableArray alloc] init];
|
|
for (TGUser *user in users) {
|
|
[userIds addObject:@(user.uid)];
|
|
}
|
|
|
|
return [data addMembers:userIds timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
|
|
}];
|
|
}] deliverOn:[SQueue mainQueue]] onDispose:^{
|
|
TGDispatchOnMainThread(^{
|
|
[progressWindow dismiss:true];
|
|
});
|
|
}] onCompletion:^{
|
|
__strong TGSelectContactController *strongSelf = weakSelf;
|
|
if (strongSelf != nil) {
|
|
if (strongSelf->_onChannelMembersInvited) {
|
|
strongSelf->_onChannelMembersInvited(users);
|
|
}
|
|
[strongSelf cancelPressed];
|
|
}
|
|
}] startWithNext:nil error:^(id error) {
|
|
NSString *errorType = [[TGTelegramNetworking instance] extractNetworkErrorType:error];
|
|
NSString *errorText = TGLocalized(@"Profile.CreateEncryptedChatError");
|
|
if ([errorType isEqual:@"USER_BLOCKED"]) {
|
|
errorText = _channelConversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddBlocked") : TGLocalized(@"Channel.ErrorAddBlocked");
|
|
} else if ([errorType isEqual:@"USERS_TOO_MUCH"]) {
|
|
if (_channelConversation.isChannelGroup) {
|
|
errorText = TGLocalized(@"Group.ErrorAddTooMuch");
|
|
} else {
|
|
errorText = TGLocalized(@"Channel.ErrorAddTooMuch");
|
|
}
|
|
} else if ([errorType isEqual:@"BOTS_TOO_MUCH"]) {
|
|
errorText = TGLocalized(@"Group.ErrorAddTooMuchBots");
|
|
} else if ([errorType isEqual:@"USER_NOT_MUTUAL_CONTACT"]) {
|
|
errorText = TGLocalized(@"Group.ErrorNotMutualContact");
|
|
} else if ([errorType isEqualToString:@"USER_PRIVACY_RESTRICTED"]) {
|
|
if (users.count == 1) {
|
|
NSString *format = conversation.isChannelGroup ? TGLocalized(@"Privacy.GroupsAndChannels.InviteToGroupError") : TGLocalized(@"Privacy.GroupsAndChannels.InviteToChannelError");
|
|
TGUser *user = users.firstObject;
|
|
errorText = [[NSString alloc] initWithFormat:format, user.displayFirstName, user.displayFirstName];
|
|
} else {
|
|
errorText = TGLocalized(@"Privacy.GroupsAndChannels.InviteToChannelMultipleError");
|
|
}
|
|
}
|
|
|
|
[[[TGAlertView alloc] initWithTitle:nil message:errorText cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:nil] show];
|
|
} completed:nil];
|
|
}
|
|
}
|
|
|
|
- (void)actionItemSelected
|
|
{
|
|
__autoreleasing NSString *disabledMessage = nil;
|
|
if (![TGApplicationFeatures isGroupCreationEnabled:&disabledMessage])
|
|
{
|
|
if ([self.tableView indexPathForSelectedRow])
|
|
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:true];
|
|
[[[TGAlertView alloc] initWithTitle:TGLocalized(@"FeatureDisabled.Oops") message:disabledMessage cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:nil] show];
|
|
return;
|
|
}
|
|
|
|
TGSelectContactController *createGroupController = [[TGSelectContactController alloc] initWithCreateGroup:true createEncrypted:false createBroadcast:false createChannel:false inviteToChannel:false showLink:false];
|
|
[self.navigationController pushViewController:createGroupController animated:true];
|
|
}
|
|
|
|
- (void)encryptionItemSelected
|
|
{
|
|
TGSelectContactController *selectContactController = [[TGSelectContactController alloc] initWithCreateGroup:false createEncrypted:true createBroadcast:false createChannel:false inviteToChannel:false showLink:false];
|
|
[self.navigationController pushViewController:selectContactController animated:true];
|
|
}
|
|
|
|
- (NSString *)baseTitle
|
|
{
|
|
if (_createChannel || _inviteToChannel) {
|
|
return TGLocalized(@"Compose.ChannelMembers");
|
|
}
|
|
return _createBroadcast ? TGLocalized(@"Compose.NewBroadcast") : TGLocalized(@"Compose.NewGroup");
|
|
}
|
|
|
|
- (void)loadView
|
|
{
|
|
[super loadView];
|
|
|
|
if ((self.contactsMode & TGContactsModeCompose) == TGContactsModeCompose)
|
|
{
|
|
if (!_createChannel && !_inviteToChannel) {
|
|
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Next") style:UIBarButtonItemStylePlain target:self action:@selector(createButtonPressed:)]];
|
|
} else if (_createChannel){
|
|
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Next") style:UIBarButtonItemStyleDone target:self action:@selector(channelNextPressed)]];
|
|
} else if (_inviteToChannel) {
|
|
[self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Cancel") style:UIBarButtonItemStyleDone target:self action:@selector(cancelPressed)]];
|
|
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Done") style:UIBarButtonItemStyleDone target:self action:@selector(inviteChannelNextPressed)]];
|
|
}
|
|
|
|
if (!self.createChannel) {
|
|
self.navigationItem.rightBarButtonItem.enabled = [self selectedContactsCount] != 0;
|
|
}
|
|
|
|
self.titleText = [self baseTitle];
|
|
|
|
_titleContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2, 2)];
|
|
|
|
_titleLabel = [[UILabel alloc] init];
|
|
_titleLabel.backgroundColor = [UIColor clearColor];
|
|
_titleLabel.textColor = [UIColor blackColor];
|
|
_titleLabel.font = TGBoldSystemFontOfSize(17.0f);
|
|
_titleLabel.text = [self baseTitle];
|
|
[_titleLabel sizeToFit];
|
|
[_titleContainer addSubview:_titleLabel];
|
|
|
|
_counterLabel = [[UILabel alloc] init];
|
|
_counterLabel.backgroundColor = [UIColor clearColor];
|
|
_counterLabel.textColor = UIColorRGB(0x8e8e93);
|
|
_counterLabel.font = TGSystemFontOfSize(15.0f);
|
|
_counterLabel.text = [[NSString alloc] initWithFormat:@"0/%d", _displayUserCountLimit];
|
|
if (!_createChannel && !_inviteToChannel) {
|
|
[_titleContainer addSubview:_counterLabel];
|
|
}
|
|
|
|
[self setTitleView:_titleContainer];
|
|
}
|
|
else if (_createEncrypted)
|
|
{
|
|
self.titleText = TGLocalized(@"Compose.NewEncryptedChat");
|
|
}
|
|
else
|
|
{
|
|
self.titleText = TGLocalized(@"Compose.NewMessage");
|
|
}
|
|
|
|
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
|
|
{
|
|
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Back") style:UIBarButtonItemStylePlain target:self action:@selector(backPressed)];
|
|
}
|
|
}
|
|
|
|
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
|
{
|
|
[self _layoutTitleViews:toInterfaceOrientation];
|
|
|
|
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
|
|
[self _layoutTitleViews:self.interfaceOrientation];
|
|
}
|
|
|
|
- (void)_layoutTitleViews:(UIInterfaceOrientation)orientation
|
|
{
|
|
CGFloat portraitOffset = 0.0f;
|
|
CGFloat landscapeOffset = 0.0f;
|
|
CGFloat indicatorOffset = 0.0f;
|
|
if (iosMajorVersion() >= 7)
|
|
{
|
|
portraitOffset = 1.0f;
|
|
landscapeOffset = 0.0f;
|
|
indicatorOffset = -1.0f;
|
|
}
|
|
else
|
|
{
|
|
portraitOffset = -1.0f;
|
|
landscapeOffset = 1.0f;
|
|
indicatorOffset = 0.0f;
|
|
}
|
|
|
|
[_counterLabel sizeToFit];
|
|
CGSize counterSize = _counterLabel.frame.size;
|
|
|
|
CGRect titleLabelFrame = _titleLabel.frame;
|
|
|
|
if (_createChannel || _inviteToChannel) {
|
|
titleLabelFrame.origin = CGPointMake(CGFloor((_titleContainer.frame.size.width - titleLabelFrame.size.width) / 2.0f), CGFloor((_titleContainer.frame.size.height - titleLabelFrame.size.height) / 2.0f) + (UIInterfaceOrientationIsPortrait(orientation) ? portraitOffset : landscapeOffset));
|
|
_titleLabel.frame = titleLabelFrame;
|
|
} else {
|
|
titleLabelFrame.origin = CGPointMake(CGFloor((_titleContainer.frame.size.width - titleLabelFrame.size.width) / 2.0f - counterSize.width / 2.0f), CGFloor((_titleContainer.frame.size.height - titleLabelFrame.size.height) / 2.0f) + (UIInterfaceOrientationIsPortrait(orientation) ? portraitOffset : landscapeOffset));
|
|
_titleLabel.frame = titleLabelFrame;
|
|
|
|
_counterLabel.frame = CGRectMake(CGRectGetMaxX(titleLabelFrame) + 4, titleLabelFrame.origin.y + 2 - TGRetinaPixel, counterSize.width, counterSize.height);
|
|
}
|
|
}
|
|
|
|
- (void)createButtonPressed:(id)__unused sender
|
|
{
|
|
NSArray *contacts = [self selectedContactsList];
|
|
if (contacts.count == 0)
|
|
return;
|
|
else
|
|
{
|
|
if (_createGroupController == nil)
|
|
{
|
|
_createGroupController = [[TGCreateGroupController alloc] initWithCreateChannel:false createChannelGroup:false];
|
|
}
|
|
|
|
NSMutableArray *userIds = [[NSMutableArray alloc] init];
|
|
for (TGUser *user in [self selectedComposeUsers])
|
|
{
|
|
[userIds addObject:@(user.uid)];
|
|
}
|
|
[_createGroupController setUserIds:userIds];
|
|
|
|
[self.navigationController pushViewController:_createGroupController animated:true];
|
|
}
|
|
}
|
|
|
|
- (void)contactSelected:(TGUser *)user
|
|
{
|
|
int count = [self selectedContactsCount];
|
|
|
|
if (!_createChannel) {
|
|
self.navigationItem.rightBarButtonItem.enabled = count != 0;
|
|
}
|
|
|
|
[super contactSelected:user];
|
|
|
|
[self updateCount:count];
|
|
}
|
|
|
|
- (void)updateCount:(int)count
|
|
{
|
|
_counterLabel.text = [[NSString alloc] initWithFormat:@"%d/%d", count, _displayUserCountLimit];
|
|
[self _layoutTitleViews:self.interfaceOrientation];
|
|
}
|
|
|
|
- (void)singleUserSelected:(TGUser *)user
|
|
{
|
|
if (_createEncrypted)
|
|
{
|
|
if ([self.tableView indexPathForSelectedRow] != nil)
|
|
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:true];
|
|
|
|
_progressWindow = [[TGProgressWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
|
[_progressWindow show:true];
|
|
|
|
_currentEncryptedUser = user;
|
|
|
|
static int actionId = 0;
|
|
[ActionStageInstance() requestActor:[[NSString alloc] initWithFormat:@"/tg/encrypted/createChat/(profile%d)", actionId++] options:@{@"uid": @(user.uid)} flags:0 watcher:self];
|
|
}
|
|
else
|
|
{
|
|
[super singleUserSelected:user];
|
|
}
|
|
}
|
|
|
|
- (void)contactDeselected:(TGUser *)user
|
|
{
|
|
int count = [self selectedContactsCount];
|
|
|
|
if (!_createChannel) {
|
|
self.navigationItem.rightBarButtonItem.enabled = count != 0;
|
|
}
|
|
|
|
[super contactDeselected:user];
|
|
|
|
[self updateCount:count];
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)actionStageActionRequested:(NSString *)action options:(NSDictionary *)options
|
|
{
|
|
if ([action isEqualToString:@"chatCreated"])
|
|
{
|
|
_shouldBeRemovedFromNavigationAfterHiding = true;
|
|
}
|
|
|
|
if ([[self superclass] instancesRespondToSelector:@selector(actionStageActionRequested:options:)])
|
|
[super actionStageActionRequested:action options:options];
|
|
}
|
|
|
|
- (void)actorCompleted:(int)status path:(NSString *)path result:(id)result
|
|
{
|
|
if ([path hasPrefix:@"/tg/encrypted/createChat/"])
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^
|
|
{
|
|
[_progressWindow dismiss:true];
|
|
_progressWindow = nil;
|
|
|
|
if (status == ASStatusSuccess)
|
|
{
|
|
TGConversation *conversation = result[@"conversation"];
|
|
[[TGInterfaceManager instance] navigateToConversationWithId:conversation.conversationId conversation:conversation];
|
|
}
|
|
else
|
|
{
|
|
[[[TGAlertView alloc] initWithTitle:nil message:status == -2 ? [[NSString alloc] initWithFormat:TGLocalized(@"Profile.CreateEncryptedChatOutdatedError"), _currentEncryptedUser.displayFirstName, _currentEncryptedUser.displayFirstName] : TGLocalized(@"Profile.CreateEncryptedChatError") delegate:nil cancelButtonTitle:TGLocalized(@"Common.OK") otherButtonTitles:nil] show];
|
|
}
|
|
});
|
|
}
|
|
|
|
if ([[self superclass] instancesRespondToSelector:@selector(actorCompleted:path:result:)])
|
|
[super actorCompleted:status path:path result:result];
|
|
}
|
|
|
|
- (UITableViewCell *)cellForRowInFirstSection:(NSInteger)__unused row
|
|
{
|
|
TGGroupInfoContactListCreateLinkCell *cell = (TGGroupInfoContactListCreateLinkCell *)[self.tableView dequeueReusableCellWithIdentifier:@"TGGroupInfoContactListCreateLinkCell"];
|
|
if (cell == nil)
|
|
{
|
|
cell = [[TGGroupInfoContactListCreateLinkCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"TGGroupInfoContactListCreateLinkCell"];
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (NSInteger)numberOfRowsInFirstSection
|
|
{
|
|
if (self.contactsMode & TGContactsModeCreateGroupLink)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
- (CGFloat)itemHeightForFirstSection
|
|
{
|
|
return 48.0f;
|
|
}
|
|
|
|
- (void)didSelectRowInFirstSection:(NSInteger)__unused row
|
|
{
|
|
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:true];
|
|
if (_onCreateLink) {
|
|
_onCreateLink();
|
|
}
|
|
}
|
|
|
|
@end
|