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

1586 lines
69 KiB
Objective-C

#import "TGChannelGroupInfoController.h"
#import "ActionStage.h"
#import "SGraphObjectNode.h"
#import "TGConversation.h"
#import "TGDatabase.h"
#import "TGHacks.h"
#import "TGFont.h"
#import "TGStringUtils.h"
#import "UIDevice+PlatformInfo.h"
#import "TGInterfaceAssets.h"
#import "TGAppDelegate.h"
#import "TGTelegraph.h"
#import "TGTelegramNetworking.h"
#import "TGInterfaceManager.h"
#import "TGNavigationBar.h"
#import "TGTelegraphDialogListCompanion.h"
#import "TGConversationChangeTitleRequestActor.h"
#import "TGConversationChangePhotoActor.h"
#import "TGHeaderCollectionItem.h"
#import "TGSwitchCollectionItem.h"
#import "TGVariantCollectionItem.h"
#import "TGButtonCollectionItem.h"
#import "TGCommentCollectionItem.h"
#import "TGGroupInfoCollectionItem.h"
#import "TGGroupInfoUserCollectionItem.h"
#import "TGTelegraphUserInfoController.h"
#import "TGGroupInfoSelectContactController.h"
#import "TGBotUserInfoController.h"
#import "TGAlertSoundController.h"
#import "TGRemoteImageView.h"
#import "TGImageUtils.h"
#import "TGAlertView.h"
#import "TGActionSheet.h"
#import "TGModernGalleryController.h"
#import "TGGroupAvatarGalleryItem.h"
#import "TGGroupAvatarGalleryModel.h"
#import "TGOverlayControllerWindow.h"
#import "TGUserInfoVariantCollectionItem.h"
#import "TGUserInfoTextCollectionItem.h"
#import "TGUserInfoUsernameCollectionItem.h"
#import "TGUserInfoButtonCollectionItem.h"
#import "TGSharedMediaController.h"
#import "TGTimerTarget.h"
#import "TGGroupManagementSignals.h"
#import "TGProgressWindow.h"
#import "TGGroupInfoShareLinkController.h"
#import "TGChannelLinkSetupController.h"
#import "TGChannelAboutSetupController.h"
#import "TGChannelManagementSignals.h"
#import "TGChannelMembersController.h"
#import "TGSelectContactController.h"
#import "TGCollectionMultilineInputItem.h"
#import "TGMediaAvatarMenuMixin.h"
static const NSUInteger keepCachedMemberCount = 32;
static const NSUInteger loadMoreMemberCount = 100;
@interface TGChannelGroupInfoController () <TGGroupInfoSelectContactControllerDelegate, TGAlertSoundControllerDelegate, ASWatcher>
{
bool _editing;
int64_t _peerId;
TGConversation *_conversation;
TGCollectionMenuSection *_groupInfoSection;
TGGroupInfoCollectionItem *_groupInfoItem;
TGButtonCollectionItem *_setGroupPhotoItem;
TGCollectionMenuSection *_leaveSection;
TGUserInfoButtonCollectionItem *_leaveItem;
TGCollectionMenuSection *_adminInfoSection;
TGVariantCollectionItem *_infoManagementItem;
TGVariantCollectionItem *_infoBlacklistItem;
TGCollectionMenuSection *_descriptionSection;
TGCollectionMultilineInputItem *_descriptionItem;
TGCollectionMultilineInputItem *_linkItem;
TGCollectionMenuSection *_linkSection;
TGCollectionMenuSection *_deleteChannelSection;
TGCollectionMenuSection *_notificationsAndMediaSection;
TGSwitchCollectionItem *_notificationsItem;
TGVariantCollectionItem *_soundItem;
TGVariantCollectionItem *_sharedMediaItem;
NSMutableDictionary *_groupNotificationSettings;
NSTimer *_muteExpirationTimer;
id<SDisposable> _completeInfoDisposable;
id<SDisposable> _cachedDataDisposable;
id<SDisposable> _cachedMembersDisposable;
NSString *_privateLink;
TGCollectionMenuSection *_usersSection;
TGHeaderCollectionItem *_usersHeaderItem;
TGButtonCollectionItem *_usersAddMemberItem;
NSArray *_users;
NSDictionary *_memberDatas;
SDisposableSet *_kickDisposables;
SPipe *_loadMoreMembersPipe;
bool _canLoadMore;
bool _shouldLoadMore;
TGMediaAvatarMenuMixin *_avatarMixin;
}
@property (nonatomic, strong) ASHandle *actionHandle;
@end
@implementation TGChannelGroupInfoController
- (instancetype)initWithPeerId:(int64_t)peerId
{
self = [super init];
if (self != nil)
{
__weak TGChannelGroupInfoController *weakSelf = self;
_kickDisposables = [[SDisposableSet alloc] init];
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Back") style:UIBarButtonItemStylePlain target:self action:@selector(backPressed)];
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true];
_peerId = peerId;
_groupNotificationSettings = [[NSMutableDictionary alloc] initWithDictionary:@{@"muteUntil": @(0), @"soundId": @(1)}];
TGConversation *conversation = [TGDatabaseInstance() loadConversationWithId:_peerId];
[self setTitleText:TGLocalized(@"GroupInfo.Title")];
_groupInfoItem = [[TGGroupInfoCollectionItem alloc] init];
_groupInfoItem.interfaceHandle = _actionHandle;
_groupInfoItem.isChannel = true;
_setGroupPhotoItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"GroupInfo.SetGroupPhoto") action:@selector(setGroupPhotoPressed)];
_setGroupPhotoItem.titleColor = TGAccentColor();
_setGroupPhotoItem.deselectAutomatically = true;
_groupInfoSection = [[TGCollectionMenuSection alloc] initWithItems:@[]];
_groupInfoSection.insets = UIEdgeInsetsMake(0.0f, 0.0f, 35.0f, 0.0f);
TGHeaderCollectionItem *descriptionHeaderItem = [[TGHeaderCollectionItem alloc] initWithTitle:[TGLocalized(@"Channel.Info.Description") uppercaseString]];
_descriptionItem = [[TGCollectionMultilineInputItem alloc] init];
_descriptionItem.placeholder = TGLocalized(@"Channel.About.Placeholder");
_descriptionItem.editable = false;
_descriptionItem.deselectAutomatically = true;
_descriptionItem.selected = ^{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf aboutPressed];
}
};
_descriptionSection = [[TGCollectionMenuSection alloc] initWithItems:@[descriptionHeaderItem, _descriptionItem]];
_linkItem = [[TGCollectionMultilineInputItem alloc] init];
_linkSection = [[TGCollectionMenuSection alloc] initWithItems:@[_linkItem]];
_leaveItem = [[TGUserInfoButtonCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.LeaveChannel") action:@selector(leavePressed)];
_leaveItem.titleColor = TGDestructiveAccentColor();
_leaveItem.deselectAutomatically = true;
_leaveSection = [[TGCollectionMenuSection alloc] initWithItems:@[_leaveItem]];
TGButtonCollectionItem *deleteChannelItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"ChannelInfo.DeleteChannel") action:@selector(deleteChannelPressed)];
deleteChannelItem.titleColor = TGDestructiveAccentColor();
deleteChannelItem.deselectAutomatically = true;
_deleteChannelSection = [[TGCollectionMenuSection alloc] initWithItems:@[deleteChannelItem]];
_infoManagementItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Info.Management") variant:@"" action:@selector(infoManagementPressed)];
_infoBlacklistItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Info.BlackList") variant:@"" action:@selector(infoBlacklistPressed)];
_adminInfoSection = [[TGCollectionMenuSection alloc] initWithItems:@[_infoManagementItem, _infoBlacklistItem]];
_notificationsItem = [[TGSwitchCollectionItem alloc] initWithTitle:TGLocalized(@"GroupInfo.Notifications") isOn:false];
_notificationsItem.toggled = ^(bool value) {
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf _commitEnableNotifications:value orMuteFor:0];
}
};
_soundItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"GroupInfo.Sound") variant:nil action:@selector(soundPressed)];
_soundItem.deselectAutomatically = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad;
_sharedMediaItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"GroupInfo.SharedMedia") variant:@"" action:@selector(sharedMediaPressed)];
_notificationsAndMediaSection = [[TGCollectionMenuSection alloc] initWithItems:@[_notificationsItem, _sharedMediaItem]];
UIEdgeInsets notificationsAndMediaSectionInsets = _notificationsAndMediaSection.insets;
notificationsAndMediaSectionInsets.bottom = 18.0f;
_notificationsAndMediaSection.insets = notificationsAndMediaSectionInsets;
_usersHeaderItem = [[TGHeaderCollectionItem alloc] initWithTitle:@""];
_usersAddMemberItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"GroupInfo.AddParticipant") action:@selector(addMemberPressed)];
_usersAddMemberItem.icon = [UIImage imageNamed:@"GroupInfoIconAddMember.png"];
_usersAddMemberItem.leftInset = 65.0f;
_usersSection = [[TGCollectionMenuSection alloc] initWithItems:@[_usersHeaderItem, _usersAddMemberItem]];
[self _setConversation:conversation];
[self _updateNotificationItems:false];
int64_t accessHash = _conversation.accessHash;
[ActionStageInstance() dispatchOnStageQueue:^
{
[ActionStageInstance() watchForPaths:@[
[[NSString alloc] initWithFormat:@"/tg/conversation/(%lld)/conversation", _peerId],
@"/tg/userdatachanges",
@"/tg/userpresencechanges",
@"/as/updateRelativeTimestamps",
] watcher:self];
[ActionStageInstance() watchForPath:[NSString stringWithFormat:@"/tg/peerSettings/(%" PRId64 ")", _peerId] watcher:self];
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/peerSettings/(%" PRId64 ",cachedOnly)", _peerId] options:@{@"peerId": @(_peerId), @"accessHash": @(accessHash)} watcher:self];
NSArray *changeTitleActions = [ActionStageInstance() rejoinActionsWithGenericPathNow:@"/tg/conversation/@/changeTitle/@" prefix:[NSString stringWithFormat:@"/tg/conversation/(%" PRId64 ")", _peerId] watcher:self];
NSArray *changeAvatarActions = [ActionStageInstance() rejoinActionsWithGenericPathNow:@"/tg/conversation/@/updateAvatar/@" prefix:[NSString stringWithFormat:@"/tg/conversation/(%" PRId64 ")", _peerId] watcher:self];
NSString *updatingTitle = nil;
if (changeTitleActions.count != 0)
{
NSString *action = [changeTitleActions lastObject];
TGConversationChangeTitleRequestActor *actor = (TGConversationChangeTitleRequestActor *)[ActionStageInstance() executingActorWithPath:action];
if (actor != nil)
updatingTitle = actor.currentTitle;
}
UIImage *updatingAvatar = nil;
bool haveUpdatingAvatar = false;
if (changeAvatarActions.count != 0)
{
NSString *action = [changeAvatarActions lastObject];
TGConversationChangePhotoActor *actor = (TGConversationChangePhotoActor *)[ActionStageInstance() executingActorWithPath:action];
if (actor != nil)
{
updatingAvatar = actor.currentImage;
haveUpdatingAvatar = true;
}
}
if (changeTitleActions.count != 0 || changeAvatarActions.count != 0)
{
TGDispatchOnMainThread(^ {
[_groupInfoItem setUpdatingTitle:updatingTitle];
[_groupInfoItem setUpdatingAvatar:updatingAvatar hasUpdatingAvatar:haveUpdatingAvatar];
[_setGroupPhotoItem setEnabled:!haveUpdatingAvatar];
[self _setConversation:_conversation];
});
}
}];
_completeInfoDisposable = [[TGChannelManagementSignals updateChannelExtendedInfo:_conversation.conversationId accessHash:_conversation.accessHash updateUnread:true] startWithNext:nil];
_cachedDataDisposable = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] deliverOn:[SQueue mainQueue]] startWithNext:^(TGCachedConversationData *cachedData) {
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil && cachedData != nil) {
[strongSelf->_infoManagementItem setVariant:[[NSString alloc] initWithFormat:@"%d", cachedData.managementCount]];
[strongSelf->_infoBlacklistItem setVariant:[[NSString alloc] initWithFormat:@"%d", cachedData.blacklistCount]];
strongSelf->_privateLink = cachedData.privateLink;
[strongSelf->_usersHeaderItem setTitle:[strongSelf titleStringForMemberCount:cachedData.memberCount]];
}
}];
SSignal *updatedMembersSignal = [[[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] deliverOn:[SQueue mainQueue]] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableArray *users = [[NSMutableArray alloc] init];
for (TGCachedConversationMember *member in cachedData.generalMembers) {
TGUser *user = [TGDatabaseInstance() loadUser:member.uid];
if (user != nil) {
[users addObject:user];
}
}
bool updated = false;
if (updatedUsers.count >= users.count) {
for (NSUInteger i = 0; i < users.count; i++) {
TGUser *user1 = users[i];
TGUser *user2 = updatedUsers[i];
if (user1.uid != user2.uid) {
updated = true;
break;
}
}
} else {
updated = true;
}
if (updated) {
return [SSignal single:cachedData];
}
}
return [SSignal single:nil];
}] filter:^bool(id next) {
return next != nil;
}];
SSignal *cachedMembersSignal = [[[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] take:1] then:updatedMembersSignal] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
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, @"count": @(cachedData.memberCount)}];
}];
_loadMoreMembersPipe = [[SPipe alloc] init];
SSignal *loadMoreMembersSignal = [SSignal defer:^SSignal *{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
strongSelf->_canLoadMore = true;
}
return [[[_loadMoreMembersPipe.signalProducer() mapToSignal:^SSignal *(__unused id next) {
return [[SSignal defer:^SSignal *{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
return [[TGChannelManagementSignals channelMembers:conversation.conversationId accessHash:conversation.accessHash offset:strongSelf->_users.count count:loadMoreMemberCount] mapToSignal:^SSignal *(NSDictionary *dict) {
return [[SSignal defer:^SSignal *{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
NSDictionary *memberDatas = dict[@"memberDatas"];
for (TGUser *user in dict[@"users"]) {
if (updatedMemberDatas[@(user.uid)] == nil) {
TGCachedConversationMember *member = memberDatas[@(user.uid)];
if (member != nil) {
updatedMemberDatas[@(user.uid)] = member;
[updatedUsers addObject:user];
}
}
}
return [SSignal single:@{@"users": updatedUsers, @"memberDatas": updatedMemberDatas, @"count": @([dict[@"count"] intValue]), @"canLoadMore": @([memberDatas count] != 0)}];
}
return [SSignal single:@[]];
}] startOn:[SQueue mainQueue]];
}];
}
return [SSignal single:@{}];
}] startOn:[SQueue mainQueue]];
}] startOn:[SQueue mainQueue]] onNext:^(NSDictionary *dict) {
TGDispatchOnMainThread(^{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
strongSelf->_canLoadMore = [dict[@"canLoadMore"] boolValue];
if (strongSelf->_canLoadMore) {
[strongSelf loadMoreIfNeeded];
}
}
});
}];
}];
SSignal *membersSignal = [cachedMembersSignal mapToSignal:^SSignal *(NSDictionary *dict) {
return [[[SSignal single:dict] then:[[TGChannelManagementSignals channelMembers:conversation.conversationId accessHash:conversation.accessHash offset:0 count:keepCachedMemberCount] onNext:^(NSDictionary *dict) {
[TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
NSMutableArray *sortedMemberDatas = [[NSMutableArray alloc] init];
NSDictionary *memberDatas = dict[@"memberDatas"];
for (TGUser *user in dict[@"users"]) {
TGCachedConversationMember *member = memberDatas[@(user.uid)];
if (member != nil) {
[sortedMemberDatas addObject:member];
}
}
return [data updateGeneralMembers:sortedMemberDatas];
}];
}]] then:loadMoreMembersSignal];
}];
_cachedMembersDisposable = [[membersSignal deliverOn:[SQueue mainQueue]] startWithNext:^(NSDictionary *dict) {
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf->_usersHeaderItem setTitle:[strongSelf titleStringForMemberCount:[dict[@"count"] intValue]]];
[strongSelf _setUsers:dict[@"users"] memberDatas:dict[@"memberDatas"]];
}
}];
[self _setupSections:false];
}
return self;
}
- (NSString *)titleStringForMemberCount:(NSUInteger)count {
NSString *title = @"";
if (count == 1)
title = TGLocalized(@"GroupInfo.ParticipantCount_1");
else if (count == 2)
title = TGLocalized(@"GroupInfo.ParticipantCount_2");
else if (count >= 3 && count <= 10)
title = [NSString localizedStringWithFormat:TGLocalized(@"GroupInfo.ParticipantCount_3_10"), [TGStringUtils stringWithLocalizedNumber:count]];
else
title = [NSString localizedStringWithFormat:TGLocalized(@"GroupInfo.ParticipantCount_any"), [TGStringUtils stringWithLocalizedNumber:count]];
return title;
}
- (void)_setupSections:(bool)editing {
while (self.menuSections.sections.count != 0) {
[self.menuSections deleteSection:0];
}
_groupInfoSection.insets = UIEdgeInsetsMake(0.0f, 0.0f, 35.0f, 0.0f);
if (editing) {
if ([self canEditChannel]) {
[_groupInfoSection replaceItems:@[_groupInfoItem, _setGroupPhotoItem]];
} else {
[_groupInfoSection replaceItems:@[_groupInfoItem]];
}
[self.menuSections addSection:_groupInfoSection];
_groupInfoSection.insets = UIEdgeInsetsMake(0.0f, 0.0f, 18.0f, 0.0f);
[self.menuSections addSection:_descriptionSection];
if (_conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRolePublisher) {
[self.menuSections addSection:_adminInfoSection];
}
self.collectionView.backgroundColor = [TGInterfaceAssets listsBackgroundColor];
} else {
[_groupInfoSection replaceItems:@[_groupInfoItem]];
[self.menuSections addSection:_groupInfoSection];
if (_descriptionItem.text.length != 0 || _conversation.username.length != 0) {
_groupInfoSection.insets = UIEdgeInsetsMake(0.0f, 0.0f, 18.0f, 0.0f);
}
if (_descriptionItem.text.length != 0) {
[self.menuSections addSection:_descriptionSection];
}
if (_conversation.username.length != 0) {
[self.menuSections addSection:_linkSection];
}
[self.menuSections addSection:_notificationsAndMediaSection];
/*if (_conversation.kind == TGConversationKindPersistentChannel && _conversation.channelRole != TGChannelRoleCreator) {
[self.menuSections addSection:_leaveSection];
}*/
}
if ([self canInviteToChannel]) {
if ([_usersSection indexOfItem:_usersAddMemberItem] == NSNotFound) {
[_usersSection insertItem:_usersAddMemberItem atIndex:1];
}
} else {
[_usersSection deleteItem:_usersAddMemberItem];
}
[self.menuSections addSection:_usersSection];
if ([self canEditChannel]) {
if (!_editing && ![self.navigationItem.rightBarButtonItem.title isEqualToString:TGLocalized(@"Common.Edit")]) {
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Edit") style:UIBarButtonItemStylePlain target:self action:@selector(editPressed)] animated:false];
}
} else {
if (_editing) {
[self leaveEditingMode:false];
}
[self setRightBarButtonItem:nil];
}
[self.collectionView reloadData];
}
- (void)backPressed
{
[self.navigationController popViewControllerAnimated:true];
}
- (void)dealloc
{
[_actionHandle reset];
[ActionStageInstance() removeWatcher:self];
[_completeInfoDisposable dispose];
[_cachedDataDisposable dispose];
[_kickDisposables dispose];
}
#pragma mark -
- (void)_resetCollectionView
{
[super _resetCollectionView];
self.collectionView.backgroundColor = self.view.backgroundColor;
[self.collectionView setAllowEditingCells:true animated:false];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
#pragma mark -
- (void)editPressed
{
if (!_editing)
{
_editing = true;
[_groupInfoItem setEditing:true animated:false];
[self _setupSections:true];
[self enterEditingMode:false];
[self animateCollectionCrossfade];
}
}
- (void)donePressed
{
if (_editing)
{
_editing = false;
if (!TGStringCompare(_conversation.chatTitle, [_groupInfoItem editingTitle]) && [_groupInfoItem editingTitle] != nil)
[self _commitUpdateTitle:[_groupInfoItem editingTitle]];
[_groupInfoItem setEditing:false animated:false];
[self _setupSections:false];
[self leaveEditingMode:false];
[self animateCollectionCrossfade];
}
[self leaveEditingMode:true];
}
- (void)didEnterEditingMode:(bool)animated
{
[super didEnterEditingMode:animated];
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Done") style:UIBarButtonItemStyleDone target:self action:@selector(donePressed)] animated:true];
}
- (void)didLeaveEditingMode:(bool)animated
{
[super didLeaveEditingMode:animated];
if ([self canEditChannel]) {
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Edit") style:UIBarButtonItemStylePlain target:self action:@selector(editPressed)] animated:animated];
}
}
- (bool)canEditChannel {
return _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRolePublisher;
}
- (bool)canInviteToChannel {
return _conversation.everybodyCanAddMembers || _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRolePublisher;
}
- (bool)canKickMembers {
return [self canInviteToChannel];
}
- (void)setGroupPhotoPressed
{
if (![self canEditChannel])
return;
__weak TGChannelGroupInfoController *weakSelf = self;
_avatarMixin = [[TGMediaAvatarMenuMixin alloc] initWithParentController:self hasDeleteButton:(_conversation.chatPhotoSmall.length != 0)];
_avatarMixin.didFinishWithImage = ^(UIImage *image)
{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf _updateGroupProfileImage:image];
strongSelf->_avatarMixin = nil;
};
_avatarMixin.didFinishWithDelete = ^
{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf _commitDeleteAvatar];
strongSelf->_avatarMixin = nil;
};
_avatarMixin.didDismiss = ^
{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_avatarMixin = nil;
};
[_avatarMixin present];
}
- (void)_updateGroupProfileImage:(UIImage *)image
{
if (image == nil)
return;
if (MIN(image.size.width, image.size.height) < 160.0f)
image = TGScaleImageToPixelSize(image, CGSizeMake(160, 160));
NSData *imageData = UIImageJPEGRepresentation(image, 0.6f);
if (imageData == nil)
return;
TGImageProcessor filter = [TGRemoteImageView imageProcessorForName:@"circle:64x64"];
UIImage *avatarImage = filter(image);
[_groupInfoItem setUpdatingAvatar:avatarImage hasUpdatingAvatar:true];
[_setGroupPhotoItem setEnabled:false];
NSMutableDictionary *uploadOptions = [[NSMutableDictionary alloc] init];
[uploadOptions setObject:imageData forKey:@"imageData"];
[uploadOptions setObject:[NSNumber numberWithLongLong:_conversation.conversationId] forKey:@"conversationId"];
[uploadOptions setObject:avatarImage forKey:@"currentImage"];
uploadOptions[@"accessHash"] = @(_conversation.accessHash);
[ActionStageInstance() dispatchOnStageQueue:^
{
static int actionId = 0;
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%" PRId64 ")/updateAvatar/(updateAvatar%d)", _peerId, actionId] options:uploadOptions watcher:self];
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%" PRId64 ")/updateAvatar/(updateAvatar%d)", _peerId, actionId++] options:uploadOptions watcher:TGTelegraphInstance];
}];
}
- (void)_commitDeleteAvatar
{
[_groupInfoItem setUpdatingAvatar:nil hasUpdatingAvatar:true];
[_setGroupPhotoItem setEnabled:false];
NSMutableDictionary *uploadOptions = [[NSMutableDictionary alloc] init];
[uploadOptions setObject:[NSNumber numberWithLongLong:_conversation.conversationId] forKey:@"conversationId"];
uploadOptions[@"accessHash"] = @(_conversation.accessHash);
[ActionStageInstance() dispatchOnStageQueue:^
{
static int actionId = 0;
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%" PRId64 ")/updateAvatar/(deleteAvatar%d)", _peerId, actionId] options:uploadOptions watcher:self];
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%" PRId64 ")/updateAvatar/(deleteAvatar%d)", _peerId, actionId++] options:uploadOptions watcher:TGTelegraphInstance];
}];
}
- (void)_commitCancelAvatarUpdate
{
[_groupInfoItem setUpdatingAvatar:nil hasUpdatingAvatar:false];
[_setGroupPhotoItem setEnabled:true];
[ActionStageInstance() dispatchOnStageQueue:^
{
NSArray *actors = [ActionStageInstance() executingActorsWithPathPrefix:[NSString stringWithFormat:@"/tg/conversation/(%lld)/updateAvatar/", _peerId]];
for (ASActor *actor in actors)
{
[ActionStageInstance() removeAllWatchersFromPath:actor.path];
}
}];
}
- (void)notificationsPressed
{
NSMutableArray *actions = [[NSMutableArray alloc] init];
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"UserInfo.NotificationsEnable") action:@"enable"]];
NSArray *muteIntervals = @[
@(1 * 60 * 60),
@(8 * 60 * 60),
@(2 * 24 * 60 * 60),
];
for (NSNumber *nMuteInterval in muteIntervals)
{
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:[TGStringUtils stringForMuteInterval:[nMuteInterval intValue]] action:[[NSString alloc] initWithFormat:@"%@", nMuteInterval]]];
}
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"UserInfo.NotificationsDisable") action:@"disable"]];
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]];
[[[TGActionSheet alloc] initWithTitle:nil actions:actions actionBlock:^(TGChannelGroupInfoController *controller, NSString *action)
{
if ([action isEqualToString:@"enable"])
[controller _commitEnableNotifications:true orMuteFor:0];
else if ([action isEqualToString:@"disable"])
[controller _commitEnableNotifications:false orMuteFor:0];
else if (![action isEqualToString:@"cancel"])
{
[controller _commitEnableNotifications:false orMuteFor:[action intValue]];
}
} target:self] showInView:self.view];
}
- (void)_commitEnableNotifications:(bool)enable orMuteFor:(int)muteFor
{
int muteUntil = 0;
if (muteFor == 0)
{
if (enable)
muteUntil = 0;
else
muteUntil = INT_MAX;
}
else
{
muteUntil = (int)([[TGTelegramNetworking instance] approximateRemoteTime] + muteFor);
}
if (muteUntil != [_groupNotificationSettings[@"muteUntil"] intValue])
{
_groupNotificationSettings[@"muteUntil"] = @(muteUntil);
static int actionId = 0;
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/changePeerSettings/(%" PRId64 ")/(userInfoControllerMute%d)", _peerId, actionId++] options:@{@"peerId": @(_peerId), @"accessHash": @(_conversation.accessHash), @"muteUntil": @(muteUntil)} watcher:TGTelegraphInstance];
[self _updateNotificationItems:false];
}
}
- (void)_commitUpdateTitle:(NSString *)title
{
[_groupInfoItem setUpdatingTitle:title];
[ActionStageInstance() dispatchOnStageQueue:^
{
static int actionId = 0;
NSString *path = [[NSString alloc] initWithFormat:@"/tg/conversation/(%" PRId64 ")/changeTitle/(groupInfoController%d)", _conversation.conversationId, actionId++];
NSMutableDictionary *options = [[NSMutableDictionary alloc] initWithDictionary:@{@"conversationId": @(_peerId), @"title": title == nil ? @"" : title}];
options[@"accessHash"] = @(_conversation.accessHash);
[ActionStageInstance() requestActor:path options:options watcher:self];
[ActionStageInstance() requestActor:path options:options watcher:TGTelegraphInstance];
}];
}
- (void)leaveGroupPressed
{
__weak typeof(self) weakSelf = self;
[[[TGActionSheet alloc] initWithTitle:TGLocalized(@"GroupInfo.DeleteAndExitConfirmation") actions:@[
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"GroupInfo.DeleteAndExit") action:@"leave" type:TGActionSheetActionTypeDestructive],
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]
] actionBlock:^(__unused id target, NSString *action)
{
if ([action isEqualToString:@"leave"])
{
TGChannelGroupInfoController *strongSelf = weakSelf;
[strongSelf _commitLeaveGroup];
}
} target:self] showInView:self.view];
}
- (void)_commitLeaveGroup
{
[TGAppDelegateInstance.rootController.dialogListController.dialogListCompanion deleteItem:[[TGConversation alloc] initWithConversationId:_peerId unreadCount:0 serviceUnreadCount:0] animated:false];
if (self.popoverController != nil)
{
dispatch_async(dispatch_get_main_queue(), ^
{
[self.popoverController dismissPopoverAnimated:true];
});
}
else
[self.navigationController popToRootViewControllerAnimated:true];
}
- (void)_changeNotificationSettings:(bool)enableNotifications
{
_groupNotificationSettings[@"muteUntil"] = @(!enableNotifications ? INT_MAX : 0);
static int actionId = 0;
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/changePeerSettings/(%" PRId64 ")/(groupInfoController%d)", _conversation.conversationId, actionId++] options:@{@"peerId": @(_peerId), @"accessHash": @(_conversation.accessHash), @"muteUntil": @(!enableNotifications ? INT_MAX : 0)} watcher:TGTelegraphInstance];
}
- (void)soundPressed
{
TGAlertSoundController *alertSoundController = [[TGAlertSoundController alloc] initWithTitle:TGLocalized(@"GroupInfo.Sound") soundInfoList:[self _soundInfoListForSelectedSoundId:[_groupNotificationSettings[@"soundId"] intValue]]];
alertSoundController.delegate = self;
TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[alertSoundController] navigationBarClass:[TGWhiteNavigationBar class]];
if ([self inPopover])
{
navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
navigationController.presentationStyle = TGNavigationControllerPresentationStyleChildInPopover;
}
[self presentViewController:navigationController animated:true completion:nil];
}
- (void)alertSoundController:(TGAlertSoundController *)__unused alertSoundController didFinishPickingWithSoundInfo:(NSDictionary *)soundInfo
{
if (soundInfo[@"soundId"] != nil && [soundInfo[@"soundId"] intValue] >= 0 && [soundInfo[@"soundId"] intValue] != [_groupNotificationSettings[@"soundId"] intValue])
{
int soundId = [soundInfo[@"soundId"] intValue];
_groupNotificationSettings[@"soundId"] = @(soundId);
[self _updateNotificationItems:false];
static int actionId = 0;
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/changePeerSettings/(%" PRId64 ")/(groupInfoController%d)", _peerId, actionId++] options:@{@"peerId": @(_peerId), @"accessHash": @(_conversation.accessHash), @"soundId": @(soundId)} watcher:TGTelegraphInstance];
}
}
- (NSString *)soundNameFromId:(int)soundId
{
if (soundId == 0 || soundId == 1)
return [TGAppDelegateInstance modernAlertSoundTitles][soundId];
if (soundId >= 2 && soundId <= 9)
return [TGAppDelegateInstance classicAlertSoundTitles][MAX(0, soundId - 2)];
if (soundId >= 100 && soundId <= 111)
return [TGAppDelegateInstance modernAlertSoundTitles][soundId - 100 + 2];
return @"";
}
- (NSArray *)_soundInfoListForSelectedSoundId:(int)selectedSoundId
{
NSMutableArray *infoList = [[NSMutableArray alloc] init];
int defaultSoundId = 1;
[TGDatabaseInstance() loadPeerNotificationSettings:INT_MAX - 2 soundId:&defaultSoundId muteUntil:NULL previewText:NULL messagesMuted:NULL notFound:NULL];
NSString *defaultSoundTitle = [self soundNameFromId:defaultSoundId];
int index = -1;
for (NSString *soundName in [TGAppDelegateInstance modernAlertSoundTitles])
{
index++;
int soundId = 0;
bool isDefault = false;
if (index == 1)
{
soundId = 1;
isDefault = true;
}
else if (index == 0)
soundId = 0;
else
soundId = index + 100 - 2;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[@"title"] = isDefault ? [[NSString alloc] initWithFormat:@"%@ (%@)", soundName, defaultSoundTitle] : soundName;
dict[@"selected"] = @(selectedSoundId == soundId);
dict[@"soundName"] = [[NSString alloc] initWithFormat:@"%d", isDefault ? defaultSoundId : soundId];
dict[@"soundId"] = @(soundId);
dict[@"groupId"] = @(0);
[infoList addObject:dict];
}
index = -1;
for (NSString *soundName in [TGAppDelegateInstance classicAlertSoundTitles])
{
index++;
int soundId = index + 2;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[@"title"] = soundName;
dict[@"selected"] = @(selectedSoundId == soundId);
dict[@"soundName"] = [[NSString alloc] initWithFormat:@"%d", soundId];
dict[@"soundId"] = @(soundId);
dict[@"groupId"] = @(1);
[infoList addObject:dict];
}
return infoList;
}
#pragma mark -
- (void)_updateNotificationItems:(bool)__unused animated
{
[_muteExpirationTimer invalidate];
_muteExpirationTimer = nil;
int muteUntil = [_groupNotificationSettings[@"muteUntil"] intValue];
bool enabled = false;
if (muteUntil <= [[TGTelegramNetworking instance] approximateRemoteTime]) {
enabled = true;
}
else
{
int muteExpiration = muteUntil - (int)[[TGTelegramNetworking instance] approximateRemoteTime];
if (muteExpiration >= 7 * 24 * 60 * 60) {
} else {
_muteExpirationTimer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(updateMuteExpiration) interval:2.0 repeat:true];
}
}
_notificationsItem.isOn = enabled;
int groupSoundId = [[_groupNotificationSettings objectForKey:@"soundId"] intValue];
_soundItem.variant = [self soundNameFromId:groupSoundId];
}
- (void)updateMuteExpiration
{
int muteUntil = [_groupNotificationSettings[@"muteUntil"] intValue];
bool enabled = false;
if (muteUntil <= [[TGTelegramNetworking instance] approximateRemoteTime]) {
enabled = true;
} else {
enabled = false;
}
if (_notificationsItem.isOn != enabled) {
_notificationsItem.isOn = enabled;
}
}
- (void)_setConversation:(TGConversation *)conversation
{
TGDispatchOnMainThread(^
{
bool reloadData = false;
if (_conversation.channelRole != conversation.channelRole) {
reloadData = true;
}
_conversation = conversation;
if (!TGStringCompare(_conversation.about, _descriptionItem.text)) {
_descriptionItem.text = _conversation.about;
reloadData = true;
}
NSString *linkText = @"";
if (_conversation.username.length != 0) {
linkText = [@"https://telegram.me/" stringByAppendingString:_conversation.username];
}
if (!TGStringCompare(linkText, _linkItem.text)) {
_linkItem.text = linkText;
if (!_editing) {
reloadData = true;
}
}
[_groupInfoItem setConversation:_conversation];
if (reloadData) {
[self _setupSections:_editing];
}
});
}
- (void)_setUsers:(NSArray *)filteredUsers memberDatas:(NSDictionary *)memberDatas {
_users = filteredUsers;
_memberDatas = memberDatas;
NSInteger headButtonCount = 0;
for (NSInteger i = 0; i < (NSInteger)_usersSection.items.count; i++) {
id item = _usersSection.items[i];
if ([item isKindOfClass:[TGGroupInfoUserCollectionItem class]]) {
break;
} else {
headButtonCount++;
}
}
NSMutableSet *currentUserIds = [[NSMutableSet alloc] init];
for (id item in _usersSection.items) {
if ([item isKindOfClass:[TGGroupInfoUserCollectionItem class]]) {
[currentUserIds addObject:@(((TGGroupInfoUserCollectionItem *)item).user.uid)];
}
}
NSMutableSet *updatedUserIds = [[NSMutableSet alloc] init];
for (TGUser *user in filteredUsers) {
[updatedUserIds addObject:@(user.uid)];
}
if ([currentUserIds isEqualToSet:updatedUserIds]) {
NSArray *sortedUsers = filteredUsers;//[self sortedUsers:filteredUsers chatAdminUids:_referenceChatAdminUids];
NSUInteger sectionIndex = [self indexForSection:_usersSection];
NSInteger index = -1 + headButtonCount;
for (TGUser *user in sortedUsers) {
index++;
for (NSInteger currentIndex = headButtonCount; currentIndex < (NSInteger)_usersSection.items.count; currentIndex++) {
TGGroupInfoUserCollectionItem *userItem = _usersSection.items[currentIndex];
if (userItem.user.uid == user.uid) {
if (currentIndex != index) {
[_usersSection deleteItemAtIndex:currentIndex];
[_usersSection insertItem:userItem atIndex:index];
[UIView performWithoutAnimation:^{
[self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:currentIndex inSection:sectionIndex] toIndexPath:[NSIndexPath indexPathForItem:index inSection:sectionIndex]];
}];
}
break;
}
}
}
[self updateItemPositions];
} else {
while ((NSInteger)_usersSection.items.count != headButtonCount) {
[_usersSection deleteItemAtIndex:_usersSection.items.count - 1];
}
for (TGUser *user in filteredUsers) {
TGGroupInfoUserCollectionItem *userItem = [[TGGroupInfoUserCollectionItem alloc] init];
userItem.interfaceHandle = _actionHandle;
userItem.selectable = user.uid != TGTelegraphInstance.clientUserId;
[userItem setCanEdit:[self canKickMembers] && user.uid != TGTelegraphInstance.clientUserId];
[userItem setUser:user];
[_usersSection addItem:userItem];
}
[self.collectionView reloadData];
}
}
- (void)_updateRelativeTimestamps
{
}
#pragma mark -
- (void)actionStageActionRequested:(NSString *)action options:(id)options
{
if ([action isEqualToString:@"openUser"])
{
int32_t uid = [options[@"uid"] int32Value];
if (uid != 0)
{
TGUser *user = [TGDatabaseInstance() loadUser:uid];
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];
}
}
}
else if ([action isEqualToString:@"deleteUser"])
{
int32_t uid = [options[@"uid"] int32Value];
if (uid != 0)
[self _commitDeleteParticipant:uid];
}
else if ([action isEqualToString:@"editedTitleChanged"])
{
NSString *title = options[@"title"];
if (_editing)
self.navigationItem.rightBarButtonItem.enabled = title.length != 0;
}
else if ([action isEqualToString:@"openAvatar"])
{
if (_conversation.chatPhotoSmall.length == 0)
{
if (_setGroupPhotoItem.enabled)
[self setGroupPhotoPressed];
}
else
{
TGRemoteImageView *avatarView = [_groupInfoItem avatarView];
if (avatarView != nil && avatarView.image != nil)
{
TGModernGalleryController *modernGallery = [[TGModernGalleryController alloc] init];
modernGallery.model = [[TGGroupAvatarGalleryModel alloc] initWithMessageId:0 legacyThumbnailUrl:_conversation.chatPhotoSmall legacyUrl:_conversation.chatPhotoBig imageSize:CGSizeMake(640.0f, 640.0f)];
__weak TGChannelGroupInfoController *weakSelf = self;
modernGallery.itemFocused = ^(id<TGModernGalleryItem> item)
{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil)
{
if ([item isKindOfClass:[TGGroupAvatarGalleryItem class]])
{
((UIView *)strongSelf->_groupInfoItem.avatarView).hidden = true;
}
}
};
modernGallery.beginTransitionIn = ^UIView *(id<TGModernGalleryItem> item, __unused TGModernGalleryItemView *itemView)
{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil)
{
if ([item isKindOfClass:[TGGroupAvatarGalleryItem class]])
{
return strongSelf->_groupInfoItem.avatarView;
}
}
return nil;
};
modernGallery.beginTransitionOut = ^UIView *(id<TGModernGalleryItem> item, __unused TGModernGalleryItemView *itemView)
{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil)
{
if ([item isKindOfClass:[TGGroupAvatarGalleryItem class]])
{
return strongSelf->_groupInfoItem.avatarView;
}
}
return nil;
};
modernGallery.completedTransitionOut = ^
{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil)
{
((UIView *)strongSelf->_groupInfoItem.avatarView).hidden = false;
}
};
TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithParentController:self contentController:modernGallery];
controllerWindow.hidden = false;
}
}
}
else if ([action isEqualToString:@"showUpdatingAvatarOptions"])
{
[[[TGActionSheet alloc] initWithTitle:nil actions:@[
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"GroupInfo.SetGroupPhotoStop") action:@"stop" type:TGActionSheetActionTypeDestructive],
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]
] actionBlock:^(TGChannelGroupInfoController *controller, NSString *action)
{
if ([action isEqualToString:@"stop"])
[controller _commitCancelAvatarUpdate];
} target:self] showInView:self.view];
}
}
- (void)actionStageResourceDispatched:(NSString *)path resource:(id)resource arguments:(id)__unused arguments
{
if ([path isEqualToString:[[NSString alloc] initWithFormat:@"/tg/conversation/(%lld)/conversation", _peerId]])
{
TGConversation *conversation = ((SGraphObjectNode *)resource).object;
if (conversation != nil) {
[self _setConversation:conversation];
}
}
else if ([path hasPrefix:@"/tg/peerSettings/"])
{
[self actorCompleted:ASStatusSuccess path:path result:resource];
}
else if ([path isEqualToString:@"/as/updateRelativeTimestamps"])
{
TGDispatchOnMainThread(^
{
[self _updateRelativeTimestamps];
});
}
else if ([path isEqualToString:@"/tg/userdatachanges"] || [path isEqualToString:@"/tg/userpresencechanges"])
{
//NSArray *users = ((SGraphObjectNode *)resource).object;
TGDispatchOnMainThread(^
{
//[self _updateUsers:users];
});
}
}
- (void)actorCompleted:(int)status path:(NSString *)path result:(id)result
{
if ([path hasPrefix:@"/tg/peerSettings/"])
{
if (status == ASStatusSuccess)
{
NSDictionary *notificationSettings = ((SGraphObjectNode *)result).object;
TGDispatchOnMainThread(^
{
_groupNotificationSettings = [notificationSettings mutableCopy];
[self _updateNotificationItems:false];
});
}
}
else if ([path hasPrefix:[[NSString alloc] initWithFormat:@"/tg/conversation/(%" PRId64 ")/changeTitle/", _conversation.conversationId]])
{
TGDispatchOnMainThread(^
{
[_groupInfoItem setUpdatingTitle:nil];
if (status == ASStatusSuccess)
{
TGConversation *resultConversation = ((SGraphObjectNode *)result).object;
TGConversation *updatedConversation = [_conversation copy];
updatedConversation.chatTitle = resultConversation.chatTitle;
_conversation = updatedConversation;
[_groupInfoItem setConversation:_conversation];
}
});
}
else if ([path hasPrefix:[[NSString alloc] initWithFormat:@"/tg/conversation/(%" PRId64 ")/updateAvatar/", _conversation.conversationId]])
{
TGDispatchOnMainThread(^
{
if (status == ASStatusSuccess)
{
TGConversation *resultConversation = ((SGraphObjectNode *)result).object;
TGConversation *updatedConversation = [_conversation copy];
updatedConversation.chatPhotoSmall = resultConversation.chatPhotoSmall;
updatedConversation.chatPhotoMedium = resultConversation.chatPhotoMedium;
updatedConversation.chatPhotoBig = resultConversation.chatPhotoBig;
_conversation = updatedConversation;
[_groupInfoItem copyUpdatingAvatarToCacheWithUri:_conversation.chatPhotoSmall];
[_groupInfoItem setConversation:_conversation];
[_groupInfoItem setUpdatingAvatar:nil hasUpdatingAvatar:false];
[_setGroupPhotoItem setEnabled:true];
}
else
{
[_groupInfoItem setUpdatingAvatar:nil hasUpdatingAvatar:false];
[_setGroupPhotoItem setEnabled:true];
}
});
}
}
- (void)aboutPressed {
if ([self canInviteToChannel]) {
TGChannelAboutSetupController *aboutController = [[TGChannelAboutSetupController alloc] initWithConversation:_conversation];
TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[aboutController]];
[self presentViewController:navigationController animated:true completion:nil];
}
}
- (void)linkPressed {
TGChannelLinkSetupController *linkController = [[TGChannelLinkSetupController alloc] initWithConversation:_conversation];
TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[linkController]];
[self presentViewController:navigationController animated:true completion:nil];
}
- (void)sharePressed {
if (_conversation.username.length != 0) {
NSArray *dataToShare = @[[NSURL URLWithString:[@"https://telegram.me/" stringByAppendingString:_conversation.username]]];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:nil];
} else {
__weak TGChannelGroupInfoController *weakSelf = self;
[[[TGAlertView alloc] initWithTitle:TGLocalized(@"Channel.ShareNoLink") message:nil cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:^(__unused bool okButtonPressed) {
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf linkPressed];
}
}] show];
}
}
- (void)leavePressed {
__weak typeof(self) weakSelf = self;
[[[TGActionSheet alloc] initWithTitle:nil actions:@[
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"ChannelInfo.ConfirmLeave") action:@"leave" type:TGActionSheetActionTypeDestructive],
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]
] actionBlock:^(__unused id target, NSString *action)
{
if ([action isEqualToString:@"leave"])
{
TGChannelGroupInfoController *strongSelf = weakSelf;
[strongSelf _commitLeaveChannel];
}
} target:self] showInView:self.view];
}
- (void)_commitLeaveChannel
{
[TGAppDelegateInstance.rootController.dialogListController.dialogListCompanion deleteItem:[[TGConversation alloc] initWithConversationId:_peerId unreadCount:0 serviceUnreadCount:0] animated:false];
if (self.popoverController != nil)
{
dispatch_async(dispatch_get_main_queue(), ^
{
[self.popoverController dismissPopoverAnimated:true];
});
}
else
[self.navigationController popToRootViewControllerAnimated:true];
}
- (void)_commitDeleteChannel
{
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
[progressWindow show:true];
[[[[TGChannelManagementSignals deleteChannel:_conversation.conversationId accessHash:_conversation.accessHash] deliverOn:[SQueue mainQueue]] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] startWithNext:nil completed:^{
[TGAppDelegateInstance.rootController.dialogListController.dialogListCompanion deleteItem:[[TGConversation alloc] initWithConversationId:_peerId unreadCount:0 serviceUnreadCount:0] animated:false];
if (self.popoverController != nil)
{
dispatch_async(dispatch_get_main_queue(), ^
{
[self.popoverController dismissPopoverAnimated:true];
});
}
else
[self.navigationController popToRootViewControllerAnimated:true];
}];
}
- (void)infoManagementPressed {
[self.navigationController pushViewController:[[TGChannelMembersController alloc] initWithConversation:_conversation mode:TGChannelMembersModeAdmins] animated:true];
}
- (void)infoBlacklistPressed {
[self.navigationController pushViewController:[[TGChannelMembersController alloc] initWithConversation:_conversation mode:TGChannelMembersModeBlacklist] animated:true];
}
- (void)sharedMediaPressed {
TGSharedMediaController *controller = [[TGSharedMediaController alloc] initWithPeerId:_peerId accessHash:_conversation.accessHash important:false];
controller.channelAllowDelete = _conversation.channelRole == TGChannelRoleCreator;
[self.navigationController pushViewController:controller animated:true];
}
- (void)deleteChannelPressed {
__weak typeof(self) weakSelf = self;
[[[TGActionSheet alloc] initWithTitle:TGLocalized(@"ChannelInfo.DeleteChannelConfirmation") actions:@[
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"ChannelInfo.DeleteChannel") action:@"leave" type:TGActionSheetActionTypeDestructive],
[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]
] actionBlock:^(__unused id target, NSString *action)
{
if ([action isEqualToString:@"leave"])
{
TGChannelGroupInfoController *strongSelf = weakSelf;
[strongSelf _commitDeleteChannel];
}
} target:self] showInView:self.view];
}
- (void)addMemberPressed {
TGSelectContactController *selectController = [[TGSelectContactController alloc] initWithCreateGroup:false createEncrypted:false createBroadcast:false createChannel:false inviteToChannel:true showLink:_conversation.channelRole == TGChannelRoleCreator];
selectController.composePlaceholder = TGLocalized(@"Compose.GroupTokenListPlaceholder");
selectController.channelConversation = _conversation;
selectController.deselectAutomatically = true;
__weak TGChannelGroupInfoController *weakSelf = self;
selectController.onCreateLink = ^{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
if ([strongSelf.presentedViewController isKindOfClass:[UINavigationController class]])
{
TGGroupInfoShareLinkController *controller = [[TGGroupInfoShareLinkController alloc] initWithPeerId:strongSelf->_peerId accessHash:strongSelf->_conversation.accessHash currentLink:strongSelf->_privateLink];
[(UINavigationController *)strongSelf.presentedViewController pushViewController:controller animated:true];
}
}
};
NSMutableArray *existingUsers = [[NSMutableArray alloc] init];
for (TGUser *user in _users) {
[existingUsers addObject:@(user.uid)];
}
selectController.disabledUsers = existingUsers;
selectController.onChannelMembersInvited = ^(NSArray *users) {
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
bool hasBots = false;
for (TGUser *user in users) {
if (updatedMemberDatas[@(user.uid)] != nil) {
continue;
}
if (user.kind == TGUserKindBot || user.kind == TGUserKindSmartBot) {
hasBots = true;
}
updatedMemberDatas[@(user.uid)] = [[TGCachedConversationMember alloc] initWithUid:user.uid role:TGChannelRoleMember timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
[updatedUsers insertObject:user atIndex:0];
}
[strongSelf _setUsers:updatedUsers memberDatas:updatedMemberDatas];
if (hasBots) {
SMetaDisposable *metaDisposable = [[SMetaDisposable alloc] init];
__weak SMetaDisposable *weakMetaDisposable = metaDisposable;
id<SDisposable> disposable = [[TGChannelManagementSignals updateChannelExtendedInfo:strongSelf->_peerId accessHash:strongSelf->_conversation.accessHash updateUnread:false] startWithNext:nil error:^(__unused id error) {
__strong SMetaDisposable *strongMetaDisposable = weakMetaDisposable;
if (strongMetaDisposable != nil) {
[TGTelegraphInstance.disposeOnLogout remove:strongMetaDisposable];
}
} completed:^{
__strong SMetaDisposable *strongMetaDisposable = weakMetaDisposable;
if (strongMetaDisposable != nil) {
[TGTelegraphInstance.disposeOnLogout remove:strongMetaDisposable];
}
}];
[metaDisposable setDisposable:disposable];
[TGTelegraphInstance.disposeOnLogout add:metaDisposable];
}
}
};
TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[selectController]];
[self presentViewController:navigationController animated:true completion:nil];
}
- (void)_commitDeleteParticipant:(int32_t)uid {
for (id item in _usersSection.items)
{
if ([item isKindOfClass:[TGGroupInfoUserCollectionItem class]] && ((TGGroupInfoUserCollectionItem *)item).user.uid == uid)
{
[(TGGroupInfoUserCollectionItem *)item setDisabled:true];
SMetaDisposable *disposable = [[SMetaDisposable alloc] init];
[_kickDisposables add:disposable];
__weak SMetaDisposable *weakDisposable = disposable;
SSignal *signal = [[TGChannelManagementSignals channelChangeMemberKicked:_conversation.conversationId accessHash:_conversation.accessHash user:((TGGroupInfoUserCollectionItem *)item).user kicked:true] onCompletion:^{
[TGDatabaseInstance() updateChannelCachedData:_conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
if (data == nil) {
data = [[TGCachedConversationData alloc] init];
}
return [data blacklistMember:((TGGroupInfoUserCollectionItem *)item).user.uid timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
}];
}];
__weak TGChannelGroupInfoController *weakSelf = self;
[disposable setDisposable:[[[signal deliverOn:[SQueue mainQueue]] onDispose:^{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
__strong SMetaDisposable *strongDisposable = weakDisposable;
if (strongDisposable != nil) {
[strongSelf->_kickDisposables remove:strongDisposable];
}
}
}] startWithNext:nil error:^(__unused id error) {
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
for (id item in strongSelf->_usersSection.items) {
if ([item isKindOfClass:[TGGroupInfoUserCollectionItem class]] && ((TGGroupInfoUserCollectionItem *)item).user.uid == uid)
{
[(TGGroupInfoUserCollectionItem *)item setDisabled:false];
}
}
}
} completed:^{
__strong TGChannelGroupInfoController *strongSelf = weakSelf;
if (strongSelf != nil) {
NSUInteger index = 0;
for (TGUser *user in strongSelf->_users) {
if (user.uid == uid) {
NSMutableArray *users = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
[users removeObjectAtIndex:index];
NSMutableDictionary *memberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
[memberDatas removeObjectForKey:@(uid)];
strongSelf->_users = users;
strongSelf->_memberDatas = memberDatas;
NSUInteger itemIndex = 0;
for (id item in strongSelf->_usersSection.items) {
if ([item isKindOfClass:[TGGroupInfoUserCollectionItem class]] && ((TGGroupInfoUserCollectionItem *)item).user.uid == uid)
{
NSUInteger sectionIndex = [strongSelf indexForSection:strongSelf->_usersSection];
if (sectionIndex != NSNotFound) {
[strongSelf.menuSections beginRecordingChanges];
[strongSelf.menuSections deleteItemFromSection:sectionIndex atIndex:itemIndex];
[strongSelf.menuSections commitRecordedChanges:strongSelf.collectionView];
}
break;
}
itemIndex++;
}
break;
}
index++;
}
}
}]];
break;
}
}
}
- (void)loadMore {
if (_canLoadMore) {
_shouldLoadMore = false;
_canLoadMore = false;
_loadMoreMembersPipe.sink(@true);
} else {
_shouldLoadMore = true;
}
}
- (void)loadMoreIfNeeded {
if (_shouldLoadMore) {
_shouldLoadMore = false;
if (_canLoadMore) {
_canLoadMore = false;
_loadMoreMembersPipe.sink(@true);
}
}
}
@end