Skip to content

Commit

Permalink
IGListKit Support II: Electric Boogaloo (#2942)
Browse files Browse the repository at this point in the history
* Reimplement IGListKit support in a cleaner way

* Rename and fix some stuff

* Fix supplementaries more

* Update docs

* Update test

* Cleanup minor things

* Tweak it

* Indentation

* Remove irrelevant changes

* Break out cell into its own file

* Fix indentation

* Address feedback
  • Loading branch information
Adlai Holler authored Jan 30, 2017
1 parent 34338ca commit 38aac9d
Show file tree
Hide file tree
Showing 70 changed files with 2,444 additions and 180 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ before_install:
install: echo "<3"
env:
- MODE=tests
- MODE=tests_listkit
- MODE=examples-pt1
- MODE=examples-pt2
- MODE=examples-pt3
Expand Down
394 changes: 394 additions & 0 deletions ASDKListKit/ASDKListKit.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions ASDKListKit/ASDKListKit.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListKitTestAdapterDataSource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// ASListKitTestAdapterDataSource.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import <IGListKit/IGListKit.h>

@interface ASListKitTestAdapterDataSource : NSObject <IGListAdapterDataSource>

// array of numbers which is then passed to -[IGListTestSection setItems:]
@property (nonatomic, strong) NSArray <NSNumber *> *objects;

@end
30 changes: 30 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListKitTestAdapterDataSource.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// ASListKitTestAdapterDataSource.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import "ASListKitTestAdapterDataSource.h"
#import "ASListTestSection.h"

@implementation ASListKitTestAdapterDataSource

- (NSArray *)objectsForListAdapter:(IGListAdapter *)listAdapter
{
return self.objects;
}

- (IGListSectionController <IGListSectionType> *)listAdapter:(IGListAdapter *)listAdapter sectionControllerForObject:(id)object
{
ASListTestSection *section = [[ASListTestSection alloc] init];
return section;
}

- (nullable UIView *)emptyViewForListAdapter:(IGListAdapter *)listAdapter
{
return nil;
}

@end
110 changes: 110 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListKitTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// ASListKitTests.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import <XCTest/XCTest.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import "ASListKitTestAdapterDataSource.h"
#import "ASXCTExtensions.h"
#import <JGMethodSwizzler/JGMethodSwizzler.h>

@interface ASListKitTests : XCTestCase

@property (nonatomic, strong) ASCollectionNode *collectionNode;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) ASListKitTestAdapterDataSource *dataSource;
@property (nonatomic, strong) UICollectionViewFlowLayout *layout;
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic) NSInteger reloadDataCount;

@end

@implementation ASListKitTests

- (void)setUp
{
[super setUp];

[ASCollectionView swizzleInstanceMethod:@selector(reloadData) withReplacement:JGMethodReplacementProviderBlock {
return JGMethodReplacement(void, ASCollectionView *) {
JGOriginalImplementation(void);
_reloadDataCount++;
};
}];

self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];

self.layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:self.layout];
self.collectionNode.frame = self.window.bounds;
self.collectionView = self.collectionNode.view;

[self.window addSubnode:self.collectionNode];

IGListAdapterUpdater *updater = [[IGListAdapterUpdater alloc] init];

self.dataSource = [[ASListKitTestAdapterDataSource alloc] init];
self.adapter = [[IGListAdapter alloc] initWithUpdater:updater
viewController:nil
workingRangeSize:0];
self.adapter.dataSource = self.dataSource;
[self.adapter setASDKCollectionNode:self.collectionNode];
XCTAssertNotNil(self.adapter.collectionView, @"Adapter was not bound to collection view. You may have a stale copy of AsyncDisplayKit that was built without IG_LIST_KIT. Clean Builder Folder IMO.");
}

- (void)tearDown
{
[super tearDown];
XCTAssert([ASCollectionView deswizzleAllMethods]);
self.reloadDataCount = 0;
self.window = nil;
self.collectionNode = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
self.layout = nil;
}

- (void)test_whenAdapterUpdated_withObjectsOverflow_thatVisibleObjectsIsSubsetOfAllObjects
{
// each section controller returns n items sized 100x10
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
XCTestExpectation *e = [self expectationWithDescription:@"Data update completed"];

[self.adapter performUpdatesAnimated:NO completion:^(BOOL finished) {
[e fulfill];
}];

[self waitForExpectationsWithTimeout:1 handler:nil];
self.collectionNode.view.contentOffset = CGPointMake(0, 30);
[self.collectionNode.view layoutIfNeeded];


NSArray *visibleObjects = [[self.adapter visibleObjects] sortedArrayUsingSelector:@selector(compare:)];
NSArray *expectedObjects = @[@3, @4, @5];
XCTAssertEqualObjects(visibleObjects, expectedObjects);
}

