Fix for #378 - emptyView not updated when items added

Summary:
Modified `IGListAdapter` to update the `hidden` status of the `emptyView` after any item-level changes (`insertInSectionController:atIndexes:` and related methods) based on whether the item count is zero.

Closes #378

- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/395

Differential Revision: D4400155

Pulled By: jessesquires

fbshipit-source-id: 6c3422297d86947e7e2878ba1b9227ff2a2a18b4
This commit is contained in:
Peter Edmonston 2017-01-10 14:40:53 -08:00 committed by Facebook Github Bot
parent 854846921b
commit dd3b9eddcc
3 changed files with 92 additions and 4 deletions

View file

@ -2,6 +2,17 @@
The changelog for `IGListKit`. Also see the [releases](https://github.com/instagram/IGListKit/releases) on GitHub.
2.2.0
-----
This release closes the [2.2.0 milestone](https://github.com/Instagram/IGListKit/milestone/4).
### Enhancements
### Fixes
- Fix bug where emptyView's hidden status is not updated after the number of items is changed with `insertInSectionController:atIndexes:` or related methods. [Peter Edmonston](https://github.com/edmonston) [(#395)](https://github.com/Instagram/IGListKit/pull/395)
2.1.0
-----

View file

@ -504,10 +504,13 @@
itemCount += [sectionController numberOfItems];
}
[self updateBackgroundViewWithItemCount:itemCount];
[self updateBackgroundViewShouldHide:itemCount > 0];
}
- (void)updateBackgroundViewWithItemCount:(NSUInteger)itemCount {
- (void)updateBackgroundViewShouldHide:(BOOL)shouldHide {
if (self.isInUpdateBlock) {
return; // will be called again when update block completes
}
UIView *backgroundView = [self.dataSource emptyViewForListAdapter:self];
// don't do anything if the client is using the same view
if (backgroundView != _collectionView.backgroundView) {
@ -516,7 +519,18 @@
[_collectionView.backgroundView removeFromSuperview];
_collectionView.backgroundView = backgroundView;
}
_collectionView.backgroundView.hidden = itemCount > 0;
_collectionView.backgroundView.hidden = shouldHide;
}
- (BOOL)itemCountIsZero {
__block BOOL isZero = YES;
[self.sectionMap enumerateUsingBlock:^(id _Nonnull object, IGListSectionController<IGListSectionType> * _Nonnull sectionController, NSInteger section, BOOL * _Nonnull stop) {
if (sectionController.numberOfItems > 0) {
isZero = NO;
*stop = YES;
}
}];
return isZero;
}
- (IGListSectionMap *)sectionMapAdjustForUpdateBlock:(BOOL)adjustForUpdateBlock {
@ -918,6 +932,7 @@
} else {
NSArray *indexPaths = [self indexPathsFromSectionController:sectionController indexes:indexes adjustForUpdateBlock:YES];
[self.updater reloadItemsInCollectionView:collectionView indexPaths:indexPaths];
[self updateBackgroundViewShouldHide:![self itemCountIsZero]];
}
}
@ -934,6 +949,7 @@
NSArray *indexPaths = [self indexPathsFromSectionController:sectionController indexes:indexes adjustForUpdateBlock:NO];
[self.updater insertItemsIntoCollectionView:collectionView indexPaths:indexPaths];
[self updateBackgroundViewShouldHide:![self itemCountIsZero]];
}
- (void)deleteInSectionController:(IGListSectionController<IGListSectionType> *)sectionController atIndexes:(NSIndexSet *)indexes {
@ -949,6 +965,7 @@
NSArray *indexPaths = [self indexPathsFromSectionController:sectionController indexes:indexes adjustForUpdateBlock:YES];
[self.updater deleteItemsFromCollectionView:collectionView indexPaths:indexPaths];
[self updateBackgroundViewShouldHide:![self itemCountIsZero]];
}
- (void)reloadSectionController:(IGListSectionController <IGListSectionType> *)sectionController {
@ -965,6 +982,7 @@
NSIndexSet *sections = [NSIndexSet indexSetWithIndex:section];
[self.updater reloadCollectionView:collectionView sections:sections];
[self updateBackgroundViewShouldHide:![self itemCountIsZero]];
}
- (void)performBatchAnimated:(BOOL)animated updates:(void (^)())updates completion:(void (^)(BOOL))completion {
@ -978,7 +996,12 @@
weakSelf.isInUpdateBlock = YES;
updates();
weakSelf.isInUpdateBlock = NO;
} completion:completion];
} completion: ^(BOOL finished) {
[weakSelf updateBackgroundViewShouldHide:![weakSelf itemCountIsZero]];
if (completion) {
completion(finished);
}
}];
}
- (void)scrollToSectionController:(IGListSectionController<IGListSectionType> *)sectionController

View file

@ -325,6 +325,60 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \
XCTAssertTrue(self.collectionView.backgroundView.hidden);
}
- (void)test_whenInsertingIntoEmptySection_thatEmptyViewBecomesHidden {
self.dataSource.objects = @[@0];
self.dataSource.backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertFalse(self.collectionView.backgroundView.hidden);
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(0)];
sectionController.items = 1;
[self.adapter insertInSectionController:sectionController atIndexes:[NSIndexSet indexSetWithIndex:0]];
XCTAssertTrue(self.collectionView.backgroundView.hidden);
}
- (void)test_whenDeletingAllItemsFromSection_thatEmptyViewBecomesVisible {
self.dataSource.objects = @[@1];
self.dataSource.backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertTrue(self.collectionView.backgroundView.hidden);
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(1)];
sectionController.items = 0;
[self.adapter deleteInSectionController:sectionController atIndexes:[NSIndexSet indexSetWithIndex:0]];
XCTAssertFalse(self.collectionView.backgroundView.hidden);
}
- (void)test_whenEmptySectionAddsItems_thatEmptyViewBecomesHidden {
self.dataSource.objects = @[@0];
self.dataSource.backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertFalse(self.collectionView.backgroundView.hidden);
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(0)];
sectionController.items = 2;
[self.adapter reloadSectionController:sectionController];
XCTAssertTrue(self.collectionView.backgroundView.hidden);
}
- (void)test_whenSectionItemsAreDeletedAsBatch_thatEmptyViewBecomesVisible {
self.dataSource.objects = @[@1, @2];
self.dataSource.backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertTrue(self.collectionView.backgroundView.hidden);
IGListTestSection *firstSectionController = [self.adapter sectionControllerForObject:@(1)];
IGListTestSection *secondSectionController = [self.adapter sectionControllerForObject:@(2)];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
[self.adapter performBatchAnimated:YES updates:^{
firstSectionController.items = 0;
[self.adapter deleteInSectionController:firstSectionController atIndexes:[NSIndexSet indexSetWithIndex:0]];
secondSectionController.items = 0;
NSIndexSet *indexesToDelete = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
[self.adapter deleteInSectionController:secondSectionController atIndexes:indexesToDelete];
} completion:^(BOOL finished) {
XCTAssertFalse(self.collectionView.backgroundView.hidden);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:15 handler:nil];
}
- (void)test_whenScrollViewDelegateSet_thatDelegateReceivesEvents {
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UIScrollViewDelegate)];