// // ViewController.m // Texture // // Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. // Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved. // Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 // #import "ViewController.h" #import #import #import "BlurbNode.h" #import "KittenNode.h" static const NSInteger kLitterSize = 20; // intial number of kitten cells in ASTableView static const NSInteger kLitterBatchSize = 10; // number of kitten cells to add to ASTableView static const NSInteger kMaxLitterSize = 100; // max number of kitten cells allowed in ASTableView @interface ViewController () { ASTableView *_tableView; // array of boxed CGSizes corresponding to placekitten.com kittens NSMutableArray *_kittenDataSource; BOOL _dataSourceLocked; NSIndexPath *_blurbNodeIndexPath; } @property (nonatomic, strong) NSMutableArray *kittenDataSource; @property (atomic, assign) BOOL dataSourceLocked; @end @implementation ViewController #pragma mark - #pragma mark UIViewController. - (instancetype)init { if (!(self = [super init])) return nil; _tableView = [[ASTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; // KittenNode has its own separator _tableView.asyncDataSource = self; _tableView.asyncDelegate = self; // populate our "data source" with some random kittens _kittenDataSource = [self createLitterWithSize:kLitterSize]; _blurbNodeIndexPath = [NSIndexPath indexPathForItem:0 inSection:0]; self.title = @"Kittens"; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(toggleEditingMode)]; return self; } - (NSMutableArray *)createLitterWithSize:(NSInteger)litterSize { NSMutableArray *kittens = [NSMutableArray arrayWithCapacity:litterSize]; for (NSInteger i = 0; i < litterSize; i++) { // placekitten.com will return the same kitten picture if the same pixel height & width are requested, // so generate kittens with different width & height values. u_int32_t deltaX = arc4random_uniform(10) - 5; u_int32_t deltaY = arc4random_uniform(10) - 5; CGSize size = CGSizeMake(350 + 2 * deltaX, 350 + 4 * deltaY); [kittens addObject:[NSValue valueWithCGSize:size]]; } return kittens; } - (void)setKittenDataSource:(NSMutableArray *)kittenDataSource { ASDisplayNodeAssert(!self.dataSourceLocked, @"Could not update data source when it is locked !"); _kittenDataSource = kittenDataSource; } - (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:_tableView]; [_tableView reloadDataImmediately]; } - (void)viewWillLayoutSubviews { _tableView.frame = self.view.bounds; } - (void)toggleEditingMode { [_tableView setEditing:!_tableView.editing animated:YES]; } #pragma mark - #pragma mark ASTableView. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [_tableView deselectRowAtIndexPath:indexPath animated:YES]; [_tableView beginUpdates]; // Assume only kitten nodes are selectable (see -tableView:shouldHighlightRowAtIndexPath:). KittenNode *node = (KittenNode *)[_tableView nodeForRowAtIndexPath:indexPath]; [node toggleImageEnlargement]; [_tableView endUpdates]; } - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath { // special-case the first row if ([_blurbNodeIndexPath compare:indexPath] == NSOrderedSame) { BlurbNode *node = [[BlurbNode alloc] init]; return node; } NSValue *size = _kittenDataSource[indexPath.row - 1]; KittenNode *node = [[KittenNode alloc] initWithKittenOfSize:size.CGSizeValue]; return node; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // blurb node + kLitterSize kitties return 1 + _kittenDataSource.count; } - (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { // Enable selection for kitten nodes return [_blurbNodeIndexPath compare:indexPath] != NSOrderedSame; } - (void)tableViewLockDataSource:(ASTableView *)tableView { self.dataSourceLocked = YES; } - (void)tableViewUnlockDataSource:(ASTableView *)tableView { self.dataSourceLocked = NO; } - (BOOL)shouldBatchFetchForTableView:(UITableView *)tableView { return _kittenDataSource.count < kMaxLitterSize; } - (void)tableView:(UITableView *)tableView willBeginBatchFetchWithContext:(ASBatchContext *)context { NSLog(@"adding kitties"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); dispatch_async(dispatch_get_main_queue(), ^{ // populate a new array of random-sized kittens NSArray *moarKittens = [self createLitterWithSize:kLitterBatchSize]; NSMutableArray *indexPaths = [[NSMutableArray alloc] init]; // find number of kittens in the data source and create their indexPaths NSInteger existingRows = _kittenDataSource.count + 1; for (NSInteger i = 0; i < moarKittens.count; i++) { [indexPaths addObject:[NSIndexPath indexPathForRow:existingRows + i inSection:0]]; } // add new kittens to the data source & notify table of new indexpaths [_kittenDataSource addObjectsFromArray:moarKittens]; [tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade]; [context completeBatchFetching:YES]; NSLog(@"kittens added"); }); }); } - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Enable editing for Kitten nodes return [_blurbNodeIndexPath compare:indexPath] != NSOrderedSame; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Assume only kitten nodes are editable (see -tableView:canEditRowAtIndexPath:). [_kittenDataSource removeObjectAtIndex:indexPath.row - 1]; [_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } } @end