#import "TGChatListSignals.h" #import "TGDatabase.h" #import "ActionStage.h" #import "TGTelegraph.h" @interface TGChatListAdapter : NSObject { NSMutableArray *_list; void (^_listUpdated)(NSArray *); NSUInteger _limit; } @property (nonatomic, strong) ASHandle *actionHandle; @end @implementation TGChatListAdapter - (instancetype)initWithList:(NSArray *)list limit:(NSUInteger)limit listUpdated:(void (^)(NSArray *))listUpdated { self = [super init]; if (self != nil) { _actionHandle = [[ASHandle alloc] initWithDelegate:self]; [ActionStageInstance() watchForPaths:@[ @"/tg/conversations", @"/tg/broadcastConversations", @"/tg/channelListSyncrhonized", @"/dialogListReloaded" ] watcher:self]; _list = [[NSMutableArray alloc] init]; [_list addObjectsFromArray:list]; _limit = limit; _listUpdated = [listUpdated copy]; } return self; } - (void)dealloc { [_actionHandle reset]; [ActionStageInstance() removeWatcher:self]; } - (void)actionStageResourceDispatched:(NSString *)path resource:(id)resource arguments:(id)__unused arguments { if ([path isEqualToString:@"/dialogListReloaded"]) { [TGDatabaseInstance() loadConversationListFromDate:INT_MAX limit:(int)_limit excludeConversationIds:@[] completion:^(NSArray *chatList, __unused bool loadedAllRegular) { [ActionStageInstance() dispatchOnStageQueue:^ { [_list removeAllObjects]; for (TGConversation *conversation in chatList) { if (!conversation.isDeactivated) { [_list addObject:conversation]; } } NSArray *items = [NSArray arrayWithArray:_list]; if (_listUpdated) _listUpdated(items); }]; }]; } else if ([path isEqualToString:@"/tg/conversations"] || [path isEqualToString:@"/tg/broadcastConversations"]) { NSMutableArray *conversations = [((SGraphObjectNode *)resource).object mutableCopy]; if (conversations.count == 0) return; for (NSInteger i = 0; i < (NSInteger)conversations.count; i++) { TGConversation *conversation = conversations[i]; if (conversation.isChannel && conversation.kind != TGConversationKindPersistentChannel) { [conversations removeObjectAtIndex:i]; i--; } if (conversation.isDeactivated) { [conversations removeObjectAtIndex:i]; i--; } } [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; }]; NSMutableDictionary *conversationIdToIndex = [[NSMutableDictionary alloc] init]; int index = -1; for (TGConversation *conversation in _list) { index++; int64_t conversationId = conversation.conversationId; conversationIdToIndex[@(conversationId)] = @(index); } for (int i = 0; i < (int)conversations.count; i++) { TGConversation *conversation = [conversations objectAtIndex:i]; int64_t conversationId = conversation.conversationId; NSNumber *conversationIndex = conversationIdToIndex[@(conversationId)]; if (conversationIndex != nil) { TGConversation *newConversation = [conversation copy]; if (!newConversation.isDeleted) { //[self initializeDialogListData:newConversation customUser:nil selfUser:selfUser]; } [_list replaceObjectAtIndex:[conversationIndex unsignedIntegerValue] withObject:newConversation]; [conversations removeObjectAtIndex:i]; i--; } } for (int i = 0; i < (int)_list.count; i++) { TGConversation *conversation = [_list objectAtIndex:i]; if (conversation.isDeleted) { [_list removeObjectAtIndex:i]; i--; } } for (TGConversation *conversation in conversations) { TGConversation *newConversation = [conversation copy]; if (!newConversation.isDeleted) { //[self initializeDialogListData:newConversation customUser:nil selfUser:selfUser]; [_list addObject:newConversation]; } } [_list 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; }]; NSArray *items = [NSArray arrayWithArray:_list]; if (_listUpdated) _listUpdated(items); } else if ([path isEqualToString:@"/tg/channelListSyncrhonized"]) { [self actionStageResourceDispatched:@"/tg/conversations" resource:[[SGraphObjectNode alloc] initWithObject:resource] arguments:@{@"filterEarliest": @true}]; } } @end @implementation TGChatListSignals + (SSignal *)currentChatListWithLimit:(NSUInteger)limit { return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { [TGDatabaseInstance() loadConversationListFromDate:INT_MAX limit:(int)limit excludeConversationIds:@[] completion:^(NSArray *chatList, __unused bool loadedAllRegular) { NSMutableArray *filteredResult = [[NSMutableArray alloc] initWithArray:chatList]; [filteredResult sortUsingComparator:^NSComparisonResult(TGConversation *lhs, TGConversation *rhs) { if (lhs.date > rhs.date) { return NSOrderedAscending; } else if (lhs.date < rhs.date) { return NSOrderedDescending; } else { if (lhs.conversationId < rhs.conversationId) { return NSOrderedDescending; } else { return NSOrderedAscending; } } }]; for (NSUInteger i = 0; i < filteredResult.count; i++) { TGConversation *conversation = filteredResult[i]; if (conversation.isChannel && conversation.kind != TGConversationKindPersistentChannel) { [filteredResult removeObjectAtIndex:i]; i--; } } [subscriber putNext:filteredResult]; [subscriber putCompletion]; }]; return nil; }]; } + (SSignal *)chatListWithLimit:(NSUInteger)limit { __block NSArray *initialList = nil; SSignal *incrementalSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { TGChatListAdapter *adapter = [[TGChatListAdapter alloc] initWithList:initialList limit:limit listUpdated:^(NSArray *list) { [subscriber putNext:list]; }]; return [[SBlockDisposable alloc] initWithBlock:^ { [adapter description]; }]; }]; return [[[self currentChatListWithLimit:limit] onNext:^(id next) { initialList = next; }] then:incrementalSignal]; } @end