1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-11 08:59:48 +01:00
Telegram/Telegraph/TGTelegraphDialogListCompanion.mm

1594 lines
64 KiB
Plaintext
Raw Normal View History

2014-07-10 16:11:09 +02:00
#import "TGTelegraphDialogListCompanion.h"
#import "TGImageUtils.h"
#import "TGAppDelegate.h"
#import "TGModernConversationController.h"
#import "TGGenericModernConversationCompanion.h"
#import "TGDialogListController.h"
#import "SGraphObjectNode.h"
#import "SGraphListNode.h"
#import "TGDatabase.h"
#import "TGInterfaceManager.h"
#import "TGInterfaceAssets.h"
#import "TGSelectContactController.h"
#import "TGTelegraph.h"
#import "TGForwardTargetController.h"
#import "TGTelegraphConversationMessageAssetsSource.h"
#import "TGModernConversationCompanion.h"
2015-10-01 18:19:52 +02:00
#import "TGBroadcastModernConversationCompanion.h"
#import "TGStringUtils.h"
#import "TGProgressWindow.h"
2014-07-10 16:11:09 +02:00
#include <map>
#include <set>
#import <libkern/OSAtomic.h>
2015-10-01 18:19:52 +02:00
#import "TGAlertView.h"
#import "TGChannelManagementSignals.h"
#import "TGCreateGroupController.h"
#import "TGPeerIdAdapter.h"
2014-07-10 16:11:09 +02:00
typedef enum {
TGDialogListStateNormal = 0,
TGDialogListStateConnecting = 1,
TGDialogListStateUpdating = 2,
TGDialogListStateWaitingForNetwork = 3
} TGDialogListState;
@interface TGTelegraphDialogListCompanion ()
{
volatile int32_t _conversationsUpdateTaskId;
2015-10-01 18:19:52 +02:00
TGProgressWindow *_progressWindow;
SMetaDisposable *_channelsDisposable;
bool _canLoadMore;
2014-07-10 16:11:09 +02:00
}
@property (nonatomic, strong) NSMutableArray *conversationList;
@property (nonatomic, strong) NSString *searchString;
@property (nonatomic) TGDialogListState state;
@end
@implementation TGTelegraphDialogListCompanion
- (id)init
{
self = [super init];
if (self != nil)
{
_conversationList = [[NSMutableArray alloc] init];
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:false];
2015-10-01 18:19:52 +02:00
self.showSecretInForwardMode = true;
2014-07-10 16:11:09 +02:00
self.showListEditingControl = true;
[self resetWatchedNodePaths];
2015-10-01 18:19:52 +02:00
_channelsDisposable = [[SMetaDisposable alloc] init];
2014-07-10 16:11:09 +02:00
}
return self;
}
- (void)dealloc
{
[_actionHandle reset];
[ActionStageInstance() removeWatcher:self];
2015-10-01 18:19:52 +02:00
[_channelsDisposable dispose];
TGProgressWindow *progressWindow = _progressWindow;
TGDispatchOnMainThread(^
{
[progressWindow dismiss:false];
});
2014-07-10 16:11:09 +02:00
}
- (id<TGDialogListCellAssetsSource>)dialogListCellAssetsSource
{
return [TGInterfaceAssets instance];
}
- (void)dialogListReady
{
[[TGInterfaceManager instance] preload];
}
- (void)resetWatchedNodePaths
{
[ActionStageInstance() dispatchOnStageQueue:^
{
[ActionStageInstance() removeWatcher:self];
[ActionStageInstance() watchForPath:@"/tg/conversations" watcher:self];
2015-10-01 18:19:52 +02:00
[ActionStageInstance() watchForPath:@"/tg/broadcastConversations" watcher:self];
[ActionStageInstance() watchForPath:@"/tg/channelListSyncrhonized" watcher:self];
2014-07-10 16:11:09 +02:00
[ActionStageInstance() watchForGenericPath:@"/tg/dialoglist/@" watcher:self];
[ActionStageInstance() watchForPath:@"/tg/userdatachanges" watcher:self];
[ActionStageInstance() watchForPath:@"/tg/unreadCount" watcher:self];
[ActionStageInstance() watchForPath:@"/tg/conversation/*/typing" watcher:self];
[ActionStageInstance() watchForPath:@"/tg/contactlist" watcher:self];
2015-10-01 18:19:52 +02:00
[ActionStageInstance() watchForPath:@"/databasePasswordChanged" watcher:self];
2014-07-10 16:11:09 +02:00
[ActionStageInstance() watchForGenericPath:@"/tg/peerSettings/@" watcher:self];
[ActionStageInstance() watchForPath:@"/tg/service/synchronizationstate" watcher:self];
[ActionStageInstance() requestActor:@"/tg/service/synchronizationstate" options:nil watcher:self];
int unreadCount = [TGDatabaseInstance() databaseState].unreadCount;
2015-10-01 18:19:52 +02:00
[self actionStageResourceDispatched:@"/tg/unreadCount" resource:[[SGraphObjectNode alloc] initWithObject:[NSNumber numberWithInt:unreadCount]] arguments:@{@"previous": @true}];
2014-07-10 16:11:09 +02:00
}];
}
- (void)clearData
{
[ActionStageInstance() dispatchOnStageQueue:^
{
2015-10-01 18:19:52 +02:00
[_channelsDisposable setDisposable:nil];
2014-07-10 16:11:09 +02:00
[_conversationList removeAllObjects];
[self resetWatchedNodePaths];
2015-10-01 18:19:52 +02:00
_canLoadMore = false;
2014-07-10 16:11:09 +02:00
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *controller = self.dialogListController;
if (controller != nil)
{
controller.canLoadMore = false;
[controller dialogListFullyReloaded:[[NSArray alloc] init]];
[controller resetState];
}
});
}];
}
2016-02-25 01:03:51 +01:00
- (void)composeMessageAndOpenSearch:(bool)openSearch
2014-07-10 16:11:09 +02:00
{
2015-10-01 18:19:52 +02:00
if ([TGAppDelegateInstance isDisplayingPasscodeWindow])
return;
2014-07-10 16:11:09 +02:00
TGDialogListController *controller = self.dialogListController;
[controller selectConversationWithId:0];
2016-02-25 01:03:51 +01:00
TGSelectContactController *selectController = [[TGSelectContactController alloc] initWithCreateGroup:false createEncrypted:false createBroadcast:false createChannel:false inviteToChannel:false showLink:false];
selectController.shouldOpenSearch = openSearch;
2015-10-01 18:19:52 +02:00
[TGAppDelegateInstance.rootController pushContentController:selectController];
2014-07-10 16:11:09 +02:00
}
- (void)navigateToBroadcastLists
{
2016-02-25 01:03:51 +01:00
TGCreateGroupController *controller = [[TGCreateGroupController alloc] initWithCreateChannel:true createChannelGroup:false];
2015-10-01 18:19:52 +02:00
[TGAppDelegateInstance.rootController pushContentController:controller];
2014-07-10 16:11:09 +02:00
}
- (void)navigateToNewGroup
{
2015-10-01 18:19:52 +02:00
__autoreleasing NSString *disabledMessage = nil;
if (![TGApplicationFeatures isGroupCreationEnabled:&disabledMessage])
{
[[[TGAlertView alloc] initWithTitle:TGLocalized(@"FeatureDisabled.Oops") message:disabledMessage cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:nil] show];
return;
}
2014-07-10 16:11:09 +02:00
TGDialogListController *controller = self.dialogListController;
[controller selectConversationWithId:0];
2016-02-25 01:03:51 +01:00
TGSelectContactController *selectController = [[TGSelectContactController alloc] initWithCreateGroup:true createEncrypted:false createBroadcast:false createChannel:false inviteToChannel:false showLink:false];
2015-10-01 18:19:52 +02:00
[TGAppDelegateInstance.rootController pushContentController:selectController];
2014-07-10 16:11:09 +02:00
}
- (void)conversationSelected:(TGConversation *)conversation
{
2015-10-01 18:19:52 +02:00
if (self.forwardMode || self.privacyMode)
2014-07-10 16:11:09 +02:00
{
[_conversatioSelectedWatcher requestAction:@"conversationSelected" options:[[NSDictionary alloc] initWithObjectsAndKeys:conversation, @"conversation", nil]];
}
else
{
2015-10-01 18:19:52 +02:00
if (conversation.isBroadcast)
{
TGBroadcastModernConversationCompanion *broadcastCompanion = [[TGBroadcastModernConversationCompanion alloc] initWithConversationId:conversation.conversationId conversation:conversation];
TGModernConversationController *conversationController = [[TGModernConversationController alloc] init];
conversationController.companion = broadcastCompanion;
[broadcastCompanion bindController:conversationController];
[TGAppDelegateInstance.rootController replaceContentController:conversationController];
}
else
{
int64_t conversationId = conversation.conversationId;
if (TGPeerIdIsChannel(conversationId) && conversation.kind == TGConversationKindTemporaryChannel) {
TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
[progressWindow showWithDelay:0.1];
[[[[TGChannelManagementSignals preloadedChannel:conversationId] deliverOn:[SQueue mainQueue]] onDispose:^{
TGDispatchOnMainThread(^{
[progressWindow dismiss:true];
});
}] startWithNext:nil completed:^{
[[TGInterfaceManager instance] navigateToConversationWithId:conversationId conversation:conversation];
}];
} else {
[[TGInterfaceManager instance] navigateToConversationWithId:conversationId conversation:conversation];
}
}
2014-07-10 16:11:09 +02:00
}
}
- (void)searchResultSelectedConversation:(TGConversation *)conversation
{
[self conversationSelected:conversation];
}
- (void)searchResultSelectedConversation:(TGConversation *)conversation atMessageId:(int)messageId
{
2015-10-01 18:19:52 +02:00
if (!self.forwardMode && !self.privacyMode)
2014-07-10 16:11:09 +02:00
{
2015-10-01 18:19:52 +02:00
if ([TGDatabaseInstance() loadMessageWithMid:messageId peerId:conversation.conversationId] != nil)
{
int64_t conversationId = conversation.conversationId;
[[TGInterfaceManager instance] navigateToConversationWithId:conversationId conversation:conversation performActions:nil atMessage:@{@"mid": @(messageId)} clearStack:true openKeyboard:false animated:true];
}
else
{
_progressWindow = [[TGProgressWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[_progressWindow show:true];
2016-02-25 01:03:51 +01:00
[ActionStageInstance() requestActor:[[NSString alloc] initWithFormat:@"/tg/loadConversationAndMessageForSearch/(%" PRId64 ", %" PRId32 ")", conversation.conversationId, messageId] options:@{@"peerId": @(conversation.conversationId), @"accessHash": @(conversation.accessHash), @"messageId": @(messageId)} flags:0 watcher:self];
2015-10-01 18:19:52 +02:00
}
2014-07-10 16:11:09 +02:00
}
}
- (void)searchResultSelectedMessage:(TGMessage *)__unused message
{
}
- (bool)shouldDisplayEmptyListPlaceholder
{
return TGTelegraphInstance.clientUserId != 0;
}
- (void)wakeUp
{
}
- (void)resetLocalization
{
}
2015-10-01 18:19:52 +02:00
- (int64_t)openedConversationId
{
UIViewController *topViewController = [TGAppDelegateInstance.rootController.viewControllers lastObject];
if ([topViewController isKindOfClass:[TGModernConversationController class]])
{
return ((TGGenericModernConversationCompanion *)((TGModernConversationController *)(topViewController)).companion).conversationId;
}
return 0;
}
2014-07-10 16:11:09 +02:00
- (bool)isConversationOpened:(int64_t)conversationId
{
2015-10-01 18:19:52 +02:00
UIViewController *topViewController = [TGAppDelegateInstance.rootController.viewControllers lastObject];
if ([topViewController isKindOfClass:[TGModernConversationController class]])
2014-07-10 16:11:09 +02:00
{
2015-10-01 18:19:52 +02:00
return ((TGGenericModernConversationCompanion *)((TGModernConversationController *)(topViewController)).companion).conversationId == conversationId;
2014-07-10 16:11:09 +02:00
}
return false;
}
- (void)deleteItem:(TGConversation *)conversation animated:(bool)animated
{
TGDispatchOnMainThread(^
{
2015-10-01 18:19:52 +02:00
if ([self isConversationOpened:conversation.conversationId]) {
[TGAppDelegateInstance.rootController clearContentControllers];
2014-07-10 16:11:09 +02:00
}
});
int64_t conversationId = conversation.conversationId;
[ActionStageInstance() dispatchOnStageQueue:^
{
2015-10-01 18:19:52 +02:00
bool found = false;
2014-07-10 16:11:09 +02:00
for (int i = 0; i < (int)self.conversationList.count; i++)
{
TGConversation *conversation = [self.conversationList objectAtIndex:i];
if (conversation.conversationId == conversationId)
{
2015-10-01 18:19:52 +02:00
found = true;
2014-07-10 16:11:09 +02:00
[self.conversationList removeObjectAtIndex:i];
NSNumber *removedIndex = [[NSNumber alloc] initWithInt:i];
2015-10-01 18:19:52 +02:00
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%lld)/delete", conversationId] options:@{@"conversationId": @(conversationId), @"block": @true} watcher:self];
2014-07-10 16:11:09 +02:00
dispatch_async(dispatch_get_main_queue(), ^
{
if (!animated)
[UIView setAnimationsEnabled:false];
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController dialogListItemsChanged:nil insertedItems:nil updatedIndices:nil updatedItems:nil removedIndices:[NSArray arrayWithObject:removedIndex]];
if (!animated)
[UIView setAnimationsEnabled:true];
});
break;
}
}
2015-10-01 18:19:52 +02:00
if (!found)
{
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%lld)/delete", conversationId] options:[NSDictionary dictionaryWithObject:[NSNumber numberWithLongLong:conversationId] forKey:@"conversationId"] watcher:self];
}
2014-07-10 16:11:09 +02:00
}];
}
- (void)clearItem:(TGConversation *)conversation animated:(bool)animated
{
int64_t conversationId = conversation.conversationId;
[ActionStageInstance() dispatchOnStageQueue:^
{
for (int i = 0; i < (int)self.conversationList.count; i++)
{
TGConversation *conversation = [self.conversationList objectAtIndex:i];
if (conversation.conversationId == conversationId)
{
[self.conversationList removeObjectAtIndex:i];
2015-10-01 18:19:52 +02:00
TGUser *user = conversation.conversationId > 0 ? [TGDatabaseInstance() loadUser:(int)conversation.conversationId] : nil;
if (user != nil && (user.kind == TGUserKindBot || user.kind == TGUserKindSmartBot))
2014-07-10 16:11:09 +02:00
{
2015-10-01 18:19:52 +02:00
NSNumber *removedIndex = [[NSNumber alloc] initWithInt:i];
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%lld)/delete", conversationId] options:@{@"conversationId": @(conversationId), @"block": @false} watcher:self];
dispatch_async(dispatch_get_main_queue(), ^
{
if (!animated)
[UIView setAnimationsEnabled:false];
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController dialogListItemsChanged:nil insertedItems:nil updatedIndices:nil updatedItems:nil removedIndices:[NSArray arrayWithObject:removedIndex]];
if (!animated)
[UIView setAnimationsEnabled:true];
});
}
else
{
int actionId = 0;
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/conversation/(%lld)/clearHistory/(dialogList%d)", conversationId, actionId++] options:[NSDictionary dictionaryWithObject:[NSNumber numberWithLongLong:conversationId] forKey:@"conversationId"] watcher:self];
conversation = [conversation copy];
conversation.outgoing = false;
conversation.text = nil;
conversation.media = nil;
conversation.unread = false;
conversation.unreadCount = 0;
conversation.fromUid = 0;
conversation.deliveryError = false;
conversation.deliveryState = TGMessageDeliveryStateDelivered;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:conversation.dialogListData];
dict[@"authorName"] = @"";
dispatch_async(dispatch_get_main_queue(), ^
{
if (!animated)
[UIView setAnimationsEnabled:false];
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController dialogListItemsChanged:nil insertedItems:nil updatedIndices:@[@(i)] updatedItems:@[conversation] removedIndices:nil];
if (!animated)
[UIView setAnimationsEnabled:true];
});
}
2014-07-10 16:11:09 +02:00
break;
}
}
}];
}
- (void)loadMoreItems
{
[ActionStageInstance() dispatchOnStageQueue:^
{
NSMutableArray *currentConversationIds = [[NSMutableArray alloc] initWithCapacity:_conversationList.count];
int minDate = INT_MAX;
for (TGConversation *conversation in _conversationList)
{
2015-10-01 18:19:52 +02:00
if (conversation.date < minDate && !conversation.isBroadcast)
2014-07-10 16:11:09 +02:00
minDate = conversation.date;
[currentConversationIds addObject:[[NSNumber alloc] initWithLongLong:conversation.conversationId]];
}
if (minDate != INT_MAX)
{
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/dialoglist/(%d)", minDate] options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:40], @"limit", [NSNumber numberWithInt:minDate], @"date", currentConversationIds, @"excludeConversationIds", nil] watcher:self];
}
else
{
2015-10-01 18:19:52 +02:00
_canLoadMore = false;
2014-07-10 16:11:09 +02:00
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
dialogListController.canLoadMore = false;
[dialogListController dialogListFullyReloaded:[NSArray array]];
});
}
}];
}
- (void)beginSearch:(NSString *)queryString inMessages:(bool)inMessages
{
[ActionStageInstance() dispatchOnStageQueue:^
{
[self resetWatchedNodePaths];
self.searchString = [[queryString stringByReplacingOccurrencesOfString:@" +" withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, queryString.length)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (self.searchString.length == 0)
{
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController searchResultsReloaded:nil searchString:nil];
});
}
else
{
if (inMessages)
{
2015-10-01 18:19:52 +02:00
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/search/messages/(%lu)", (unsigned long)[self.searchString hash]] options:[NSDictionary dictionaryWithObject:self.searchString forKey:@"query"] watcher:self];
2014-07-10 16:11:09 +02:00
}
else
{
2015-10-01 18:19:52 +02:00
[ActionStageInstance() requestActor:[NSString stringWithFormat:@"/tg/search/dialogs/(%lu)", (unsigned long)[self.searchString hash]] options:[NSDictionary dictionaryWithObject:self.searchString forKey:@"query"] watcher:self];
2014-07-10 16:11:09 +02:00
}
}
}];
}
- (void)searchResultSelectedUser:(TGUser *)user
{
2015-10-01 18:19:52 +02:00
if (self.forwardMode || self.privacyMode)
2014-07-10 16:11:09 +02:00
{
[_conversatioSelectedWatcher requestAction:@"userSelected" options:[[NSDictionary alloc] initWithObjectsAndKeys:user, @"user", nil]];
}
else
{
int64_t conversationId = user.uid;
[[TGInterfaceManager instance] navigateToConversationWithId:conversationId conversation:nil];
}
}
2015-10-01 18:19:52 +02:00
- (NSString *)stringForMemberCount:(int)memberCount
{
if (memberCount == 1)
return TGLocalizedStatic(@"Conversation.StatusRecipients_1");
else if (memberCount == 2)
return TGLocalizedStatic(@"Conversation.StatusRecipients_2");
else if (memberCount >= 3 && memberCount <= 10)
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"Conversation.StatusRecipients_3_10"), [TGStringUtils stringWithLocalizedNumber:memberCount]];
else
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"Conversation.StatusRecipients_any"), [TGStringUtils stringWithLocalizedNumber:memberCount]];
}
2014-07-10 16:11:09 +02:00
- (void)initializeDialogListData:(TGConversation *)conversation customUser:(TGUser *)customUser selfUser:(TGUser *)selfUser
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
2015-10-01 18:19:52 +02:00
int64_t mutePeerId = conversation.conversationId;
if (conversation.isChannel) {
dict[@"isChannel"] = @true;
[dict setObject:(conversation.chatTitle == nil ? @"" : conversation.chatTitle) forKey:@"title"];
if (conversation.chatPhotoSmall.length != 0)
[dict setObject:conversation.chatPhotoSmall forKey:@"avatarUrl"];
[dict setObject:[NSNumber numberWithBool:true] forKey:@"isChat"];
[dict setObject:[NSNumber numberWithBool:conversation.isVerified] forKey:@"isVerified"];
NSString *authorName = nil;
NSString *authorAvatarUrl = nil;
if (conversation.fromUid == selfUser.uid)
{
authorAvatarUrl = selfUser.photoUrlSmall;
static NSString *youString = nil;
if (youString == nil)
youString = authorNameYou;
if (conversation.text.length != 0 || conversation.media.count != 0)
authorName = youString;
}
else
{
if (conversation.fromUid != 0)
{
TGUser *authorUser = [[TGDatabase instance] loadUser:conversation.fromUid];
if (authorUser != nil)
{
authorAvatarUrl = authorUser.photoUrlSmall;
authorName = authorUser.displayName;
}
}
}
if (authorAvatarUrl != nil)
[dict setObject:authorAvatarUrl forKey:@"authorAvatarUrl"];
if (authorName != nil)
[dict setObject:authorName forKey:@"authorName"];
}
else if (!conversation.isChat || conversation.isEncrypted)
2014-07-10 16:11:09 +02:00
{
int32_t userId = 0;
if (conversation.isEncrypted)
{
if (conversation.chatParticipants.chatParticipantUids.count != 0)
2015-10-01 18:19:52 +02:00
userId = [conversation.chatParticipants.chatParticipantUids[0] intValue];
2014-07-10 16:11:09 +02:00
}
else
userId = (int)conversation.conversationId;
2015-10-01 18:19:52 +02:00
mutePeerId = userId;
2014-07-10 16:11:09 +02:00
TGUser *user = nil;
if (customUser != nil && customUser.uid == userId)
user = customUser;
else
user = [[TGDatabase instance] loadUser:(int)userId];
2016-02-25 01:03:51 +01:00
dict[@"isVerified"] = @(user.isVerified);
2014-07-10 16:11:09 +02:00
NSString *title = nil;
NSArray *titleLetters = nil;
2015-10-01 18:19:52 +02:00
if (user.uid == [TGTelegraphInstance serviceUserUid])
title = [user displayName];
else if ((user.phoneNumber.length != 0 && ![TGDatabaseInstance() uidIsRemoteContact:user.uid]))
2014-07-10 16:11:09 +02:00
title = user.formattedPhoneNumber;
else
title = [user displayName];
if (user.firstName.length != 0 && user.lastName.length != 0)
2015-10-01 18:19:52 +02:00
titleLetters = [[NSArray alloc] initWithObjects:user.firstName, user.lastName, nil];
2014-07-10 16:11:09 +02:00
else if (user.firstName.length != 0)
2015-10-01 18:19:52 +02:00
titleLetters = [[NSArray alloc] initWithObjects:user.firstName, nil];
2014-07-10 16:11:09 +02:00
else if (user.lastName.length != 0)
2015-10-01 18:19:52 +02:00
titleLetters = [[NSArray alloc] initWithObjects:user.lastName, nil];
2014-07-10 16:11:09 +02:00
if (title != nil)
[dict setObject:title forKey:@"title"];
if (titleLetters != nil)
dict[@"titleLetters"] = titleLetters;
dict[@"isEncrypted"] = [[NSNumber alloc] initWithBool:conversation.isEncrypted];
if (conversation.isEncrypted)
{
dict[@"encryptionStatus"] = [[NSNumber alloc] initWithInt:conversation.encryptedData.handshakeState];
dict[@"encryptionOutgoing"] = [[NSNumber alloc] initWithBool:conversation.chatParticipants.chatAdminId == TGTelegraphInstance.clientUserId];
NSString *firstName = user.displayFirstName;
dict[@"encryptionFirstName"] = firstName != nil ? firstName : @"";
if (user.firstName != nil)
dict[@"firstName"] = user.firstName;
if (user.lastName != nil)
dict[@"lastName"] = user.lastName;
}
dict[@"encryptedUserId"] = [[NSNumber alloc] initWithInt:userId];
if (user.photoUrlSmall != nil)
[dict setObject:user.photoUrlSmall forKey:@"avatarUrl"];
[dict setObject:[NSNumber numberWithBool:false] forKey:@"isChat"];
NSString *authorAvatarUrl = nil;
if (selfUser != nil)
authorAvatarUrl = selfUser.photoUrlSmall;
if (authorAvatarUrl != nil)
[dict setObject:authorAvatarUrl forKey:@"authorAvatarUrl"];
if (conversation.media.count != 0)
{
NSString *authorName = nil;
if (conversation.fromUid == selfUser.uid)
{
static NSString *youString = nil;
if (youString == nil)
youString = authorNameYou;
authorName = youString;
}
else
{
if (conversation.fromUid != 0)
{
TGUser *authorUser = [[TGDatabase instance] loadUser:conversation.fromUid];
if (authorUser != nil)
{
authorName = authorUser.displayName;
}
}
}
if (authorName != nil)
[dict setObject:authorName forKey:@"authorName"];
}
}
else
{
2015-10-01 18:19:52 +02:00
dict[@"isBroadcast"] = @(conversation.isBroadcast);
if (conversation.isBroadcast && conversation.chatTitle.length == 0)
dict[@"title"] = [self stringForMemberCount:conversation.chatParticipantCount];
else
[dict setObject:(conversation.chatTitle == nil ? @"" : conversation.chatTitle) forKey:@"title"];
2014-07-10 16:11:09 +02:00
if (conversation.chatPhotoSmall.length != 0)
[dict setObject:conversation.chatPhotoSmall forKey:@"avatarUrl"];
[dict setObject:[NSNumber numberWithBool:true] forKey:@"isChat"];
NSString *authorName = nil;
NSString *authorAvatarUrl = nil;
if (conversation.fromUid == selfUser.uid)
{
authorAvatarUrl = selfUser.photoUrlSmall;
static NSString *youString = nil;
if (youString == nil)
youString = authorNameYou;
if (conversation.text.length != 0 || conversation.media.count != 0)
authorName = youString;
}
else
{
if (conversation.fromUid != 0)
{
TGUser *authorUser = [[TGDatabase instance] loadUser:conversation.fromUid];
if (authorUser != nil)
{
authorAvatarUrl = authorUser.photoUrlSmall;
authorName = authorUser.displayName;
}
}
}
if (authorAvatarUrl != nil)
[dict setObject:authorAvatarUrl forKey:@"authorAvatarUrl"];
if (authorName != nil)
[dict setObject:authorName forKey:@"authorName"];
}
NSMutableDictionary *messageUsers = [[NSMutableDictionary alloc] init];
for (TGMediaAttachment *attachment in conversation.media)
{
if (attachment.type == TGActionMediaAttachmentType)
{
TGActionMediaAttachment *actionAttachment = (TGActionMediaAttachment *)attachment;
2016-02-25 01:03:51 +01:00
if (actionAttachment.actionType == TGMessageActionChatAddMember || actionAttachment.actionType == TGMessageActionChatDeleteMember || actionAttachment.actionType == TGMessageActionChannelInviter)
2014-07-10 16:11:09 +02:00
{
2016-02-25 01:03:51 +01:00
NSArray *uids = actionAttachment.actionData[@"uids"];
if (uids != nil) {
for (NSNumber *nUid in uids) {
TGUser *user = [TGDatabaseInstance() loadUser:[nUid intValue]];
if (user != nil)
[messageUsers setObject:user forKey:nUid];
}
} else {
NSNumber *nUid = [actionAttachment.actionData objectForKey:@"uid"];
if (nUid != nil)
{
TGUser *user = [TGDatabaseInstance() loadUser:[nUid intValue]];
if (user != nil)
[messageUsers setObject:user forKey:nUid];
}
2014-07-10 16:11:09 +02:00
}
}
TGUser *user = conversation.fromUid == selfUser.uid ? selfUser : [TGDatabaseInstance() loadUser:(int)conversation.fromUid];
if (user != nil)
{
[messageUsers setObject:user forKey:[[NSNumber alloc] initWithInt:user.uid]];
[messageUsers setObject:user forKey:@"author"];
}
}
}
2015-10-01 18:19:52 +02:00
[dict setObject:[[NSNumber alloc] initWithBool:[TGDatabaseInstance() isPeerMuted:mutePeerId]] forKey:@"mute"];
2014-07-10 16:11:09 +02:00
[dict setObject:messageUsers forKey:@"users"];
conversation.dialogListData = dict;
}
2015-10-01 18:19:52 +02:00
- (void)actorMessageReceived:(NSString *)path messageType:(NSString *)messageType message:(id)message
{
if ([path isEqualToString:[NSString stringWithFormat:@"/tg/search/messages/(%lu)", (unsigned long)[_searchString hash]]])
{
if ([messageType isEqualToString:@"searchResultsUpdated"])
{
NSArray *conversations = [((SGraphObjectNode *)message[@"dialogs"]).object sortedArrayUsingComparator:^NSComparisonResult(TGConversation *conversation1, TGConversation *conversation2)
{
return conversation1.date > conversation2.date ? NSOrderedAscending : NSOrderedDescending;
}];
NSMutableArray *result = [[NSMutableArray alloc] init];
TGUser *selfUser = [[TGDatabase instance] loadUser:TGTelegraphInstance.clientUserId];
CFAbsoluteTime dialogListDataStartTime = CFAbsoluteTimeGetCurrent();
for (TGConversation *conversation in conversations)
{
[self initializeDialogListData:conversation customUser:nil selfUser:selfUser];
[result addObject:conversation];
}
NSString *searchString = _searchString;
TGLog(@"Dialog list data parsing time: %f s", CFAbsoluteTimeGetCurrent() - dialogListDataStartTime);
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController searchResultsReloaded:@{@"dialogs": result} searchString:searchString];
});
}
}
}
- (id)processSearchResultItem:(id)item
{
bool forwardMode = self.forwardMode;
bool privacyMode = self.privacyMode;
bool showGroupsOnly = self.showGroupsOnly;
bool showSecretInForwardMode = self.showSecretInForwardMode;
if ([item isKindOfClass:[TGConversation class]])
{
TGConversation *conversation = (TGConversation *)item;
if (((forwardMode || privacyMode) && conversation.conversationId <= INT_MIN) && !showSecretInForwardMode)
return nil;
if ((forwardMode || privacyMode) && conversation.isBroadcast)
return nil;
if (showGroupsOnly && (conversation.conversationId > 0 || conversation.conversationId <= INT_MIN))
return nil;
[self initializeDialogListData:conversation customUser:nil selfUser:[TGDatabaseInstance() loadUser:TGTelegraphInstance.clientUserId]];
return conversation;
}
else if ([item isKindOfClass:[TGUser class]])
{
if (showGroupsOnly)
return nil;
return item;
}
return nil;
}
2014-07-10 16:11:09 +02:00
- (void)actorCompleted:(int)resultCode path:(NSString *)path result:(id)result
{
2015-10-01 18:19:52 +02:00
if ([path isEqualToString:[NSString stringWithFormat:@"/tg/search/dialogs/(%lu)", (unsigned long)[_searchString hash]]])
2014-07-10 16:11:09 +02:00
{
NSDictionary *dict = ((SGraphObjectNode *)result).object;
NSArray *users = [dict objectForKey:@"users"];
NSArray *chats = [dict objectForKey:@"chats"];
NSMutableArray *result = [[NSMutableArray alloc] init];
if (chats != nil)
{
bool forwardMode = self.forwardMode;
2015-10-01 18:19:52 +02:00
bool privacyMode = self.privacyMode;
bool showGroupsOnly = self.showGroupsOnly;
2014-07-10 16:11:09 +02:00
bool showSecretInForwardMode = self.showSecretInForwardMode;
for (id object in chats)
{
if ([object isKindOfClass:[TGConversation class]])
{
TGConversation *conversation = (TGConversation *)object;
2015-10-01 18:19:52 +02:00
if (((forwardMode || privacyMode) && conversation.conversationId <= INT_MIN) && !showSecretInForwardMode)
continue;
2016-02-25 01:03:51 +01:00
if (conversation.isDeactivated || conversation.isDeleted) {
continue;
}
2015-10-01 18:19:52 +02:00
if ((forwardMode || privacyMode) && conversation.isBroadcast)
continue;
if (showGroupsOnly && (conversation.conversationId <= INT_MIN || conversation.conversationId > 0))
2014-07-10 16:11:09 +02:00
continue;
2015-10-01 18:19:52 +02:00
[self initializeDialogListData:conversation customUser:nil selfUser:[TGDatabaseInstance() loadUser:TGTelegraphInstance.clientUserId]];
2014-07-10 16:11:09 +02:00
[result addObject:conversation];
}
else
{
[result addObject:object];
}
}
}
if (users != nil)
[result addObjectsFromArray:users];
NSString *searchString = _searchString;
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
2015-10-01 18:19:52 +02:00
[dialogListController searchResultsReloaded:@{@"dialogs": result} searchString:searchString];
2014-07-10 16:11:09 +02:00
});
}
2015-10-01 18:19:52 +02:00
else if ([path isEqualToString:[NSString stringWithFormat:@"/tg/search/messages/(%lu)", (unsigned long)[_searchString hash]]])
2014-07-10 16:11:09 +02:00
{
2015-10-01 18:19:52 +02:00
[self actorMessageReceived:path messageType:@"searchResultsUpdated" message:result];
2014-07-10 16:11:09 +02:00
}
else if ([path hasPrefix:@"/tg/dialoglist"])
{
if (resultCode == 0)
{
2015-10-01 18:19:52 +02:00
if (TGTelegraphInstance.clientUserId != 0) {
[_channelsDisposable setDisposable:[[TGChannelManagementSignals synchronizedChannelList] startWithNext:nil]];
}
2014-07-10 16:11:09 +02:00
SGraphListNode *listNode = (SGraphListNode *)result;
NSMutableArray *loadedItems = [[listNode items] mutableCopy];
bool canLoadMore = false;
bool forwardMode = self.forwardMode;
2015-10-01 18:19:52 +02:00
bool privacyMode = self.privacyMode;
bool showGroupsOnly = self.showGroupsOnly;
2014-07-10 16:11:09 +02:00
bool showSecretInForwardMode = self.showSecretInForwardMode;
TGUser *selfUser = [[TGDatabase instance] loadUser:TGTelegraphInstance.clientUserId];
2015-10-01 18:19:52 +02:00
if ((forwardMode || privacyMode) && !showSecretInForwardMode)
2014-07-10 16:11:09 +02:00
{
for (int i = 0; i < (int)loadedItems.count; i++)
{
2016-02-25 01:03:51 +01:00
TGConversation *conversation = (TGConversation *)loadedItems[i];
if (conversation.isChannel && conversation.isChannelGroup && (!self.botStartMode || conversation.channelRole == TGChannelRoleCreator || conversation.channelRole == TGChannelRoleModerator || conversation.channelRole == TGChannelRolePublisher)) {
} else if (conversation.conversationId <= INT_MIN)
2014-07-10 16:11:09 +02:00
{
[loadedItems removeObjectAtIndex:i];
i--;
}
}
}
2015-10-01 18:19:52 +02:00
if (forwardMode || privacyMode)
{
for (int i = 0; i < (int)loadedItems.count; i++)
{
if (((TGConversation *)loadedItems[i]).isBroadcast)
{
[loadedItems removeObjectAtIndex:i];
i--;
}
}
}
2016-02-25 01:03:51 +01:00
for (int i = 0; i < (int)loadedItems.count; i++)
{
if (((TGConversation *)loadedItems[i]).isDeactivated)
{
[loadedItems removeObjectAtIndex:i];
i--;
}
}
2015-10-01 18:19:52 +02:00
if (showGroupsOnly)
{
for (int i = 0; i < (int)loadedItems.count; i++)
{
TGConversation *conversation = loadedItems[i];
2016-02-25 01:03:51 +01:00
if (conversation.isChannel && conversation.isChannelGroup && (!self.botStartMode || conversation.channelRole == TGChannelRoleCreator || conversation.channelRole == TGChannelRoleModerator || conversation.channelRole == TGChannelRolePublisher)) {
} else if (conversation.conversationId <= INT_MIN || conversation.conversationId > 0) {
2015-10-01 18:19:52 +02:00
[loadedItems removeObjectAtIndex:i];
i--;
}
}
}
2014-07-10 16:11:09 +02:00
for (TGConversation *conversation in loadedItems)
{
[self initializeDialogListData:conversation customUser:nil selfUser:selfUser];
}
if (_conversationList.count == 0)
{
[_conversationList addObjectsFromArray:loadedItems];
canLoadMore = loadedItems.count != 0;
}
else
{
std::set<int64_t> existingConversations;
for (TGConversation *conversation in _conversationList)
{
existingConversations.insert(conversation.conversationId);
}
for (int i = 0; i < (int)loadedItems.count; i++)
{
TGConversation *conversation = [loadedItems objectAtIndex:i];
if (existingConversations.find(conversation.conversationId) != existingConversations.end())
{
[loadedItems removeObjectAtIndex:i];
i--;
}
}
canLoadMore = loadedItems.count != 0;
[_conversationList addObjectsFromArray:loadedItems];
}
[_conversationList sortUsingComparator:^NSComparisonResult(TGConversation *conversation1, TGConversation *conversation2)
{
int date1 = conversation1.date;
int date2 = conversation2.date;
if (date1 > date2)
return NSOrderedAscending;
else if (date1 < date2)
return NSOrderedDescending;
else
return NSOrderedSame;
}];
NSArray *items = [NSArray arrayWithArray:_conversationList];
2015-10-01 18:19:52 +02:00
_canLoadMore = canLoadMore;
2014-07-10 16:11:09 +02:00
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *controller = self.dialogListController;
if (controller != nil)
{
controller.canLoadMore = canLoadMore;
[controller dialogListFullyReloaded:items];
}
});
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
NSMutableArray *conversationIds = [[NSMutableArray alloc] init];
for (TGConversation *conversation in items)
{
[conversationIds addObject:@(conversation.conversationId)];
}
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
{
[self dialogListReady];
[TGModernConversationCompanion warmupResources];
2015-10-01 18:19:52 +02:00
//[TGDatabaseInstance() preloadConversationStates:conversationIds];
2014-07-10 16:11:09 +02:00
});
});
}
else
{
}
}
else if ([path isEqualToString:@"/tg/service/synchronizationstate"])
{
int state = [((SGraphObjectNode *)result).object intValue];
TGDialogListState newState;
if (state & 2)
{
if (state & 4)
newState = TGDialogListStateWaitingForNetwork;
else
newState = TGDialogListStateConnecting;
}
else if (state & 1)
newState = TGDialogListStateUpdating;
else
newState = TGDialogListStateNormal;
if (newState != _state)
{
_state = newState;
dispatch_async(dispatch_get_main_queue(), ^
{
NSString *title = nil;
if (newState == TGDialogListStateConnecting)
title = TGLocalized(@"State.Connecting");
else if (newState == TGDialogListStateUpdating)
title = TGLocalized(@"State.Updating");
else if (newState == TGDialogListStateWaitingForNetwork)
title = TGLocalized(@"State.WaitingForNetwork");
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController titleStateUpdated:title isLoading:newState != TGDialogListStateNormal];
});
}
}
2015-10-01 18:19:52 +02:00
else if ([path hasPrefix:@"/tg/loadConversationAndMessageForSearch/"])
{
TGDispatchOnMainThread(^
{
[_progressWindow dismiss:true];
_progressWindow = nil;
if (resultCode == ASStatusSuccess)
{
int64_t conversationId = [result[@"peerId"] longLongValue];
TGConversation *conversation = result[@"conversation"];
int32_t messageId = [result[@"messageId"] intValue];
[[TGInterfaceManager instance] navigateToConversationWithId:conversationId conversation:conversation performActions:nil atMessage:@{@"mid": @(messageId)} clearStack:true openKeyboard:false animated:true];
}
});
}
2014-07-10 16:11:09 +02:00
}
2015-10-01 18:19:52 +02:00
- (void)actionStageResourceDispatched:(NSString *)path resource:(id)resource arguments:(id)arguments
2014-07-10 16:11:09 +02:00
{
if ([path hasPrefix:@"/tg/dialoglist"])
{
[self actorCompleted:ASStatusSuccess path:path result:resource];
}
2015-10-01 18:19:52 +02:00
else if ([path isEqualToString:@"/tg/conversations"] || [path isEqualToString:@"/tg/broadcastConversations"])
2014-07-10 16:11:09 +02:00
{
NSMutableArray *conversations = [((SGraphObjectNode *)resource).object mutableCopy];
2015-10-01 18:19:52 +02:00
for (NSInteger i = 0; i < (NSInteger)conversations.count; i++) {
TGConversation *conversation = conversations[i];
2016-02-25 01:03:51 +01:00
2015-10-01 18:19:52 +02:00
if (conversation.isChannel && conversation.kind != TGConversationKindPersistentChannel) {
[conversations removeObjectAtIndex:i];
i--;
}
}
2014-07-10 16:11:09 +02:00
TGUser *selfUser = [[TGDatabase instance] loadUser:TGTelegraphInstance.clientUserId];
2015-10-01 18:19:52 +02:00
TGDialogListController *controller = self.dialogListController;
if (controller.isDisplayingSearch)
{
NSMutableArray *searchConversations = [[NSMutableArray alloc] init];
for (TGConversation *conversation in ((SGraphObjectNode *)resource).object)
{
TGConversation *copyConversation = [conversation copy];
[self initializeDialogListData:copyConversation customUser:nil selfUser:selfUser];
[searchConversations addObject:copyConversation];
}
TGDispatchOnMainThread(^
{
[controller updateSearchConversations:searchConversations];
});
}
if ((self.forwardMode || self.privacyMode) && !self.showSecretInForwardMode)
2014-07-10 16:11:09 +02:00
{
for (int i = 0; i < (int)conversations.count; i++)
{
2016-02-25 01:03:51 +01:00
TGConversation *conversation = (TGConversation *)conversations[i];
if (conversation.isChannel && conversation.isChannelGroup && (!self.botStartMode || conversation.channelRole == TGChannelRoleCreator || conversation.channelRole == TGChannelRoleModerator || conversation.channelRole == TGChannelRolePublisher)) {
} else {
if (conversation.conversationId <= INT_MIN)
{
[conversations removeObjectAtIndex:i];
i--;
}
2014-07-10 16:11:09 +02:00
}
}
}
2015-10-01 18:19:52 +02:00
if (self.forwardMode || self.privacyMode)
{
for (int i = 0; i < (int)conversations.count; i++)
{
if (((TGConversation *)conversations[i]).isBroadcast)
{
[conversations removeObjectAtIndex:i];
i--;
}
}
}
if (self.showGroupsOnly)
{
for (int i = 0; i < (int)conversations.count; i++)
{
TGConversation *conversation = conversations[i];
2016-02-25 01:03:51 +01:00
if (conversation.isChannel && conversation.isChannelGroup && (!self.botStartMode || conversation.channelRole == TGChannelRoleCreator || conversation.channelRole == TGChannelRoleModerator || conversation.channelRole == TGChannelRolePublisher)) {
} else if (conversation.conversationId <= INT_MIN || conversation.conversationId > 0) {
2015-10-01 18:19:52 +02:00
[conversations removeObjectAtIndex:i];
i--;
}
}
}
2014-07-10 16:11:09 +02:00
if (conversations.count == 0)
return;
[conversations sortUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
int date1 = (int)((TGConversation *)obj1).date;
int date2 = (int)((TGConversation *)obj2).date;
if (date1 < date2)
return NSOrderedAscending;
else if (date1 > date2)
return NSOrderedDescending;
else
return NSOrderedSame;
}];
if (conversations.count == 1 && _conversationList.count != 0)
{
TGConversation *singleConversation = [conversations objectAtIndex:0];
TGConversation *topConversation = ((TGConversation *)[_conversationList objectAtIndex:0]);
2016-02-25 01:03:51 +01:00
if (!singleConversation.isDeleted && !singleConversation.isDeactivated && _conversationList.count > 0 && topConversation.conversationId == singleConversation.conversationId && topConversation.date <= singleConversation.date)
2014-07-10 16:11:09 +02:00
{
[self initializeDialogListData:singleConversation customUser:nil selfUser:selfUser];
[_conversationList replaceObjectAtIndex:0 withObject:singleConversation];
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController dialogListItemsChanged:nil insertedItems:nil updatedIndices:[NSArray arrayWithObject:[[NSNumber alloc] initWithInt:0]] updatedItems:[NSArray arrayWithObject:singleConversation] removedIndices:nil];
});
return;
}
}
std::map<int64_t, int> conversationIdToIndex;
int index = -1;
for (TGConversation *conversation in _conversationList)
{
index++;
int64_t conversationId = conversation.conversationId;
conversationIdToIndex.insert(std::pair<int64_t, int>(conversationId, index));
}
2016-02-25 01:03:51 +01:00
NSMutableSet *addedPeerIds = [[NSMutableSet alloc] init];
for (TGConversation *conversation in conversations) {
if (conversationIdToIndex.find(conversation.conversationId) == conversationIdToIndex.end()) {
[addedPeerIds addObject:@(conversation.conversationId)];
}
}
NSMutableSet *candidatesForCutoff = [[NSMutableSet alloc] init];
2014-07-10 16:11:09 +02:00
for (int i = 0; i < (int)conversations.count; i++)
{
TGConversation *conversation = [conversations objectAtIndex:i];
int64_t conversationId = conversation.conversationId;
std::map<int64_t, int>::iterator it = conversationIdToIndex.find(conversationId);
if (it != conversationIdToIndex.end())
{
TGConversation *newConversation = [conversation copy];
2016-02-25 01:03:51 +01:00
if (!newConversation.isDeleted && !newConversation.isDeactivated)
2014-07-10 16:11:09 +02:00
[self initializeDialogListData:newConversation customUser:nil selfUser:selfUser];
2016-02-25 01:03:51 +01:00
TGConversation *previousConversation = _conversationList[(it->second)];
if (newConversation.date < previousConversation.date) {
[candidatesForCutoff addObject:@(newConversation.conversationId)];
}
2014-07-10 16:11:09 +02:00
[_conversationList replaceObjectAtIndex:(it->second) withObject:newConversation];
[conversations removeObjectAtIndex:i];
i--;
}
}
for (int i = 0; i < (int)_conversationList.count; i++)
{
TGConversation *conversation = [_conversationList objectAtIndex:i];
2016-02-25 01:03:51 +01:00
if (conversation.isDeleted || conversation.isDeactivated)
2014-07-10 16:11:09 +02:00
{
[_conversationList removeObjectAtIndex:i];
i--;
}
}
for (TGConversation *conversation in conversations)
{
TGConversation *newConversation = [conversation copy];
2016-02-25 01:03:51 +01:00
if (!newConversation.isDeleted && !newConversation.isDeactivated)
2014-07-10 16:11:09 +02:00
{
[self initializeDialogListData:newConversation customUser:nil selfUser:selfUser];
[_conversationList addObject:newConversation];
}
}
[_conversationList sortUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
int date1 = (int)((TGConversation *)obj1).date;
int date2 = (int)((TGConversation *)obj2).date;
if (date1 < date2)
return NSOrderedDescending;
else if (date1 > date2)
return NSOrderedAscending;
else
return NSOrderedSame;
}];
2015-10-01 18:19:52 +02:00
if ([arguments[@"filterEarliest"] boolValue] && _canLoadMore) {
while (_conversationList.count != 0) {
TGConversation *conversation = [_conversationList lastObject];
if (conversation.isChannel) {
[_conversationList removeLastObject];
} else {
break;
}
}
}
2016-02-25 01:03:51 +01:00
if (candidatesForCutoff.count != 0) {
for (NSInteger i = _conversationList.count - 1; i >= 0; i--) {
TGConversation *conversation = _conversationList[i];
if ([candidatesForCutoff containsObject:@(conversation.conversationId)]) {
[_conversationList removeObjectAtIndex:i];
} else {
break;
}
}
}
if (_canLoadMore) {
for (NSInteger i = _conversationList.count - 1; i >= 0; i--) {
TGConversation *conversation = _conversationList[i];
if ([addedPeerIds containsObject:@(conversation.conversationId)]) {
[_conversationList removeObjectAtIndex:i];
} else {
break;
}
}
}
2014-07-10 16:11:09 +02:00
NSArray *items = [NSArray arrayWithArray:_conversationList];
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *controller = self.dialogListController;
if (controller != nil)
{
[controller dialogListFullyReloaded:items];
2015-10-01 18:19:52 +02:00
if (!self.forwardMode && !self.privacyMode) {
[controller selectConversationWithId:[self openedConversationId]];
2014-07-10 16:11:09 +02:00
}
}
});
}
else if ([path isEqualToString:@"/tg/userdatachanges"])
{
std::map<int, int> userIdToIndex;
int index = -1;
NSArray *users = (((SGraphObjectNode *)resource).object);
for (TGUser *user in users)
{
index++;
userIdToIndex.insert(std::pair<int, int>(user.uid, index));
}
TGUser *selfUser = [[TGDatabase instance] loadUser:TGTelegraphInstance.clientUserId];
NSMutableArray *updatedIndices = [[NSMutableArray alloc] init];
NSMutableArray *updatedItems = [[NSMutableArray alloc] init];
bool updateAllOutgoing = userIdToIndex.find(TGTelegraphInstance.clientUserId) != userIdToIndex.end();
for (index = 0; index < (int)_conversationList.count; index++)
{
TGConversation *conversation = [_conversationList objectAtIndex:index];
int userId = 0;
if (conversation.isEncrypted)
{
if (conversation.chatParticipants.chatParticipantUids.count != 0)
userId = [conversation.chatParticipants.chatParticipantUids[0] intValue];
}
else if (conversation.isChat)
userId = conversation.outgoing ? TGTelegraphInstance.clientUserId : conversation.fromUid;
else
userId = (int)conversation.conversationId;
std::map<int, int>::iterator it = userIdToIndex.find(userId);
if (it != userIdToIndex.end() || (updateAllOutgoing && conversation.outgoing))
{
TGConversation *newConversation = [conversation copy];
[self initializeDialogListData:newConversation customUser:(it != userIdToIndex.end() ? [users objectAtIndex:it->second] : nil) selfUser:selfUser];
[_conversationList replaceObjectAtIndex:index withObject:newConversation];
[updatedIndices addObject:[NSNumber numberWithInt:index]];
[updatedItems addObject:newConversation];
}
}
if (updatedIndices.count != 0)
{
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *controller = self.dialogListController;
if (controller != nil)
[controller dialogListItemsChanged:nil insertedItems:nil updatedIndices:updatedIndices updatedItems:updatedItems removedIndices:nil];
});
}
}
else if ([path isEqualToString:@"/tg/conversation/*/typing"])
{
NSDictionary *dict = ((SGraphObjectNode *)resource).object;
int64_t conversationId = [[dict objectForKey:@"conversationId"] longLongValue];
if (conversationId != 0)
{
2015-10-01 18:19:52 +02:00
NSDictionary *userActivities = [dict objectForKey:@"typingUsers"];
2014-07-10 16:11:09 +02:00
NSString *typingString = nil;
2015-10-01 18:19:52 +02:00
NSArray *typingUsers = userActivities.allKeys;
2016-02-25 01:03:51 +01:00
if (((conversationId < 0 && conversationId > INT_MIN) || TGPeerIdIsChannel(conversationId)) && typingUsers.count != 0)
2014-07-10 16:11:09 +02:00
{
2015-10-01 18:19:52 +02:00
NSMutableString *userNames = [[NSMutableString alloc] init];
NSMutableArray *userNamesArray = [[NSMutableArray alloc] init];
for (NSNumber *nUid in typingUsers)
2014-07-10 16:11:09 +02:00
{
2015-10-01 18:19:52 +02:00
TGUser *user = [TGDatabaseInstance() loadUser:[nUid intValue]];
if (userNames.length != 0)
[userNames appendString:@", "];
[userNames appendString:user.displayFirstName == nil ? @"" : user.displayFirstName];
if (user.displayFirstName != nil)
[userNamesArray addObject:user.displayFirstName];
}
if (userNamesArray.count == 1)
{
typingString = [[NSString alloc] initWithFormat:[self formatForGroupActivity:userActivities[typingUsers[0]]], userNames];
}
else if (userNamesArray.count != 0)
{
NSString *format = [TGStringUtils integerValueFormat:@"ForwardedAuthorsOthers_" value:userNamesArray.count - 1];
typingString = [[NSString alloc] initWithFormat:TGLocalized(format), userNamesArray[0], [[NSString alloc] initWithFormat:@"%d", (int)userNamesArray.count - 1]];
2014-07-10 16:11:09 +02:00
}
}
else if (typingUsers.count != 0)
2015-10-01 18:19:52 +02:00
{
NSMutableString *userNames = [[NSMutableString alloc] init];
for (NSNumber *nUid in typingUsers)
{
TGUser *user = [TGDatabaseInstance() loadUser:[nUid intValue]];
if (userNames.length != 0)
[userNames appendString:@", "];
[userNames appendString:user.displayFirstName];
}
if (typingUsers.count == 1)
{
typingString = [[NSString alloc] initWithFormat:[self formatForUserActivity:userActivities[typingUsers[0]]], userNames];
}
else
typingString = userNames;
}
2014-07-10 16:11:09 +02:00
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController userTypingInConversationUpdated:conversationId typingString:typingString];
});
}
}
else if ([path isEqualToString:@"/tg/service/synchronizationstate"])
{
[self actorCompleted:ASStatusSuccess path:path result:resource];
}
else if ([path isEqualToString:@"/tg/unreadCount"])
{
dispatch_async(dispatch_get_main_queue(), ^ // request to controller
{
[TGDatabaseInstance() dispatchOnDatabaseThread:^ // request to database
{
int unreadCount = [TGDatabaseInstance() databaseState].unreadCount;
TGDispatchOnMainThread(^
{
2015-10-01 18:19:52 +02:00
if (![arguments[@"previous"] boolValue]) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:unreadCount];
}
2014-07-10 16:11:09 +02:00
if (unreadCount == 0)
[[UIApplication sharedApplication] cancelAllLocalNotifications];
self.unreadCount = unreadCount;
2015-10-01 18:19:52 +02:00
[TGAppDelegateInstance.rootController.mainTabsController setUnreadCount:unreadCount];
2014-07-10 16:11:09 +02:00
TGDialogListController *dialogListController = self.dialogListController;
dialogListController.tabBarItem.badgeValue = unreadCount == 0 ? nil : [[NSString alloc] initWithFormat:@"%d", unreadCount];
});
} synchronous:false];
});
}
else if ([path hasPrefix:@"/tg/peerSettings/"])
{
NSDictionary *dict = ((SGraphObjectNode *)resource).object;
NSMutableArray *updatedIndices = [[NSMutableArray alloc] init];
NSMutableArray *updatedItems = [[NSMutableArray alloc] init];
int64_t peerId = [[path substringWithRange:NSMakeRange(18, path.length - 1 - 18)] longLongValue];
2015-10-01 18:19:52 +02:00
int count = (int)_conversationList.count;
2014-07-10 16:11:09 +02:00
for (int i = 0; i < count; i++)
{
TGConversation *conversation = [_conversationList objectAtIndex:i];
2015-10-01 18:19:52 +02:00
int64_t mutePeerId = conversation.conversationId;
if (conversation.isEncrypted)
{
if (conversation.chatParticipants.chatParticipantUids.count != 0)
mutePeerId = [conversation.chatParticipants.chatParticipantUids[0] intValue];
}
if (mutePeerId == peerId)
2014-07-10 16:11:09 +02:00
{
TGConversation *newConversation = [conversation copy];
NSMutableDictionary *newData = [conversation.dialogListData mutableCopy];
[newData setObject:[[NSNumber alloc] initWithBool:[dict[@"muteUntil"] intValue] != 0] forKey:@"mute"];
newConversation.dialogListData = newData;
[_conversationList replaceObjectAtIndex:i withObject:newConversation];
[updatedIndices addObject:[[NSNumber alloc] initWithInt:i]];
[updatedItems addObject:newConversation];
break;
}
}
if (updatedItems.count != 0)
{
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController dialogListItemsChanged:nil insertedItems:nil updatedIndices:updatedIndices updatedItems:updatedItems removedIndices:nil];
});
}
}
else if ([path isEqualToString:@"/tg/contactlist"])
{
NSMutableArray *updatedIndices = [[NSMutableArray alloc] init];
NSMutableArray *updatedItems = [[NSMutableArray alloc] init];
int index = -1;
2015-10-01 18:19:52 +02:00
int count = (int)_conversationList.count;
2014-07-10 16:11:09 +02:00
for (int i = 0; i < count; i++)
{
index++;
TGConversation *conversation = [_conversationList objectAtIndex:i];
if (!conversation.isChat)
{
TGUser *user = [TGDatabaseInstance() loadUser:(int)conversation.conversationId];
if (user == nil)
continue;
NSString *title = nil;
2015-10-01 18:19:52 +02:00
if (user.uid == [TGTelegraphInstance serviceUserUid])
title = [user displayName];
else if (user.phoneNumber.length != 0 && ![TGDatabaseInstance() uidIsRemoteContact:user.uid])
2014-07-10 16:11:09 +02:00
title = user.formattedPhoneNumber;
else
title = [user displayName];
if (title != nil && ![title isEqualToString:[conversation.dialogListData objectForKey:@"title"]])
{
TGConversation *newConversation = [conversation copy];
NSMutableDictionary *newData = [conversation.dialogListData mutableCopy];
[newData setObject:title forKey:@"title"];
newConversation.dialogListData = newData;
[_conversationList replaceObjectAtIndex:i withObject:newConversation];
[updatedIndices addObject:[[NSNumber alloc] initWithInt:index]];
[updatedItems addObject:newConversation];
}
}
}
if (updatedItems.count != 0)
{
dispatch_async(dispatch_get_main_queue(), ^
{
TGDialogListController *dialogListController = self.dialogListController;
[dialogListController dialogListItemsChanged:nil insertedItems:nil updatedIndices:updatedIndices updatedItems:updatedItems removedIndices:nil];
});
}
}
2015-10-01 18:19:52 +02:00
else if ([path isEqualToString:@"/databasePasswordChanged"])
{
TGDispatchOnMainThread(^
{
TGDialogListController *controller = self.dialogListController;
[controller updateDatabasePassword];
});
}
else if ([path isEqualToString:@"/tg/channelListSyncrhonized"]) {
[self actionStageResourceDispatched:@"/tg/conversations" resource:[[SGraphObjectNode alloc] initWithObject:resource] arguments:@{@"filterEarliest": @true}];
}
}
- (NSString *)formatForGroupActivity:(NSString *)activity
{
if ([activity isEqualToString:@"recordingAudio"])
return TGLocalized(@"DialogList.SingleRecordingAudioSuffix");
else if ([activity isEqualToString:@"uploadingPhoto"])
return TGLocalized(@"DialogList.SingleUploadingPhotoSuffix");
else if ([activity isEqualToString:@"uploadingVideo"])
return TGLocalized(@"DialogList.SingleUploadingVideoSuffix");
else if ([activity isEqualToString:@"uploadingDocument"])
return TGLocalized(@"DialogList.SingleUploadingFileSuffix");
return TGLocalized(@"DialogList.SingleTypingSuffix");
}
- (NSString *)formatForUserActivity:(NSString *)activity
{
if ([activity isEqualToString:@"recordingAudio"])
return TGLocalized(@"Activity.RecordingAudio");
else if ([activity isEqualToString:@"uploadingPhoto"])
return TGLocalized(@"Activity.UploadingPhoto");
else if ([activity isEqualToString:@"uploadingVideo"])
return TGLocalized(@"Activity.UploadingVideo");
else if ([activity isEqualToString:@"uploadingDocument"])
return TGLocalized(@"Activity.UploadingDocument");
return TGLocalized(@"DialogList.Typing");
2014-07-10 16:11:09 +02:00
}
@end