- (void)test_whenCollectionViewIsNotInAWindow_updaterDoesNotJustCallReloadData
{
[self.collectionView removeFromSuperview];

[self.collectionView layoutIfNeeded];
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
XCTestExpectation *e = [self expectationWithDescription:@"Data update completed"];

[self.adapter performUpdatesAnimated:NO completion:^(BOOL finished) {
[e fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
[self.collectionView layoutIfNeeded];

XCTAssertEqual(self.reloadDataCount, 2);
}

@end
13 changes: 13 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestCellNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// ASListTestCellNode.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import <AsyncDisplayKit/AsyncDisplayKit.h>

@interface ASListTestCellNode : ASCellNode

@end
13 changes: 13 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestCellNode.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// ASListTestCellNode.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import "ASListTestCellNode.h"

@implementation ASListTestCellNode

@end
22 changes: 22 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestObject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// ASListTestObject.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import <IGListKit/IGListKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface ASListTestObject : NSObject <IGListDiffable, NSCopying>

- (instancetype)initWithKey:(id <NSCopying>)key value:(id)value;

@property (nonatomic, strong, readonly) id key;
@property (nonatomic, strong) id value;

@end

NS_ASSUME_NONNULL_END
49 changes: 49 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestObject.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// ASListTestObject.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import "ASListTestObject.h"

@implementation ASListTestObject

- (instancetype)initWithKey:(id)key value:(id)value
{
if (self = [super init]) {
_key = [key copy];
_value = value;
}
return self;
}

- (instancetype)copyWithZone:(NSZone *)zone
{
return [[ASListTestObject alloc] initWithKey:self.key value:self.value];
}

#pragma mark - IGListDiffable

- (id<NSObject>)diffIdentifier
{
return self.key;
}

- (BOOL)isEqualToDiffableObject:(id)object
{
if (object == self) {
return YES;
}
if ([object isKindOfClass:[ASListTestObject class]]) {
id k1 = self.key;
id k2 = [object key];
id v1 = self.value;
id v2 = [(ASListTestObject *)object value];
return (v1 == v2 || [v1 isEqual:v2]) && (k1 == k2 || [k1 isEqual:k2]);
}
return NO;
}

@end
18 changes: 18 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestSection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// ASListTestSection.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import <IGListKit/IGListKit.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>

@interface ASListTestSection : IGListSectionController <IGListSectionType, ASSectionController>

@property (nonatomic) NSInteger itemCount;

@property (nonatomic) NSInteger selectedItemIndex;

@end
58 changes: 58 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestSection.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// ASListTestSection.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import "ASListTestSection.h"
#import "ASListTestCellNode.h"

@implementation ASListTestSection

- (instancetype)init
{
if (self = [super init])
{
_selectedItemIndex = NSNotFound;
}
return self;
}

- (NSInteger)numberOfItems
{
return self.itemCount;
}

- (CGSize)sizeForItemAtIndex:(NSInteger)index
{
ASDisplayNodeFailAssert(@"Did not expect %@ to be called.", NSStringFromSelector(_cmd));
return CGSizeMake(100, 10);
}

ASIGSectionControllerCellForIndexImplementation

- (void)didUpdateToObject:(id)object
{
if ([object isKindOfClass:[NSNumber class]])
{
self.itemCount = [object integerValue];
}
}

- (void)didSelectItemAtIndex:(NSInteger)index
{
self.selectedItemIndex = index;
}

- (ASCellNodeBlock)nodeBlockForItemAtIndex:(NSInteger)index
{
return ^{
ASListTestCellNode *node = [[ASListTestCellNode alloc] init];
node.style.preferredSize = CGSizeMake(100, 10);
return node;
};
}

@end
13 changes: 13 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestSupplementaryNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// ASListTestSupplementaryNode.h
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import <AsyncDisplayKit/AsyncDisplayKit.h>

@interface ASListTestSupplementaryNode : ASCellNode

@end
13 changes: 13 additions & 0 deletions ASDKListKit/ASDKListKitTests/ASListTestSupplementaryNode.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// ASListTestSupplementaryNode.m
// AsyncDisplayKit
//
// Created by Adlai Holler on 12/25/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import "ASListTestSupplementaryNode.h"

@implementation ASListTestSupplementaryNode

@end
Loading

0 comments on commit 38aac9d

Please sign in to comment.