/* Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ #import "ASCollectionDataController.h" #import "ASAssert.h" #import "ASMultidimensionalArrayUtils.h" #import "ASDisplayNode.h" #import "ASDisplayNodeInternal.h" #import "ASDataController+Subclasses.h" @interface ASCollectionDataController () - (id)collectionDataSource; @end @implementation ASCollectionDataController { NSMutableDictionary *_completedSupplementaryNodes; NSMutableDictionary *_editingSupplementaryNodes; NSMutableDictionary *_pendingNodes; NSMutableDictionary *_pendingIndexPaths; } - (void)prepareForReloadData { NSArray *elementKinds = [self.collectionDataSource supplementaryNodeKindsInDataController:self]; [elementKinds enumerateObjectsUsingBlock:^(NSString *kind, NSUInteger idx, BOOL * _Nonnull stop) { NSMutableArray *indexPaths = [NSMutableArray array]; NSMutableArray *nodes = [NSMutableArray array]; [self _populateSupplementaryNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths]; _pendingNodes[kind] = nodes; _pendingIndexPaths[kind] = indexPaths; }]; } - (void)willReloadData { [_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) { [self batchLayoutNodes:nodes atIndexPaths:_pendingIndexPaths[kind] constrainedSize:^ASSizeRange(NSIndexPath *indexPath) { return [self.collectionDataSource dataController:self constrainedSizeForSupplementaryNodeOfKind:kind atIndexPath:indexPath]; } completion:nil]; }]; } - (void)_populateSupplementaryNodesOfKind:(NSString *)kind withMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths { NSUInteger sectionCount = [self.collectionDataSource dataController:self numberOfSectionsForSupplementaryKind:kind]; for (NSUInteger i = 0; i < sectionCount; i++) { NSIndexPath *sectionIndexPath = [[NSIndexPath alloc] initWithIndex:i]; NSUInteger rowCount = [self.collectionDataSource dataController:self supplementaryViewsOfKind:kind inSection:i]; for (NSUInteger j = 0; j < rowCount; j++) { NSIndexPath *indexPath = [sectionIndexPath indexPathByAddingIndex:j]; [indexPaths addObject:indexPath]; [nodes addObject:[self.collectionDataSource dataController:self supplementaryNodeOfKind:kind atIndexPath:indexPath]]; } } } - (ASDisplayNode *)supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { ASDisplayNodeAssertMainThread(); return _completedSupplementaryNodes[kind][indexPath.section][indexPath.item]; } - (id)collectionDataSource { return (id)self.dataSource; } #pragma mark - Internal Data Querying // TODO: Reduce code duplication by exposing generic insert/delete helpers from ASDataController - (void)_insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths { if (indexPaths.count == 0) return; NSMutableArray *editingNodes = [self _editingNodesOfKind:kind]; ASInsertElementsIntoMultidimensionalArrayAtIndexPaths(editingNodes, indexPaths, nodes); NSMutableArray *completedNodes = (NSMutableArray *)ASMultidimensionalArrayDeepMutableCopy(editingNodes); ASDisplayNodePerformBlockOnMainThread(^{ _completedSupplementaryNodes[kind] = completedNodes; // TODO: Notify change }); } // TODO: Reduce code duplication by exposing generic insert/delete helpers from ASDataController - (void)_deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths { if (indexPaths.count == 0) return; } - (NSMutableArray *)_completedNodesOfKind:(NSString *)kind { return _completedSupplementaryNodes[kind]; } - (NSMutableArray *)_editingNodesOfKind:(NSString *)kind { return _editingSupplementaryNodes[kind]; } @end