Showing preview only (5,113K chars total). Download the full file or copy to clipboard to get everything.
Repository: Instagram/IGListKit
Branch: main
Commit: 01887c6e16e0
Files: 574
Total size: 4.8 MB
Directory structure:
gitextract_na4i75rs/
├── .github/
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── RELEASE_CHECKLIST.md
│ └── workflows/
│ └── CI.yml
├── .gitignore
├── .slather.yml
├── .swiftlint.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dangerfile
├── Examples/
│ ├── Examples-iOS/
│ │ ├── IGListKitExamples/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ └── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── LaunchScreen.storyboard
│ │ │ ├── DelegateProtocols/
│ │ │ │ └── PostSectionControllerDelegate.swift
│ │ │ ├── Extensions/
│ │ │ │ ├── UIActivityIndicatorView+Extension.swift
│ │ │ │ └── UIColor+Extension.swift
│ │ │ ├── IGListKitExamples.entitlements
│ │ │ ├── Info.plist
│ │ │ ├── Models/
│ │ │ │ ├── APIService.swift
│ │ │ │ ├── ActivityItem.swift
│ │ │ │ ├── FeedItem.swift
│ │ │ │ ├── GridItem.swift
│ │ │ │ ├── HorizontalCardsSection.swift
│ │ │ │ ├── LoadingCellModel.swift
│ │ │ │ ├── Month.swift
│ │ │ │ ├── Post.h
│ │ │ │ ├── Post.m
│ │ │ │ ├── PostModel.swift
│ │ │ │ ├── RemodelGeneratedModels/
│ │ │ │ │ ├── PersonModel.h
│ │ │ │ │ ├── PersonModel.m
│ │ │ │ │ └── PersonModel.value
│ │ │ │ ├── SelectionModel.swift
│ │ │ │ ├── SwipeActionSection.swift
│ │ │ │ ├── User.swift
│ │ │ │ └── ViewModels/
│ │ │ │ ├── DayViewModel.swift
│ │ │ │ └── MonthTitleViewModel.swift
│ │ │ ├── SectionControllers/
│ │ │ │ ├── DemoSectionController.swift
│ │ │ │ ├── DisplaySectionController.swift
│ │ │ │ ├── EmbeddedSectionController.swift
│ │ │ │ ├── ExpandableSectionController.swift
│ │ │ │ ├── FeedItemSectionController.swift
│ │ │ │ ├── GridSectionController.swift
│ │ │ │ ├── HorizontalSectionController.swift
│ │ │ │ ├── LabelSectionController.swift
│ │ │ │ ├── ListeningSectionController.swift
│ │ │ │ ├── LoadingSectionController.swift
│ │ │ │ ├── MonthSectionController.swift
│ │ │ │ ├── PersonSectionController.h
│ │ │ │ ├── PersonSectionController.m
│ │ │ │ ├── PostSectionController.h
│ │ │ │ ├── PostSectionController.m
│ │ │ │ ├── PostSectionController.swift
│ │ │ │ ├── RemoveSectionController.swift
│ │ │ │ ├── ReorderableSectionController.swift
│ │ │ │ ├── SearchSectionController.swift
│ │ │ │ ├── SelfSizingSectionController.swift
│ │ │ │ ├── StoryboardLabelSectionController.swift
│ │ │ │ ├── UserSectionController.swift
│ │ │ │ ├── With Composable Layout/
│ │ │ │ │ ├── ActivityComposableSectionController.swift
│ │ │ │ │ ├── ExpandableComposableSectionController.swift
│ │ │ │ │ ├── GridComposableSectionController.swift
│ │ │ │ │ ├── HorizontalComposableSectionController.swift
│ │ │ │ │ ├── SelectionComposableSectionController.swift
│ │ │ │ │ ├── SwipeActionComposabelSectionController.swift
│ │ │ │ │ └── UserComposableSectionController.swift
│ │ │ │ └── WorkingRangeSectionController.swift
│ │ │ ├── Storyboard/
│ │ │ │ └── Demo.storyboard
│ │ │ ├── Systems/
│ │ │ │ └── IncrementAnnouncer.swift
│ │ │ ├── ViewControllers/
│ │ │ │ ├── AnnouncingDepsViewController.swift
│ │ │ │ ├── CalendarViewController.swift
│ │ │ │ ├── CompositionLayoutViewController.swift
│ │ │ │ ├── DemosViewController.swift
│ │ │ │ ├── DiffTableViewController.swift
│ │ │ │ ├── DisplayViewController.swift
│ │ │ │ ├── EmptyViewController.swift
│ │ │ │ ├── FeedViewController.swift
│ │ │ │ ├── IGListKitExamples-Bridging-Header.h
│ │ │ │ ├── LoadMoreViewController.swift
│ │ │ │ ├── MixedDataViewController.swift
│ │ │ │ ├── NestedAdapterViewController.swift
│ │ │ │ ├── ObjcDemoViewController.h
│ │ │ │ ├── ObjcDemoViewController.m
│ │ │ │ ├── ObjcGeneratedModelDemoViewController.h
│ │ │ │ ├── ObjcGeneratedModelDemoViewController.m
│ │ │ │ ├── ReorderableViewController.swift
│ │ │ │ ├── SearchViewController.swift
│ │ │ │ ├── SelfSizingCellsViewController.swift
│ │ │ │ ├── SingleSectionStoryboardViewController.swift
│ │ │ │ ├── SingleSectionViewController.swift
│ │ │ │ ├── StoryboardViewController.swift
│ │ │ │ ├── SupplementaryViewController.swift
│ │ │ │ └── WorkingRangeViewController.swift
│ │ │ └── Views/
│ │ │ ├── CalendarDayCell.swift
│ │ │ ├── CenterLabelCell.swift
│ │ │ ├── CommentCell.h
│ │ │ ├── CommentCell.m
│ │ │ ├── CompositionLayoutCell.swift
│ │ │ ├── DetailLabelCell.swift
│ │ │ ├── EmbeddedCollectionViewCell.swift
│ │ │ ├── FullWidthSelfSizingCell.swift
│ │ │ ├── ImageCell.swift
│ │ │ ├── InteractiveCell.h
│ │ │ ├── InteractiveCell.m
│ │ │ ├── LabelCell.swift
│ │ │ ├── LoadingCell.swift
│ │ │ ├── ManuallySelfSizingCell.swift
│ │ │ ├── MonthTitleCell.swift
│ │ │ ├── NibCell.swift
│ │ │ ├── NibCell.xib
│ │ │ ├── NibSelfSizingCell.swift
│ │ │ ├── NibSelfSizingCell.xib
│ │ │ ├── PersonCell.h
│ │ │ ├── PersonCell.m
│ │ │ ├── PhotoCell.h
│ │ │ ├── PhotoCell.m
│ │ │ ├── PostCell.swift
│ │ │ ├── RemoveCell.swift
│ │ │ ├── SearchCell.swift
│ │ │ ├── SpinnerCell.swift
│ │ │ ├── StoryboardCell.swift
│ │ │ ├── UserFooterView.swift
│ │ │ ├── UserFooterView.xib
│ │ │ ├── UserHeaderView.swift
│ │ │ ├── UserHeaderView.xib
│ │ │ ├── UserInfoCell.h
│ │ │ └── UserInfoCell.m
│ │ ├── IGListKitExamples-UITests/
│ │ │ ├── DemosViewControllerUITests.swift
│ │ │ ├── FeedViewController.swift
│ │ │ ├── Info.plist
│ │ │ ├── LoadMoreViewControllerUITests.swift
│ │ │ ├── MixedDataViewControllerUITests.swift
│ │ │ ├── SearchViewControllerUITests.swift
│ │ │ └── UITestCase.swift
│ │ ├── IGListKitExamples.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ ├── IGListKitExamples.xcscheme
│ │ │ ├── IGListKitMessageExample.xcscheme
│ │ │ └── IGListKitTodayExample.xcscheme
│ │ ├── IGListKitMessageExample/
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── Contents.json
│ │ │ │ └── iMessage App Icon.stickersiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Info.plist
│ │ │ └── MessagesViewController.swift
│ │ ├── IGListKitTodayExample/
│ │ │ ├── Info.plist
│ │ │ └── TodayViewController.swift
│ │ └── LICENSE-examples.md
│ ├── Examples-macOS/
│ │ ├── IGListKitExamples/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ └── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── Main.storyboard
│ │ │ ├── Data/
│ │ │ │ └── users.json
│ │ │ ├── Helpers/
│ │ │ │ ├── IndexSet+Extensions.swift
│ │ │ │ ├── Shuffle.swift
│ │ │ │ └── UsersProvider.swift
│ │ │ ├── Info.plist
│ │ │ ├── Models/
│ │ │ │ └── User.swift
│ │ │ ├── View/
│ │ │ │ ├── UserCollectionViewCell.swift
│ │ │ │ └── UserCollectionViewCell.xib
│ │ │ └── ViewControllers/
│ │ │ └── UsersViewController.swift
│ │ ├── IGListKitExamples.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── IGListKitExamples.xcscheme
│ │ └── LICENSE-examples.md
│ └── Examples-tvOS/
│ ├── IGListKitExamples/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── App Icon & Top Shelf Image.brandassets/
│ │ │ │ ├── App Icon - Large.imagestack/
│ │ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── App Icon - Small.imagestack/
│ │ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Top Shelf Image Wide.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Top Shelf Image.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── LaunchImage.launchimage/
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── Models/
│ │ │ └── NSObject+IGListDiffable.swift
│ │ ├── SectionControllers/
│ │ │ ├── CarouselSectionController.swift
│ │ │ ├── DemoSectionController.swift
│ │ │ ├── HorizontalSectionController.swift
│ │ │ └── LabelSectionController.swift
│ │ ├── ViewControllers/
│ │ │ ├── DemosViewController.swift
│ │ │ └── NestedAdapterViewController.swift
│ │ └── Views/
│ │ ├── CarouselCell.swift
│ │ ├── CarouselCell.xib
│ │ ├── DemoCell.swift
│ │ ├── EmbeddedCollectionViewCell.swift
│ │ └── LabelCell.swift
│ ├── IGListKitExamples.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── IGListKitExamples.xcscheme
│ └── LICENSE-examples.md
├── Gemfile
├── Guides/
│ ├── Best Practices and FAQ.md
│ ├── Generating your models using remodel.md
│ ├── Getting Started.md
│ ├── IGListDiffable and Equality.md
│ ├── Installation.md
│ ├── Migration.md
│ ├── Modeling and Binding.md
│ ├── VISION.md
│ ├── Working with Core Data.md
│ └── Working with UICollectionView.md
├── IGListDiffKit.podspec
├── IGListKit.podspec
├── IGListKit.xcodeproj/
│ ├── project.pbxproj
│ └── xcshareddata/
│ └── xcschemes/
│ ├── IGListKit-macOS.xcscheme
│ ├── IGListKit-tvOS.xcscheme
│ └── IGListKit.xcscheme
├── IGListSwiftKit.podspec
├── LICENSE.md
├── Package.swift
├── README.md
├── README.zh.md
├── Source/
│ ├── IGListDiffKit/
│ │ ├── IGListAssert.h
│ │ ├── IGListBatchUpdateData.h
│ │ ├── IGListBatchUpdateData.mm
│ │ ├── IGListCompatibility.h
│ │ ├── IGListDiff.h
│ │ ├── IGListDiff.mm
│ │ ├── IGListDiffKit.h
│ │ ├── IGListDiffable.h
│ │ ├── IGListExperiments.h
│ │ ├── IGListIndexPathResult.h
│ │ ├── IGListIndexPathResult.m
│ │ ├── IGListIndexSetResult.h
│ │ ├── IGListIndexSetResult.m
│ │ ├── IGListMacros.h
│ │ ├── IGListMoveIndex.h
│ │ ├── IGListMoveIndex.m
│ │ ├── IGListMoveIndexPath.h
│ │ ├── IGListMoveIndexPath.m
│ │ ├── Internal/
│ │ │ ├── IGListIndexPathResultInternal.h
│ │ │ ├── IGListIndexSetResultInternal.h
│ │ │ ├── IGListMoveIndexInternal.h
│ │ │ └── IGListMoveIndexPathInternal.h
│ │ ├── NSNumber+IGListDiffable.h
│ │ ├── NSNumber+IGListDiffable.m
│ │ ├── NSString+IGListDiffable.h
│ │ └── NSString+IGListDiffable.m
│ ├── IGListKit/
│ │ ├── IGListAdapter.h
│ │ ├── IGListAdapter.m
│ │ ├── IGListAdapterDataSource.h
│ │ ├── IGListAdapterDelegate.h
│ │ ├── IGListAdapterDelegateAnnouncer.h
│ │ ├── IGListAdapterDelegateAnnouncer.m
│ │ ├── IGListAdapterMoveDelegate.h
│ │ ├── IGListAdapterPerformanceDelegate.h
│ │ ├── IGListAdapterUpdateListener.h
│ │ ├── IGListAdapterUpdater.h
│ │ ├── IGListAdapterUpdater.m
│ │ ├── IGListAdapterUpdaterDelegate.h
│ │ ├── IGListBatchContext.h
│ │ ├── IGListBindable.h
│ │ ├── IGListBindingSectionController.h
│ │ ├── IGListBindingSectionController.m
│ │ ├── IGListBindingSectionControllerDataSource.h
│ │ ├── IGListBindingSectionControllerSelectionDelegate.h
│ │ ├── IGListBindingSingleSectionController.h
│ │ ├── IGListBindingSingleSectionController.m
│ │ ├── IGListCollectionContext.h
│ │ ├── IGListCollectionScrollingTraits.h
│ │ ├── IGListCollectionView.h
│ │ ├── IGListCollectionView.m
│ │ ├── IGListCollectionViewDelegateLayout.h
│ │ ├── IGListCollectionViewLayout.h
│ │ ├── IGListCollectionViewLayout.mm
│ │ ├── IGListCollectionViewLayoutCompatible.h
│ │ ├── IGListCollectionViewLayoutInvalidationContext.h
│ │ ├── IGListCollectionViewLayoutInvalidationContext.m
│ │ ├── IGListDisplayDelegate.h
│ │ ├── IGListGenericSectionController.h
│ │ ├── IGListGenericSectionController.m
│ │ ├── IGListKit.h
│ │ ├── IGListReloadDataUpdater.h
│ │ ├── IGListReloadDataUpdater.m
│ │ ├── IGListScrollDelegate.h
│ │ ├── IGListSectionController.h
│ │ ├── IGListSectionController.m
│ │ ├── IGListSingleSectionController.h
│ │ ├── IGListSingleSectionController.m
│ │ ├── IGListSupplementaryViewSource.h
│ │ ├── IGListTransitionData.h
│ │ ├── IGListTransitionData.m
│ │ ├── IGListTransitionDelegate.h
│ │ ├── IGListUpdatingDelegate.h
│ │ ├── IGListWorkingRangeDelegate.h
│ │ ├── Internal/
│ │ │ ├── IGListAdapter+DebugDescription.h
│ │ │ ├── IGListAdapter+DebugDescription.m
│ │ │ ├── IGListAdapter+UICollectionView.h
│ │ │ ├── IGListAdapter+UICollectionView.m
│ │ │ ├── IGListAdapterDelegateAnnouncerInternal.h
│ │ │ ├── IGListAdapterInternal.h
│ │ │ ├── IGListAdapterProxy.h
│ │ │ ├── IGListAdapterProxy.m
│ │ │ ├── IGListAdapterUpdater+DebugDescription.h
│ │ │ ├── IGListAdapterUpdater+DebugDescription.m
│ │ │ ├── IGListAdapterUpdaterHelpers.h
│ │ │ ├── IGListAdapterUpdaterHelpers.m
│ │ │ ├── IGListAdapterUpdaterInternal.h
│ │ │ ├── IGListArrayUtilsInternal.h
│ │ │ ├── IGListArrayUtilsInternal.m
│ │ │ ├── IGListBatchUpdateData+DebugDescription.h
│ │ │ ├── IGListBatchUpdateData+DebugDescription.m
│ │ │ ├── IGListBatchUpdateState.h
│ │ │ ├── IGListBatchUpdateTransaction.h
│ │ │ ├── IGListBatchUpdateTransaction.m
│ │ │ ├── IGListBindingSectionController+DebugDescription.h
│ │ │ ├── IGListBindingSectionController+DebugDescription.m
│ │ │ ├── IGListCollectionViewLayoutInternal.h
│ │ │ ├── IGListDataSourceChangeTransaction.h
│ │ │ ├── IGListDataSourceChangeTransaction.m
│ │ │ ├── IGListDebugger.h
│ │ │ ├── IGListDebugger.m
│ │ │ ├── IGListDebuggingUtilities.h
│ │ │ ├── IGListDebuggingUtilities.m
│ │ │ ├── IGListDefaultExperiments.h
│ │ │ ├── IGListDisplayHandler.h
│ │ │ ├── IGListDisplayHandler.m
│ │ │ ├── IGListItemUpdatesCollector.h
│ │ │ ├── IGListItemUpdatesCollector.m
│ │ │ ├── IGListPerformDiff.h
│ │ │ ├── IGListPerformDiff.m
│ │ │ ├── IGListReloadIndexPath.h
│ │ │ ├── IGListReloadIndexPath.m
│ │ │ ├── IGListReloadTransaction.h
│ │ │ ├── IGListReloadTransaction.m
│ │ │ ├── IGListSectionControllerInternal.h
│ │ │ ├── IGListSectionMap+DebugDescription.h
│ │ │ ├── IGListSectionMap+DebugDescription.m
│ │ │ ├── IGListSectionMap.h
│ │ │ ├── IGListSectionMap.m
│ │ │ ├── IGListUpdateCoalescer.h
│ │ │ ├── IGListUpdateCoalescer.m
│ │ │ ├── IGListUpdateTransactable.h
│ │ │ ├── IGListUpdateTransactionBuilder.h
│ │ │ ├── IGListUpdateTransactionBuilder.m
│ │ │ ├── IGListViewVisibilityTracker.h
│ │ │ ├── IGListViewVisibilityTracker.m
│ │ │ ├── IGListViewVisibilityTrackerInternal.h
│ │ │ ├── IGListWorkingRangeHandler.h
│ │ │ ├── IGListWorkingRangeHandler.mm
│ │ │ ├── UICollectionView+DebugDescription.h
│ │ │ ├── UICollectionView+DebugDescription.m
│ │ │ ├── UICollectionView+IGListBatchUpdateData.h
│ │ │ ├── UICollectionView+IGListBatchUpdateData.m
│ │ │ ├── UICollectionViewLayout+InteractiveReordering.h
│ │ │ ├── UICollectionViewLayout+InteractiveReordering.m
│ │ │ ├── UIScrollView+IGListKit.h
│ │ │ ├── UIScrollView+IGListKit.m
│ │ │ └── UIViewController+IGListAdapterInternal.h
│ │ ├── UIViewController+IGListAdapter.h
│ │ └── UIViewController+IGListAdapter.m
│ ├── IGListSwiftKit/
│ │ ├── IGListAdapter+Async.swift
│ │ ├── IGListCollectionContext+Refinements.swift
│ │ ├── IGListSingleSectionController+Refinements.swift
│ │ ├── IGListSwiftKit.h
│ │ ├── ListIdentifiable.swift
│ │ └── ListValueSectionController.swift
│ └── Info.plist
├── Tests/
│ ├── Assets/
│ │ ├── IGTestNibCell.xib
│ │ ├── IGTestNibSupplementaryView.xib
│ │ └── IGTestStoryboard.storyboard
│ ├── IGListAdapterDelegateAnnouncerTests.m
│ ├── IGListAdapterE2ETests.m
│ ├── IGListAdapterProxyTests.m
│ ├── IGListAdapterStoryboardTests.m
│ ├── IGListAdapterTests.m
│ ├── IGListAdapterUpdaterTests.m
│ ├── IGListBatchUpdateDataTests.m
│ ├── IGListBindingSectionControllerTests.m
│ ├── IGListBindingSingleSectionControllerTests.m
│ ├── IGListCollectionScrollingTraitsTests.m
│ ├── IGListCollectionViewLayoutTests.m
│ ├── IGListCollectionViewTests.m
│ ├── IGListContentInsetTests.m
│ ├── IGListDebugDescriptionTests.m
│ ├── IGListDebuggerTests.m
│ ├── IGListDiffDescriptionStringTests.m
│ ├── IGListDiffResultTests.m
│ ├── IGListDiffSwiftTests.swift
│ ├── IGListDiffTests.h
│ ├── IGListDiffTests.m
│ ├── IGListDisplayHandlerTests.m
│ ├── IGListGenericSectionControllerTests.m
│ ├── IGListInteractiveMovingTests.m
│ ├── IGListItemUpdatesCollectorTests.m
│ ├── IGListKitTests-Bridging-Header.h
│ ├── IGListPerformDiffTests.m
│ ├── IGListReloadDataUpdaterTests.m
│ ├── IGListSectionControllerTests.m
│ ├── IGListSectionMapTests.m
│ ├── IGListSingleNibItemControllerTests.m
│ ├── IGListSingleSectionControllerTests.m
│ ├── IGListSingleStoryboardItemControllerTests.m
│ ├── IGListTestCase.h
│ ├── IGListTestCase.m
│ ├── IGListTestHelpers.h
│ ├── IGListTransactionTests.m
│ ├── IGListUpdateCoalescerTests.m
│ ├── IGListViewVisibilityTrackerTests.m
│ ├── IGListWorkingRangeHandlerTests.m
│ ├── Info.plist
│ ├── Objects/
│ │ ├── IGLayoutTestDataSource.h
│ │ ├── IGLayoutTestDataSource.m
│ │ ├── IGLayoutTestItem.h
│ │ ├── IGLayoutTestItem.m
│ │ ├── IGLayoutTestSection.h
│ │ ├── IGLayoutTestSection.m
│ │ ├── IGListAdapterUpdateTester.h
│ │ ├── IGListAdapterUpdateTester.m
│ │ ├── IGListTestAdapterDataSource.h
│ │ ├── IGListTestAdapterDataSource.m
│ │ ├── IGListTestAdapterHorizontalDataSource.h
│ │ ├── IGListTestAdapterHorizontalDataSource.m
│ │ ├── IGListTestAdapterReorderingDataSource.h
│ │ ├── IGListTestAdapterReorderingDataSource.m
│ │ ├── IGListTestAdapterStoryboardDataSource.h
│ │ ├── IGListTestAdapterStoryboardDataSource.m
│ │ ├── IGListTestCollectionViewLayout.h
│ │ ├── IGListTestCollectionViewLayout.m
│ │ ├── IGListTestContainerSizeSection.h
│ │ ├── IGListTestContainerSizeSection.m
│ │ ├── IGListTestHorizontalSection.h
│ │ ├── IGListTestHorizontalSection.m
│ │ ├── IGListTestOffsettingLayout.h
│ │ ├── IGListTestOffsettingLayout.m
│ │ ├── IGListTestSection.h
│ │ ├── IGListTestSection.m
│ │ ├── IGListTestStoryboardSection.h
│ │ ├── IGListTestStoryboardSection.m
│ │ ├── IGListTestUICollectionViewDataSource.h
│ │ ├── IGListTestUICollectionViewDataSource.m
│ │ ├── IGTestBindingSingleItemDataSource.h
│ │ ├── IGTestBindingSingleItemDataSource.m
│ │ ├── IGTestBindingWithoutDeselectionDelegate.h
│ │ ├── IGTestBindingWithoutDeselectionDelegate.m
│ │ ├── IGTestCell.h
│ │ ├── IGTestCell.m
│ │ ├── IGTestDelegateController.h
│ │ ├── IGTestDelegateController.m
│ │ ├── IGTestDelegateDataSource.h
│ │ ├── IGTestDelegateDataSource.m
│ │ ├── IGTestDiffingDataSource.h
│ │ ├── IGTestDiffingDataSource.m
│ │ ├── IGTestDiffingObject.h
│ │ ├── IGTestDiffingObject.m
│ │ ├── IGTestDiffingSectionController.h
│ │ ├── IGTestDiffingSectionController.m
│ │ ├── IGTestInvalidateLayoutDataSource.h
│ │ ├── IGTestInvalidateLayoutDataSource.m
│ │ ├── IGTestInvalidateLayoutObject.h
│ │ ├── IGTestInvalidateLayoutObject.m
│ │ ├── IGTestInvalidateLayoutSectionController.h
│ │ ├── IGTestInvalidateLayoutSectionController.m
│ │ ├── IGTestNibSupplementaryView.h
│ │ ├── IGTestNibSupplementaryView.m
│ │ ├── IGTestNumberBindableCell.h
│ │ ├── IGTestNumberBindableCell.m
│ │ ├── IGTestObject.h
│ │ ├── IGTestObject.m
│ │ ├── IGTestReorderableSection.h
│ │ ├── IGTestReorderableSection.m
│ │ ├── IGTestSingleItemDataSource.h
│ │ ├── IGTestSingleItemDataSource.m
│ │ ├── IGTestSingleNibItemDataSource.h
│ │ ├── IGTestSingleNibItemDataSource.m
│ │ ├── IGTestSingleStoryboardItemDataSource.h
│ │ ├── IGTestSingleStoryboardItemDataSource.m
│ │ ├── IGTestSingleWithoutDeselectionDelegate.h
│ │ ├── IGTestSingleWithoutDeselectionDelegate.m
│ │ ├── IGTestStoryboardCell.h
│ │ ├── IGTestStoryboardCell.m
│ │ ├── IGTestStoryboardSupplementarySource.h
│ │ ├── IGTestStoryboardSupplementarySource.m
│ │ ├── IGTestStoryboardSupplementaryView.h
│ │ ├── IGTestStoryboardSupplementaryView.m
│ │ ├── IGTestStoryboardViewController.h
│ │ ├── IGTestStoryboardViewController.m
│ │ ├── IGTestStringBindableCell.h
│ │ ├── IGTestStringBindableCell.m
│ │ ├── IGTestSupplementarySource.h
│ │ └── IGTestSupplementarySource.m
│ └── UIViewControllerIGListAdapterTests.m
├── docs/
│ ├── Categories/
│ │ └── UIViewController(IGListAdapter).html
│ ├── Categories.html
│ ├── Classes/
│ │ ├── IGListAdapter.html
│ │ ├── IGListAdapterDelegateAnnouncer.html
│ │ ├── IGListAdapterUpdater.html
│ │ ├── IGListBatchUpdateData.html
│ │ ├── IGListBindingSectionController.html
│ │ ├── IGListBindingSingleSectionController.html
│ │ ├── IGListCollectionView.html
│ │ ├── IGListCollectionViewLayout.html
│ │ ├── IGListCollectionViewLayoutInvalidationContext.html
│ │ ├── IGListGenericSectionController.html
│ │ ├── IGListIndexPathResult.html
│ │ ├── IGListIndexSetResult.html
│ │ ├── IGListMoveIndex.html
│ │ ├── IGListMoveIndexPath.html
│ │ ├── IGListSectionController.html
│ │ ├── IGListSingleSectionController.html
│ │ └── IGListTransitionData.html
│ ├── Classes.html
│ ├── Constants.html
│ ├── Enums/
│ │ ├── IGListAdapterUpdateType.html
│ │ ├── IGListDiffOption.html
│ │ └── IGListExperiment.html
│ ├── Enums.html
│ ├── Functions.html
│ ├── Guides.html
│ ├── Protocols/
│ │ ├── IGListAdapterDataSource.html
│ │ ├── IGListAdapterDelegate.html
│ │ ├── IGListAdapterMoveDelegate.html
│ │ ├── IGListAdapterPerformanceDelegate.html
│ │ ├── IGListAdapterUpdateListener.html
│ │ ├── IGListAdapterUpdaterDelegate.html
│ │ ├── IGListBatchContext.html
│ │ ├── IGListBindable.html
│ │ ├── IGListBindingSectionControllerDataSource.html
│ │ ├── IGListBindingSectionControllerSelectionDelegate.html
│ │ ├── IGListCollectionContext.html
│ │ ├── IGListCollectionViewDelegateLayout.html
│ │ ├── IGListCollectionViewLayoutCompatible.html
│ │ ├── IGListDiffable.html
│ │ ├── IGListDisplayDelegate.html
│ │ ├── IGListScrollDelegate.html
│ │ ├── IGListSingleSectionControllerDelegate.html
│ │ ├── IGListSupplementaryViewSource.html
│ │ ├── IGListTransitionDelegate.html
│ │ ├── IGListUpdatingDelegate.html
│ │ └── IGListWorkingRangeDelegate.html
│ ├── Protocols.html
│ ├── Structs/
│ │ ├── IGListAdaptiveCoalescingExperimentConfig.html
│ │ ├── IGListAdaptiveDiffingExperimentConfig.html
│ │ └── IGListCollectionScrollingTraits.html
│ ├── Structs.html
│ ├── Type Definitions/
│ │ ├── IGListAdaptiveCoalescingExperimentConfig/
│ │ │ └── IGListAdaptiveCoalescingExperimentConfig.html
│ │ ├── IGListAdaptiveCoalescingExperimentConfig.html
│ │ ├── IGListAdaptiveDiffingExperimentConfig/
│ │ │ └── IGListAdaptiveDiffingExperimentConfig.html
│ │ ├── IGListAdaptiveDiffingExperimentConfig.html
│ │ ├── IGListCollectionScrollingTraits/
│ │ │ └── IGListCollectionScrollingTraits.html
│ │ └── IGListCollectionScrollingTraits.html
│ ├── Type Definitions.html
│ ├── best-practices-and-faq.html
│ ├── css/
│ │ ├── highlight.css
│ │ └── jazzy.css
│ ├── generating-your-models-using-remodel.html
│ ├── getting-started.html
│ ├── iglistdiffable-and-equality.html
│ ├── index.html
│ ├── installation.html
│ ├── js/
│ │ ├── jazzy.js
│ │ ├── jazzy.search.js
│ │ └── typeahead.jquery.js
│ ├── migration.html
│ ├── modeling-and-binding.html
│ ├── search.json
│ ├── undocumented.json
│ ├── vision.html
│ ├── working-with-core-data.html
│ └── working-with-uicollectionview.html
├── remodel-plugin/
│ ├── features/
│ │ └── iglistdiffable.feature
│ └── src/
│ ├── __tests__/
│ │ └── plugins/
│ │ └── iglistdiffable-test.ts
│ └── plugins/
│ ├── iglistdiffable-utils.ts
│ └── iglistdiffable.ts
└── scripts/
├── build_docs.sh
├── generate_spm_sources_layout.sh
├── lint.sh
└── version.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to IGListKit
We want to make contributing to this project as easy and transparent as
possible, and actively welcome your pull requests. If you run into problems,
please open an issue on GitHub.
## Pull Requests
1. Fork the repo and create your branch from `main`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints.
6. If you haven't already, complete the Contributor License Agreement ("CLA").
7. Add an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
## Experimental changes
If your change can't be unit tested, we might ask that you add your change as an experiment so that we can verify your change works. To do this, first add a new option to [IGListExperiment](https://github.com/Instagram/IGListKit/blob/main/Source/Common/IGListExperiments.h#L17).
Then, use an `experiments` bitmask wherever your change is and wrap it in a check to see if it is enabled:
```swift
IGListExperimentEnabled(self.experiments, IGListExperimentMyAwesomeChange) {
// your code here
}
```
Once your experiment is confirmed we will remove the option and wrapping check!
## How we do major and minor releases
Everything merges into `main`. When we cut a release, we merge from `main` into `stable`, tag, and push to CocoaPods.
*Example:*
If current release is `2.1.0`, then any commits for `2.2.0` go into `stable` while commits for `3.0` would go to `main`.
## Testing
Keep in mind that we want 99% test coverage at all times. If you add new code, please make sure it gets tested! When fixing bugs, try to reproduce the bug in a unit test and then fix the test. This makes sure we never regress that issue again.
## Contributor License Agreement ("CLA")
In order to accept your pull request, we need you to submit a CLA. You only need
to do this once to work on any of Facebook's open source projects.
Complete your CLA here: <https://code.facebook.com/cla>
## Issues
We use GitHub issues to track public bugs. Please ensure your description is
clear and has sufficient instructions to be able to reproduce the issue.
Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
disclosure of security bugs. In those cases, please go through the process
outlined on that page and do not file a public issue.
## Coding Style
* 4 spaces for indentation rather than tabs
* Public classes and methods must contain header documentation
* Use plain C functions instead of class methods whenever possible
* Restrict subclassing (`IGLK_SUBCLASSING_RESTRICTED` macro or `final` in Swift), unless the class is designed for subclassing.
* Use instance variables instead of properties
* Create local variables instead of repeatedly accessing properties like `self.property`. This results in a larger binary and extra `objc_msgSend(...)` calls.
## Updating Testing Dependencies
If you need a different version of one of the testing dependencies, you will need to first [install Cocoapods](https://guides.cocoapods.org/using/getting-started.html):
```
$ [sudo] gem install cocoapods
```
Then within the project directory, run `pod install` to update the dependency to that version.
## License
By contributing to `IGListKit`, you agree that your contributions will be licensed under the LICENSE file in the root directory of this source tree.
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
## New issue checklist
- [ ] I have reviewed the [`README`](https://github.com/Instagram/IGListKit/blob/main/README.md) and [documentation](http://instagram.github.io/IGListKit)
- [ ] I have searched [existing issues](https://github.com/Instagram/IGListKit/issues) and this is not a duplicate
- [ ] I have attempted to reproduce the issue and include an example project.
### General information
- `IGListKit` version:
- iOS version(s):
- CocoaPods/Carthage version:
- Xcode version:
- Devices/Simulators affected:
- Reproducible in the demo project? (Yes/No):
- Related issues:
### Debug information
```bash
# Please include debug logs using the following lldb command:
po [IGListDebugger dump]
```
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## Changes in this pull request
Issue fixed: #
### Checklist
- [ ] All tests pass. Demo project builds and runs.
- [ ] I added tests, an experiment, or detailed why my change isn't tested.
- [ ] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [ ] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/main/.github/CONTRIBUTING.md)
================================================
FILE: .github/RELEASE_CHECKLIST.md
================================================
# Release Checklist
Here are the steps for creating and publishing a new release for `IGListKit`.
- Final review and update of header docs and guides
- Final review of changelog
- Regenerate docs
- Update pod spec version
- Update xcodeproj version
- Run `pod install` on all examples (**must happen on FB internal** because of sync issues)
- Merge `main` into `stable` via cmd-line and push
- Confirm `stable` is `0|0` [ahead/behind](https://github.com/Instagram/IGListKit/branches)
- Create [GitHub release](https://github.com/Instagram/IGListKit/releases) from `stable`
- Paste changelog into GH release notes
- Publish GitHub release
- Run `pod lib lint`
- Push updated podspec: `pod trunk push IGListKit.podspec`
- Verify new release on [CocoaPods](https://cocoapods.org/pods/IGListKit)
- Tweet all the tweets
================================================
FILE: .github/workflows/CI.yml
================================================
name: "IGListKit CI"
on:
push:
branches:
- main
pull_request:
branches:
- '*'
jobs:
macOS:
name: Unit Test macOS
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
PROJECT_NAME: IGListKit.xcodeproj
SCHEME_NAME: IGListKit-macOS
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache RubyGems
uses: actions/cache@v3
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install ruby gems.
run: bundle install
- name: Run unit tests for macOS
run: |
set -o pipefail
xcodebuild build build-for-testing -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "platform=macOS" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
xcodebuild analyze test-without-building -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "platform=macOS" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
iOS:
name: Unit Test iOS
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
PROJECT_NAME: IGListKit.xcodeproj
SCHEME_NAME: IGListKit
strategy:
matrix:
destination: ["platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache RubyGems
uses: actions/cache@v3
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install ruby gems.
run: bundle install
- name: iOS - ${{ matrix.destination }}
run: |
set -o pipefail
xcodebuild build build-for-testing -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
xcodebuild analyze test-without-building -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
- name: Upload code coverage
run: bundle exec slather
env:
COVERAGE_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI_PULL_REQUEST: ${{ github.event.number }}
GIT_BRANCH: ${{ github.head_ref || github.ref_name }}
tvOS:
name: Unit Test tvOS
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
PROJECT_NAME: IGListKit.xcodeproj
SCHEME_NAME: IGListKit-tvOS
strategy:
matrix:
destination: ["platform=tvOS Simulator,name=Apple TV,OS=18.2"]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache RubyGems
uses: actions/cache@v3
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install ruby gems.
run: bundle install
- name: Run unit tests for tvOS
run: |
set -o pipefail
xcodebuild build build-for-testing -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
xcodebuild analyze test-without-building -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
CocoaPods:
name: CocoaPods Lint
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache RubyGems
uses: actions/cache@v3
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install ruby gems.
run: bundle install
- name: Run IGListDiffKit podspec lint
run: bundle exec pod lib lint IGListDiffKit.podspec --allow-warnings
- name: Run IGListKit podspec lint
run: bundle exec pod lib lint IGListKit.podspec --allow-warnings "--include-podspecs=IGListDiffKit.podspec"
- name: Run IGListSwiftKit podspec lint
run: bundle exec pod lib lint IGListSwiftKit.podspec --allow-warnings "--include-podspecs=*.podspec"
SPM-layout-generator:
name: Verify generate_spm_sources_layout.sh is not broken
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
PROJECT_NAME: IGListKit.xcodeproj
IOS_DESTINATION: "platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"
SPM_IG_LIST_DIFF_KIT_PUBLIC_HEADERS_PATH: "spm/Sources/IGListDiffKit/include"
SPM_IG_LIST_DIFF_KIT_SOURCES_PATH: "spm/Sources/IGListDiffKit"
SPM_IG_LIST_KIT_PUBLIC_HEADERS_PATH: "spm/Sources/IGListKit/include"
SPM_IG_LIST_KIT_SOURCES_PATH: "spm/Sources/IGListKit"
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Manually clean SPM Sources folder
run: |
rm -rf "${{ env.SPM_IG_LIST_DIFF_KIT_PUBLIC_HEADERS_PATH }}/*.*"
rm -rf "${{ env.SPM_IG_LIST_DIFF_KIT_SOURCES_PATH }}/*.*"
rm -rf "${{ env.SPM_IG_LIST_KIT_PUBLIC_HEADERS_PATH }}/*.*"
rm -rf "${{ env.SPM_IG_LIST_KIT_SOURCES_PATH }}/*.*"
- name: Regenerate SPM layout
run: sh scripts/generate_spm_sources_layout.sh
- name: Clean project's ${{ env.PROJECT_NAME }}
run: |
rm -rf "${{ env.PROJECT_NAME }}"
- name: Verify IGListKit can be build using Package.swift which was generated by 'scripts/generate_spm_sources_layout.sh'
run: xcodebuild -scheme "IGListKit" build -destination "${{ env.IOS_DESTINATION }}" | xcpretty
SPM-build-from-Package:
name: Verify SPM build by invoking `xcodebuild` on Package.swift
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
PROJECT_NAME: IGListKit.xcodeproj
IOS_DESTINATION: "platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"
strategy:
matrix:
schemeName: ["IGListDiffKit",
"IGListKit",
"IGListSwiftKit"]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Clean project's ${{ env.PROJECT_NAME }}
run: |
rm -rf "${{ env.PROJECT_NAME }}"
- name: Run ${{ matrix.schemeName}} using Package.swift
run: xcodebuild -scheme "${{ matrix.schemeName}}" build -destination "${{ env.IOS_DESTINATION }}" | xcpretty
Carthage-XCFramework:
name: Verify Carthage build XCFramework
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Carthage build framework
run: carthage build --no-skip-current --use-xcframeworks
Build-Examples:
name: Build Examples and UI tests.
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode.app
IOS_EXAMPLE_XCODEPROJ: Examples/Examples-iOS/IGListKitExamples.xcodeproj
TVOS_EXAMPLE_XCODEPROJ: Examples/Examples-tvOS/IGListKitExamples.xcodeproj
MACOS_EXAMPLE_XCODEPROJ: Examples/Examples-macOS/IGListKitExamples.xcodeproj
EXAMPLE_SCHEME: IGListKitExamples
strategy:
matrix:
iosDestination: ["platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"]
tvOSDestination: ["platform=tvOS Simulator,name=Apple TV 4K (3rd generation)"]
macOSDestination: ["platform=macOS"]
macCatalystDestination: ["platform=macOS,variant=Mac Catalyst"]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache RubyGems
uses: actions/cache@v3
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install ruby gems.
run: bundle install
- name: Preboot iOS Simulator
uses: futureware-tech/simulator-action@v2
with:
model: 'iPhone 16 Pro Max'
os_version: '=18.2'
- name: Build iOS Example - ${{ matrix.iosDestination }}
run: |
set -o pipefail
xcodebuild build build-for-testing -project "${{ env.IOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.iosDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c
- name: Run iOS Example's UI Tests - ${{ matrix.iosDestination }}
run: |
set -o pipefail
xcodebuild build test -project "${{ env.IOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.iosDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c
- name: Build tvOS Example - ${{ matrix.tvOSDestination }}
run: |
set -o pipefail
xcodebuild build -project "${{ env.TVOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.tvOSDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c
- name: Build macOS Example - ${{ matrix.macOSDestination }}
run: |
set -o pipefail
xcodebuild build -project "${{ env.MACOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.macOSDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c
- name: Build Mac Catalyst Example - ${{ matrix.macCatalystDestination }}
run: |
set -o pipefail
xcodebuild build -project "${{ env.IOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.macCatalystDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c
Danger:
name: Run Danger
if: github.event_name == 'pull_request'
runs-on: macos-14
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache RubyGems
uses: actions/cache@v3
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install ruby gems.
run: bundle install
- name: Run Danger
run: bundle exec danger --verbose
================================================
FILE: .gitignore
================================================
.DS_Store
Podfile.lock
Gemfile.lock
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xcuserstate
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
## Docs
docs/docsets/
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
Pods/
# Add this line if you want to avoid checking in source code from the Xcode workspace
*.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# Bundler
.bundle
vendor
# Jetbrains
.idea
================================================
FILE: .slather.yml
================================================
ci_service: github
coverage_service: coveralls
xcodeproj: IGListKit.xcodeproj
workspace: IGListKit.xcworkspace
scheme: IGListKit
source_directory: Source
ignore:
- ../**/*/Xcode*
- Tests/*
================================================
FILE: .swiftlint.yml
================================================
included:
- Examples
- Source/IGListSwiftKit
excluded:
- Pods
opt_in_rules:
- empty_count
- number_separator
- operator_usage_whitespace
- sorted_imports
- vertical_parameter_alignment_on_call
- overridden_super_call
disabled_rules:
- force_unwrapping
- comma
- line_length
force_cast: warning
force_try: warning
weak_delegate: error
type_body_length:
warning: 300
error: 400
file_length:
warning: 500
error: 1200
type_name:
min_length: 4
max_length:
warning: 40
error: 50
excluded: iPhone
identifier_name:
min_length:
error: 4
excluded:
- id
- url
- URL
- pk
- day
- map
- row
- nib
- GlobalAPIKey
- to
- obj
- str
- set
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji)
================================================
FILE: CHANGELOG.md
================================================
# CHANGELOG
The changelog for `IGListKit`. Also see the [releases](https://github.com/instagram/IGListKit/releases) on GitHub.
5.3.0 (Upcoming Release)
-----
5.2.0
-----
### Enhancements
- Added a more defensive check for NaN values in item bounds when applying layout attributes in `-[IGListCollectionViewLayout layoutAttributesForItemAtIndexPath:]`. Minqi Ma [(358fe894)](https://github.com/Instagram/IGListKit/commit/358fe894f2c66a14ac1eda7ba09a2de158373cd5)
- Improved assertion details in `IGListAdapter+UICollectionView.m`. [Maxime Ollivier](https://github.com/maxolls) [(7240131c)](https://github.com/Instagram/IGListKit/commit/7240131ceaa7784bfed60fdb9a623e3b7f4cdf5b)
- Formalized assertions that `IGListAdapterDelegateAnnouncer` is main-thread confined. Andrew Cuneo [(7dddb0d4)](https://github.com/Instagram/IGListKit/commit/7dddb0d4c83c14a3cade15a24a9df5b61f7a6836)
### Fixes
- An `EXC_BAD_ACCESS` crash in `IGListSectionMap.m` during `IGListAdapter` deallocation. [Hoà V. DINH](https://github.com/dinhvh) [(d1ddab8e)](https://github.com/Instagram/IGListKit/commit/d1ddab8e20fe8b3effc70dc878697e0f421f9a25)
- A crash where an index value provided to `-[IGListBindingSectionController sizeForItemAtIndex:]` was out of bounds. Kaur Ishnoor [(0a0b11bd)](https://github.com/Instagram/IGListKit/commit/0a0b11bdc81d96aa6525d558715bc46d91393711)
5.1.0
-----
### Breaking Changes
- Added methods to the `IGListAdapterDelegate` to include callback methods for any time a cell will appear or did disappear from the screen. This can be used in conjunction with the `IGListAdapterDelegateAnnouncer` to listen globally for cell lifecycle events. Any implementer of `IGListAdapterDelegate` must update to include these methods. [Jesse Seidman](https://github.com/jseidman95) [(fa50aa1c)](https://github.com/Instagram/IGListKit/commit/fa50aa1cf1be85940787e211d23eb5e7873dbf24), [(d1d6f9d5)](https://github.com/Instagram/IGListKit/commit/d1d6f9d52caef89efd11444161ac341266d36ccf), [(03049f74)](https://github.com/Instagram/IGListKit/commit/03049f742f46a6ac28abedd249d176cac4694990)
- Added `willCrash` delegate methods in order to capture incoming crashes in IGListKit for analysis. Any implementer of `IGListAdapterUpdaterDelegate` and/or `IGListUpdatingDelegate` must update to include these methods. [Hoà V. DINH](https://github.com/dinhvh) [(da1050ef)](https://github.com/Instagram/IGListKit/commit/da1050ef397c9cf38e88ac047196fe53fe6febb0)
### Enhancements
- Replaced CocoaPods with SPM as the new dependency manager of `IGListKit.xcodeproj` when running unit tests. [Tim Oliver](https://github.com/timoliver) [(2964f066)](https://github.com/Instagram/IGListKit/commit/2964f066a3b0ad533f2eeda71096caeb0b54500a)
- Added handling for new collection view cell dequeue behavior in iOS 18 [Maxime Ollivier](https://github.com/maxolls) [(4bad7d52)](https://github.com/Instagram/IGListKit/commit/4bad7d52604c695e48c0c161fed631aad8511449)
- Added support for Swift Concurrency [Mark Davis](https://instagram.com/m4rk) [(0ec2d52)](https://github.com/Instagram/IGListKit/commit/0ec2d526f35374dc0366024f8bb62aac4db1fd8d)
- Exposed an option to disable layout cache invalidation when new items are inserted [Constantine Fry](https://github.com/constantine-fry) [(700905e)](https://github.com/Instagram/IGListKit/commit/700905e628bf56abebce5bbdb0698ecade3c9842)
- Exposed `IGListCollectionViewLayoutInvalidationContext` as a public interface [(1560956)](https://github.com/Instagram/IGListKit/commit/1560956da3ce27e1816c641541dbdc616cf5ef56)
- Annotated main API classes with `NS_SWIFT_UI_ACTOR` in preparation of moving to Swift 6 [Cory Wilhite](https://github.com/corywilhite) [(a28d835)](https://github.com/Instagram/IGListKit/commit/a28d835b739af5136841622854b276d07cda7852)
- Added `autoDeselectEnabled` on `IGListAdapter` to free each section-controller from having to do this and avoid bugs [Maxime Ollivier](https://github.com/maxolls) [(fec6b0e)](https://github.com/Instagram/IGListKit/commit/fec6b0ef0f4a0224519b868cb51600ad3fdf6923)
- Added `associatedListAdapters` as a property of `UIViewController` to track `IGListAdapter` instances bound to that view controller. [Maxime Ollivier](https://github.com/maxolls) [(9c0ef52)](https://github.com/Instagram/IGListKit/commit/9c0ef5271583fadaa10fda6340794c20bcf609b2)
- Added assert when a section's `diffIdentifier` changed before an update starts, which could manifest in a few different crashes [Maxime Ollivier](https://github.com/maxolls) [(64ba471)](https://github.com/Instagram/IGListKit/commit/64ba4712012f074acbafa3fee05aefb28fa06fd2)
- Added support for iOS 13 Context Menus with `contextMenuConfigurationForItemAt` method. [Jérôme B.](https://github.com/jeromeboursier) [(23daf6d)](https://github.com/Instagram/IGListKit/commit/23daf6de7290198b775062d04906ba3019519ff0).
### Fixes
- A crash that could periodically occur when collection view layout attributes were `nil` [(6e91299)](https://github.com/Instagram/IGListKit/commit/6e9129978e0e3537aec53eea2d6909e45fe057f9)
- A crash that could occur when reloading the same cell index multiple times [Maxime Ollivier](https://github.com/maxolls) [(0c25779)](https://github.com/Instagram/IGListKit/commit/0c257795e4a6e448fb76b5f15ebc83a1afcbd272)
- A crash in `IGListCollectionViewLayout` that could occur if a nil `indexPath` value was provided [(5ee2207)](https://github.com/Instagram/IGListKit/commit/5ee22079822ef30d05366d58173b09e238b6e44b)
5.0.0
-----
### Breaking Changes
- Changed iOS deployment target to 11.0 and macOS deployment target to 10.13 [Kent Sutherland](https://github.com/ksuther) [(#1573)](https://github.com/Instagram/IGListKit/pull/1573)
- Removed unneeded diffing functions `IGListDiffExperiment(...)` and `IGListDiffPathsExperiment(...)`. [Maxime Ollivier](https://github.com/maxolls) [(254c041)](https://github.com/Instagram/IGListKit/commit/254c04196a6b906a155d8a1dd670c720500bed6c)
- `ListSectionController.collectionContext` and `ListGenericSectionController.object` are now implicitly-unwrapped optionals in Swift. [Nate Stedman](https://github.com/natestedman) [(a6526ce)](https://github.com/Instagram/IGListKit/commit/a6526ce097fe38de85459cd6a34d948ec8440db7)
- The argument of `IGListGenericSectionController`'s `-didUpdateToObject:` is now generic, not `id`. [Nate Stedman](https://github.com/natestedman) [(a6526ce)](https://github.com/Instagram/IGListKit/commit/a6526ce097fe38de85459cd6a34d948ec8440db7)
- Updated `IGListUpdatingDelegate`, including a new method to safely perform `[IGListAdapter setDataSource:]` and changes to `-performUpdateWithCollectionViewBlock` that allows section-controllers to be created before the diffing (and therefore use a more accurate `toObjects` array) [Maxime Ollivier](https://github.com/maxolls) [(43af883)](https://github.com/Instagram/IGListKit/commit/43af8838dfdcfc50b8145c56cfecb5f5ed9195a5)
```objc
// OLD
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
fromObjects:(nullable NSArray<id <IGListDiffable>> *)fromObjects
toObjectsBlock:(nullable IGListToObjectBlock)toObjectsBlock
animated:(BOOL)animated
objectTransitionBlock:(IGListObjectTransitionBlock)objectTransitionBlock
completion:(nullable IGListUpdatingCompletion)completion;
// NEW
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
animated:(BOOL)animated
sectionDataBlock:(IGListTransitionDataBlock)sectionDataBlock
applySectionDataBlock:(IGListTransitionDataApplyBlock)applySectionDataBlock
completion:(nullable IGListUpdatingCompletion)completion;
// NEW
- (void)performDataSourceChange:(IGListDataSourceChangeBlock)block;
```
- Removed `allowsBackgroundReloading` from `IGListAdapterUpdater` because it's causing performance issues and other bugs. [Maxime Ollivier](https://github.com/maxolls) [(032e1b0)](https://github.com/Instagram/IGListKit/commit/032e1b0b8367e68ef3015f0dc7dfe2f3ff2bae0c)
- Introducing `allowsBackgroundDiffing` on `IGListAdapterUpdater`! This property lets the updater perform the diffing on a background thread. Originally introduced by Ryan Nystrom a while back. [Maxime Ollivier](https://github.com/maxolls) [(9a11f6)](https://github.com/Instagram/IGListKit/commit/9a11f6b55f02a8a89494035fb17203655e454404)
- Updated `scrollToObject:` method in `IGListAdapter` to include a new parameter `additionalOffset` to handle shifting the final scroll position by some vertical or horizontal offset depending on the scroll direction. This allows the object to be shown at the correct position when it is scrolled to in a list with sticky headers. [Anna Tang](https://www.instagram.com/anna.likesfood/) [(f2166c3)](https://github.com/Instagram/IGListKit/commit/f2166c358b3ed0fb3e9dd55d2bed9b7fe7a6a05e)
```objc
// OLD
- (void)scrollToObject:(id)object
supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
scrollDirection:(UICollectionViewScrollDirection)scrollDirection
scrollPosition:(UICollectionViewScrollPosition)scrollPosition
animated:(BOOL)animated;
// NEW
- (void)scrollToObject:(id)object
supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
scrollDirection:(UICollectionViewScrollDirection)scrollDirection
scrollPosition:(UICollectionViewScrollPosition)scrollPosition
additionalOffset:(CGPoint)additionalOffset
animated:(BOOL)animated;
```
- Unshipped the `IGListExperimentSkipViewSectionControllerMap` experiment as it was no longer being used. [Maxime Ollivier](https://github.com/maxolls) [(99e24af)](https://github.com/Instagram/IGListKit/commit/99e24afbf872c0d858291084cfa45243f0c9a448)
- Unshipped the `IGListExperimentSkipPerformUpdateIfPossible` experiment since it wasn't considered safe enough. [Maxime Ollivier](https://github.com/maxolls) [(b3a22ad)](https://github.com/Instagram/IGListKit/commit/b3a22ad554995b3a869bb1b75369108e65bd867e)
### Enhancements
- Added `traitCollection` property to `IGListAdapter` in order to access the current trait collection of the underlying collection view. [Sash Zats](https://github.com/zats) [(53a96a9)](https://github.com/Instagram/IGListKit/commit/53a96a9896732ffeb2683953aa6bd23642743ec8)
- Added `viewForSupplementaryElementOfKind:atIndex:sectionController:` to `IGListAdapter`. [ryanmathews](https://www.instagram.com/_rmathews_/) [(c708a10)](https://github.com/Instagram/IGListKit/commit/c708a10757944f147110a31be661d015e9fc901c)
- Replaced usage of `method_exchangeImplementations` with `class_replaceMethod` for increased performance. [Saagar Jha](https://github.com/saagarjha) [(#1583)](https://github.com/Instagram/IGListKit/pull/1583)
- Added `shouldDeselectItemAtIndex:` to `IGListSectionController`. [bladeofky](https://github.com/bladeofky) [(b22a10e)](https://github.com/Instagram/IGListKit/commit/b22a10e47ffa87c79993ea19db7b52605e83ebbf)
- Added `shouldSelectItemAtIndex:` to `IGListSectionController`. [dirtmelon](https://github.com/dirtmelon) [(#1479)](https://github.com/Instagram/IGListKit/pull/1479)
- Added [Mac Catalyst](https://developer.apple.com/mac-catalyst/) support. [Petro Rovenskyy](https://github.com/3a4oT/) [(#1487)](https://github.com/Instagram/IGListKit/pull/1487)
- Introduce `IGListSwiftKit`, with Swift refinements for `dequeueReusableCellOfClass` methods. [Koen Punt](https://github.com/koenpunt) [(#1388)](https://github.com/Instagram/IGListKit/pull/1388).
- Added `APPLICATION_EXTENSION_API_ONLY` support for `IGListDiffKit` [Peter Meyers](https://github.com/pm-dev) [(#1422)](https://github.com/Instagram/IGListKit/pull/1422)
- Improved performance by deferring requesting objects from the `IGListAdapterDataSource` until just before diffing is executed. If n updates are coalesced into one, this results in just a single request for objects from the data source. Shipped with experiment `IGListExperimentDeferredToObjectCreation` from Ryan Nystrom. [Maxime Ollivier](https://github.com/maxolls) [(7fc4384)](https://github.com/Instagram/IGListKit/commit/7fc4384a786968027f529ad24b8d821f671d25af)
- Improved performance by using `reloadData` when there are too many diffing updates. Shipped with experiment `IGListExperimentReloadDataFallback` from Ryan Nystrom. [Maxime Ollivier](https://github.com/maxolls) [(86ecc60)](https://github.com/Instagram/IGListKit/commit/86ecc600856b4199f8a31359140753955f02b5a4)
- Small performance improvement by replacing `NSSet` with `NSArray` during the data update to avoid unnecessary hashing, especially when dealing with lots of large objects with non trivial hashes. [Maxime Ollivier](https://github.com/maxolls) [(c0cf10d)](https://github.com/Instagram/IGListKit/commit/c0cf10d84c0d41b5c02af3a9f3268e438b8e1e77)
- Lazy initialize the `-emptyViewForListAdapter:` [Maxime Ollivier](https://github.com/maxolls) [(29d4640)](https://github.com/Instagram/IGListKit/commit/29d464099782813113246da47cb9c7bf4676a311)
- Updated `IGListAdapterUpdater` to be safer, more performant, and better organized! [Maxime Ollivier](https://github.com/maxolls) [(247e7ca)](https://github.com/Instagram/IGListKit/commit/247e7cac6547d52dbabf0c6fdcb7fa38b00d0e0f)
- Safely handles `[IGListAdapter setDataSource:]` by also invalidating the `UICollectionView` data.
- Safely handles `[IGListAdapter setCollectionView:]` by cancelling on-going transactions.
- Safely handles returning nil `IGListSectionController` from `IGListAdapterDataSource` by dumping objects that don't have a controller before the diffing.
- Checks that the `UICollectionView` section count matches the `IGListAdapter` before committing the update, otherwise fallback to a reload.
- Schedules an update block (`dispatch_async`) only when needed, instead of scheduling on every single call to `-performUpdateWithCollectionViewBlock`.
- Wraps each update in a `transaction` that can be easily cancelled.
- Uses methods instead of blocks to make the callstack easier to read in crash reports.
- Unblocks `IGListExperimentBackgroundDiffing`
- The `IGListExperimentFixCrashOnReloadObjects` experiment succeeded and has officially been implemented into IGListKit. [Maxime Ollivier](https://github.com/maxolls) [(99e24af)](https://github.com/Instagram/IGListKit/commit/99e24afbf872c0d858291084cfa45243f0c9a448)
- Added `IGListExperimentKeepPointerToCollectionViewDataSource` experiment as a potential solution for certain crashes being periodically observed.
- Added `IGListExperimentDisableAnimationOnUpdates` experiment to optionally disable update animations in `IGListAdapter` instances. [(eeb5208)](https://github.com/Instagram/IGListKit/commit/eeb5208911fe340b39d2cc3231d1cd59df16e215)
### Fixes
- Don't crash if you use `IGListSectionController` without a subclass [Maxime Ollivier](https://github.com/maxolls) [(6ea2b91)](https://github.com/Instagram/IGListKit/commit/6ea2b91150040911bcbe4f98201e36035e26e47f)
- Testing crash fix when calling `-[IGListAdapter reloadObjects ...]` during an update [Maxime Ollivier](https://github.com/maxolls) [(cd3f84f)](https://github.com/Instagram/IGListKit/commit/cd3f84f22709dc6bd0153476372cade8167b9513)
- Repaired Swift Package Manager support. [Petro Rovenskyy](https://github.com/3a4oT/) [(#1487)](https://github.com/Instagram/IGListKit/pull/1487)
- `IGListCollectionViewLayout` should get the section/index counts via `UICollectionView` to stay in sync, instead of the `dataSource` [Maxime Ollivier](https://github.com/maxolls) [(677ce77)](https://github.com/Instagram/IGListKit/commit/677ce77ecad11850f61436681ee1d04a5e67e96a)
- Remove `[collectionView layoutIfNeeded]` before scrolling in `[IGListAdapter scrollToObject...]` to avoid creating off-screen cells. [Maxime Ollivier](https://github.com/maxolls) [(ea03bc9)](https://github.com/Instagram/IGListKit/commit/ea03bc959dcfdc5937655ca471135f874980f0ad)
- Remove `[collectionView layoutIfNeeded]` before updating in `[IGListAdapterUpdater performBatchUpdates...]` to fix occasional glitches. [Maxime Ollivier](https://github.com/maxolls) [(aca18c7)](https://github.com/Instagram/IGListKit/commit/aca18c747009c5d2c3825cf0af1ea1d214afba0c)
- Fixed `IGListAdapterUpdaterDelegate` by 1) calling `willReloadDataWithCollectionView` on fallback reloads and 2) making sure `willPerformBatchUpdatesWithCollectionView` is only called when performing a batch update. [Maxime Ollivier](https://github.com/maxolls) [(29bf582)](https://github.com/Instagram/IGListKit/commit/29bf582f479ddf6beb118abc83ba7a8ea87543b0)
- Fixed missing update when calling `performUpdatesAnimated` multiple times quickly and using the `reloadDataFallback()`. [Maxime Ollivier](https://github.com/maxolls) [(a70d2d7)](https://github.com/Instagram/IGListKit/commit/a70d2d70ae8975af5b00f93ae596589b42017c38)
- Request the `UICollectionView` until just-before we update. This way if the `UICollectionView` is changed between update-queue and execution, we guarantee the update is performed on the correct view. Ship with experiment `IGListExperimentGetCollectionViewAtUpdate` from Ryan Nystrom. [Maxime Ollivier](https://github.com/maxolls) [(34c935c)](https://github.com/Instagram/IGListKit/commit/34c935c1a5fee83283beece8f1c6b3d6344f275d)
- Fixed unsigned integer overflow handling in `IGListBatchUpdateData` [Jason Hsu](https://github.com/tuoxie007) [(#1299)](https://github.com/Instagram/IGListKit/pull/1299)
- Fixed when collection views wouldn't recalculate its layout when its bound changes. [Sash Zats](https://github.com/zats) [(d220f8a)](https://github.com/Instagram/IGListKit/commit/d220f8a73fa91fb8444398992b2667f24a38b7a7)
- Fixed when calling `invalidateLayout` on `IGListCollectionViewLayout` wouldn't perform layout recalculation. [Tim Oliver](https://github.com/timoliver) [(ffd51e6)](https://github.com/Instagram/IGListKit/commit/ffd51e6235c761b14c52ac657c69dd52ee7b321f)
4.0.0
-----
### Breaking Changes
- Added Swift annotation name to `IGListAdapterDelegate` which removes `IG` prefix. The new name for Swift clients is `ListAdapterDelegate`. [Andrea Antonioni](https://github.com/andreaantonioni) [(#1116)](https://github.com/Instagram/IGListKit/pull/1116)
- Remove support for iOS 8 [Ian Perry](https://github.com/iperry90) [(#1381)](https://github.com/Instagram/IGListKit/pull/1381)
- `IGListKit` has been split into `IGListKit` and `IGListDiffKit` for Xcode and Carthage builds. Cocoapods continues to use an all-inclusive `IGListKit` podspec. [Nate Stedman](https://github.com/natestedman) [(#1377)](https://github.com/Instagram/IGListKit/pull/1377)
- Remove `coalescanceTime` from IGListAdapterUpdate, since it increase crash rate. [Zhisheng Huang](https://github.com/lorixx) [(2f76e8c)](https://github.com/Instagram/IGListKit/commit/2f76e8ce684bf7cea75ee52f25d4ea0af3e0081b)
- All `IGListBindingSectionControllerSelectionDelegate` methods are now required. [Bofei Zhu](https://github.com/zhubofei) [(#1186)](https://github.com/Instagram/IGListKit/pull/1186)
- Renamed `[IGListAdapterUpdatingDelegate listAdapterUpdater:willPerformBatchUpdatesWithCollectionView:]` to `[IGListAdapterUpdatingDelegate listAdapterUpdater:willPerformBatchUpdatesWithCollectionView:fromObjects:toObjects:listIndexSetResult:]` to include more supporting info on updated objects. [Jeremy Cohen](https://github.com/jeremycohen) [(b200dda)](https://github.com/Instagram/IGListKit/commit/b200ddacf59547641d77e31d313566c78944a67b)
- Renamed `[IGListAdapterUpdatingDelegatelistAdapterUpdater:collectionView:willCrashWithException:fromObjects:toObjects:updates:]` to `[ IGListAdapterUpdatingDelegatelistAdapterUpdater:collectionView:willCrashWithException:fromObjects:toObjects:diffResult:updates:]` to include diff result info. [Zhisheng Huang](https://github.com/lorixx) [(039e77e)](https://github.com/Instagram/IGListKit/commit/039e77e3593251c8711497f76ab25857d641ecee)
- Remove `IGListStackedSectionController`. [Hanton Yang](https://github.com/hanton) [(#1355)](https://github.com/Instagram/IGListKit/pull/1355)
### Enhancements
- Added `IGListCollectionScrollingTraits` for exposing `UICollectionView` scrolling traits to section controllers via `IGListCollectionContext`. [Adam Stern](https://github.com/adamastern) [(b4c8ea1)](https://github.com/Instagram/IGListKit/commit/b4c8ea180f3bbda8b7995da758fbec58bf7214a8)
- `IGListBindingSectionController` no longer asserts when reloading the entire section. A warning message is now logged if the entire section is going to be reloaded. [Jeff Bailey](https://github.com/jeffbailey) [(#1213)](https://github.com/Instagram/IGListKit/pull/1213)
- Added `preferItemReloadsForSectionReloads` in IGListAdapterUpdater so that the item updates are invoked with the proper collectionView animation, instead of using the delete+insert section operation when the number of items is unchanged. [Zhisheng Huang](https://github.com/lorixx) [(f699ea0)](https://github.com/Instagram/IGListKit/commit/f699ea0e17a8cc6335285dc9f86fb80a0ad49700)
- Created `IGListAdapterPerformanceDelegate` for IGListAdapter to be able to measure how long some operations take across all section controllers. For example, how long it takes to dequeue a cell. [Maxime Ollivier](https://github.com/maxoll) [(4662454)](https://github.com/Instagram/IGListKit/commit/4662454c4aedbc5d3bed0cb386f2ef93de40ba51)
- Update CocoaPods integration to use the CocoaPods specs CDN [Koen Punt](https://github.com/koenpunt) [(#1386)](https://github.com/Instagram/IGListKit/pull/1386)
- Remove useless system version code [Kinarobin](https://github.com/kinarobin) [(#1386)](https://github.com/Instagram/IGListKit/pull/1396)
### Fixes
- Fixed bug with layouts inconsistency in `updateAnimated:completion` of IGListBindingSectionController. [Qinghua Hong](https://github.com/qhhonx) [(#1285)](https://github.com/Instagram/IGListKit/pull/1285)
- Fixed bug with `-[IGListAdapter scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:animated:]` where the content inset(bottom/right) of the collection view was incorrectly being applied to the final offset and was inconsistent with the content inset(top/left) of the collection view being applied. [Qinghua Hong](https://github.com/qhhonx) [(#1284)](https://github.com/Instagram/IGListKit/pull/1284)
- Fixed crash when the data source is nil before calling `-[IGListAdapterUpdater performUpdateWithCollectionViewBlock:fromObjects:toObjectsBlock:animated:objectTransitionBlock:completion:]`. [Zhisheng Huang](https://github.com/lorixx) [(6cdd112)](https://github.com/Instagram/IGListKit/commit/6cdd112790f13a683d3e061a7646f2c3549cc4dd)
- Experimental fix to get the `UICollectionView` for batch updating immediately before applying the update. [Ryan Nystrom](https://github.com/rnystrom) [(583efb9)](https://github.com/Instagram/IGListKit/commit/583efb936b0ba4d8beac0678b145aa5aff8ac12b)
- Fixed bug with `IGListDiff.mm` where arrays of `NSIndexPath`, instead of `NSIndexPath`, were incorrectly set as objects for the IndexPathMaps. [Bofei Zhu](https://github.com/zhubofei) [(#1205)](https://github.com/Instagram/IGListKit/pull/1205)
- `[IGListAdapterUpdater performBatchUpdatesWithCollectionViewBlock:]` and `[IGListAdapterUpdater performReloadDataWithCollectionViewBlock:]` clean state and run completion blocks if their `UICollectionView` is nil. [Brandon Darin](https://github.com/jbd1030) [(290d592)](https://github.com/Instagram/IGListKit/commit/290d592983713c3ef82eb4950ba773a0059563a2)
- Ensuring view models with duplicate diff identifiers are removed when view models are first requested by `IGListBindingSectionController` [Adam Stern](https://github.com/adamastern) [(a1ee4c1)](https://github.com/Instagram/IGListKit/commit/a1ee4c19f7a6cbd9899dba82deb5fb3ece669e9c)
- Fixed `[IGListAdapterUpdater reloadItemInCollectionView:fromIndexPath:toIndexPath:]` does not call delegate when not inside a batch update. [Bofei Zhu](https://github.com/zhubofei) [(#1211)](https://github.com/Instagram/IGListKit/pull/1211)
- Log instead of assert for duplicate diff identifiers to make code testable. [Adam Stern](https://github.com/adamastern) [(bee2178)](https://github.com/Instagram/IGListKit/commit/bee2178443ffcaff1d9135c4e094f74240433a62)
- Removed `nibName` argument from `IGListReusableViewIdentifier`. [Trung Duc](https://github.com/trungducc) [(#1223)](https://github.com/Instagram/IGListKit/issues/1223)
- Fixed crash when using `-[IGListCollectionContext dequeueReusableCellOfClass:withReuseIdentifier:forSectionController:atIndex:]` [Jeremy Lawrence](https://github.com/ziewvater) [(3b19cfb)](https://github.com/Instagram/IGListKit/commit/3b19cfb9d742d1fd97540bd8cf42c3552ab47de9)
- Added missing method override to `IGListBindingSectionController` that updates the internal `viewModels` array after moving a cell. [Dennis Müller](https://github.com/d3mueller) [(#1262)](https://github.com/Instagram/IGListKit/issues/1262)
- Fixed logic flaw in `[IGListCollectionViewLayout shouldInvalidateLayoutForBoundsChange:]`. [Allen Hsu](https://github.com/allenhsu) [(#1236)](https://github.com/Instagram/IGListKit/pull/1236)
- Fixed crash when calling `[UICollectionView layoutAttributesForSupplementaryElementOfKind...]` with `IGListCollectionViewLayout` and the section controller doesn't actually return a supplementary view [Maxime Ollivier](https://github.com/maxolls) [(cddb297)](https://github.com/Instagram/IGListKit/commit/cddb29799c5393f3c1a1ab7e9c072208e8c23225)
- Added `IGListExperimentAvoidLayoutOnScrollToObject` to avoid creating off-screen cells when calling `[IGListAdapter scrollToObject ...]`. [Maxime Ollivier](https://github.com/maxolls) [(6faddd9)](https://github.com/Instagram/IGListKit/commit/6faddd99c95428cf42bb38684464b458ef1455c0)
- Added `IGListExperimentFixIndexPathImbalance` to test fixing a crash when inserting and deleting the same NSIndexPath multiple times. [Maxime Ollivier](https://github.com/maxolls) [(7824698)](https://github.com/Instagram/IGListKit/commit/78246986108e7caf73111fe784057cc107ee67f1)
3.4.0
-----
### Enhancements
- Relicensed IGListKit to MIT. [Ryan Nystrom](https://github.com/rnystrom) [(000bc36)](https://github.com/Instagram/IGListKit/commit/000bc3691909f50649a5dfb098a5f2102c86385b)
- Experimental performance improvement from deferring `-[IGListAdapterDataSource objectsForListAdapter:]` calls until just before diffing. [Ryan Nystrom](https://github.com/rnystrom) [(3059c5e)](https://github.com/Instagram/IGListKit/commit/3059c5e6f5aeac73f112375d032677ae5f38342a)
3.3.0
-----
### Enhancements
- Add support for UICollectionView's interactive reordering in iOS 9+. Updates include `-[IGListSectionController canMoveItemAtIndex:]` to enable the behavior, `-[IGListSectionController moveObjectFromIndex:toIndex:]` called when items within a section controller were moved through reordering, `-[IGListAdapterDataSource listAdapter:moveObject:from:to]` called when section controllers themselves were reordered (only possible when all section controllers contain exactly 1 object), and `-[IGListUpdatingDelegate moveSectionInCollectionView:fromIndex:toIndex]` to enable custom updaters to conform to the reordering behavior. The update also includes two new examples `ReorderableSectionController` and `ReorderableStackedViewController` to demonstrate how to enable interactive reordering in your client app. [Jared Verdi](https://github.com/jverdi) [(#976)](https://github.com/Instagram/IGListKit/pull/976)
- 5x improvement to diffing performance when result is only inserts or deletes. [Ryan Nystrom](https://github.com/rnystrom) [(afd2d29)](https://github.com/Instagram/IGListKit/commit/afd2d29eecfac2231d2bcf815c76e844c98d838e)
- Can always show sticky header although section data is empty. [Marcus Wu](https://github.com/marcuswu0814) [(#1129)](https://github.com/Instagram/IGListKit/pull/1129)
- Added `-[IGListCollectionContext dequeueReusableCellOfClass:withReuseIdentifier:forSectionController:atIndex:]` to allow for registering cells of the same class with different reuse identifiers. [Jeremy Lawrence](https://github.com/Ziewvater) [(f47753e)](https://github.com/Instagram/IGListKit/commit/f47753e3615431f3b079eb3b7900469f9ffdce5b)
### Fixes
- Fixed Xcode 9.3 build errors. [Sho Ikeda](https://github.com/ikesyo) [(#1143)](https://github.com/Instagram/IGListKit/pull/1143)
- Copy objects when retrieving from datasource to prevent modification of models in binding section controller. [Kashish Goel](https://github.com/kashishgoel) [(#1109)](https://github.com/Instagram/IGListKit/pull/1109)
- Fixed footer is sticky when `stickyHeader` is `true` [aelam](https://github.com/aelam) [(#1094)](https://github.com/Instagram/IGListKit/pull/1094)
- Updated IGListCollectionViewLayout to rely on layoutAttributesClass instead of vanilla `UICollectionViewLayoutAttributes` [Cole Potrocky](https://github.com/SirensOfTitan) [#1135](https://github.com/instagram/IGListKit/pull/1135)
- `-[IGListSectionController didSelectItemAtIndex:]` is now called when a `scrollViewDelegate` or `collectionViewDelegate` is set. [Ryan Nystrom](https://github.com/rnystrom) [(#1108)](https://github.com/Instagram/IGListKit/pull/1108)
- Fixed binding section controllers failing to update their cells when the section controller's section changes. [Chrisna Aing](https://github.com/ccrazy88) [(#1144)](https://github.com/Instagram/IGListKit/pull/1144)
- Fixed a bug caused when applying interactive reordering on a single section item while dragging it through the last spot of the collection view and back to some (non-last) target position. [Ofir Gluzman](https://github.com/ofirgluzman) [#1289](https://github.com/Instagram/IGListKit/pull/1289)
3.2.0
-----
### Enhancements
- Added `-[IGListSectionController didHighlightItemAtIndex:]` and `-[IGListSectionController didUnhighlightItemAtIndex:]` APIs to support `UICollectionView` cell highlighting. [Kevin Delannoy](https://github.com/delannoyk) [(#933)](https://github.com/Instagram/IGListKit/pull/933)
- Added `-didDeselectSectionController:withObject:` to `IGListSingleSectionControllerDelegate` [Darren Clark](https://github.com/darrenclark) [(#954)](https://github.com/Instagram/IGListKit/pull/954)
- Added a new listener API to be notified when `IGListAdapter` finishes updating. Add listeners via `-[IGListAdapter addUpdateListener:]` with objects conforming to the new `IGListAdapterUpdateListener` protocol. [Ryan Nystrom](https://github.com/rnystrom) [(5cf01cc)](https://github.com/Instagram/IGListKit/commit/5cf01cc0a7c41d370600df495aff91d1099fa0bc)
- Updated project settings for iOS 11. [Ryan Nystrom](https://github.com/rnystrom) [(#942)](https://github.com/Instagram/IGListKit/pull/942)
- Added support UICollectionElementKindSectionFooter for IGListCollectionViewLayout. [Igor Vasilenko](https://github.com/vasilenkoigor) [(#1017)](https://github.com/Instagram/IGListKit/pull/1017)
- Added experiment to make `-[IGListAdapter visibleSectionControllers:]` a bit faster. [Maxime Ollivier](https://github.com/maxoll) [(82a2a2e)](https://github.com/Instagram/IGListKit/commit/82a2a2ee18bb6272744fd14c64c8ff2da3a620a6)
- Added support `-[UIScrollView adjustedContentInset]` for iOS 11. [Guoyin Li](https://github.com/yiplee) [(#1020)](https://github.com/Instagram/IGListKit/pull/1020)
- Added new `transitionDelegate` API to give `IGListSectionController`s control to customize initial and final `UICollectionViewLayoutAttribute`s. Includes automatic integration with `IGListCollectionViewLayout`. Sue Suhan Ma [(26924ec)](https://github.com/Instagram/IGListKit/commit/26924ec3b665d37aeed7e28887e4221a7f3501b1)
- Reordered position of intercepted selector in `IGListAdapterProxy`'s `isInterceptedSelector` method to reduce overall consumption of compare. [zhongwuzw](https://github.com/zhongwu) [(#1055)](https://github.com/Instagram/IGListKit/pull/1055)
- Made IGListTransitionDelegate inherited from NSObject. [Igor Vasilenko](https://github.com/vasilenkoigor) [(#1075)](https://github.com/Instagram/IGListKit/pull/1075)
### Fixes
- Duplicate objects for initial data source setup filtered out. [Mikhail Vashlyaev](https://github.com/yemodin) [(#993](https://github.com/Instagram/IGListKit/pull/993)
- Weakly reference the `UICollectionView` in coalescence so that it can be released if the rest of system is destroyed. [Ryan Nystrom](https://github.com/rnystrom) [(d322c2e)](https://github.com/Instagram/IGListKit/commit/d322c2e5ae241141309923da257542f163c07cc6)
- Fix bug with `-[IGListAdapter scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:animated:]` where the content inset of the collection view was incorrectly being applied to the final offset. [Ryan Nystrom](https://github.com/rnystrom) [(b2860c3)](https://github.com/Instagram/IGListKit/commit/b2860c3604f0c452be1d21ab09c771c921786150)
- Avoid crash when invalidating the layout while inside `-[UICollectionView performBatchUpdates:completion:]. [Ryan Nystrom](https://github.com/rnystrom) [(d9a89c9)](https://github.com/Instagram/IGListKit/commit/d9a89c9b00aa1a9537a24d9affb6919f83065f65)
- Duplicate view models in `IGListBindingSectionController` gets filtered out. [Weyert de Boer](https://github.com/weyert) [(#916)](https://github.com/Instagram/IGListKit/pull/916)
- Check object type on lookup to prevent crossing types if different objects collide with their identifiers. [Ryan Nystrom](https://github.com/rnystrom) [(296baf5)](https://github.com/Instagram/IGListKit/commit/296baf5f854f57150ed12ca5bd8d3903db492734)
3.1.1
-----
### Fixes
- Prevent a crash when `IGListBindingSectionControllerDelegate` objects do not implement the optional deselection API. [Ryan Nystrom](https://github.com/rnystrom) [(#921)](https://github.com/Instagram/IGListKit/pull/921)
3.1.0
-----
### Enhancements
- Added debug descriptions for 'IGListBindingSectionController' when printing to lldb via `po [IGListDebugger dump]`. [Candance Smith](https://github.com/candance) [(#856)](https://github.com/Instagram/IGListKit/pull/856)
- Added `-[IGListSectionController didDeselectItemAtIndex:]` API to support default `UICollectionView` cell deselection. [Ryan Nystrom](https://github.com/rnystrom) [(6540f96)](https://github.com/Instagram/IGListKit/commit/6540f960e2e69bd4776e1e1d8c460ff812ba4c07)
- Added `-[IGListCollectionContext selectItemAtIndex:]` Select an item through IGListCollectionContext like `-[IGListCollectionContext deselectItemAtIndex:]`. [Marvin Nazari](https://github.com/MarvinNazari) [(#874)](https://github.com/Instagram/IGListKit/pull/874)
- Added horizontal scrolling support to `IGListCollectionViewLayout`. [Peter Edmonston](https://github.com/edmonston) [(#857)](https://github.com/Instagram/IGListKit/pull/857)
- Added support for `scrollViewDidEndDecelerating` to `IGListAdapter`. [Phil Larson](https://github.com/plarson) [(#899)](https://github.com/Instagram/IGListKit/pull/899)
- Automatically disable `[UICollectionView isPrefetchingEnabled]` when setting a collection view on an adapter. [Ryan Nystrom](https://github.com/rnystrom) [(#889)](https://github.com/Instagram/IGListKit/pull/889)
### Fixes
- Prevent a crash when update queued immediately after item batch update. [Ryan Nystrom](https://github.com/rnystrom) [(3dc6060)](https://github.com/Instagram/IGListKit/commit/3dc6060a385d9bfcb4fa1f61262ba74776573229)
- Return correct `-[IGListAdapter visibleSectionControllers]` when section has no items, but has supplementary views. [Mani Ghasemlou](https://github.com/manicakes) [(#643)](https://github.com/Instagram/IGListKit/issues/643)
- Call `[CATransaction commit]` before calling completion block in IGListAdapterUpdater to prevent animation issues. [Maxime Ollivier](https://github.com/maxoll) [(6f946b2)](https://github.com/Instagram/IGListKit/commit/6f946b2981d266f823324a366213bd214357bb6d)
- Fix `scrollToObject:supplementaryKinds:...` not scrolling when section is empty but does have supplymentary views. [Gulam Moledina](https://github.com/gmoledina) [(#808)](https://github.com/Instagram/IGListKit/pull/808)
- Better support for non-top positions in `scrollToObject:` API. [Gulam Moledina](https://github.com/gmoledina) [(#861)](https://github.com/Instagram/IGListKit/pull/861)
3.0.0
-----
This release closes the [3.0.0 milestone](https://github.com/Instagram/IGListKit/milestone/3).
### Breaking Changes
- Added Swift annotation names which remove `IG` prefixes from class names, C functions, and other APIs. Note, this only affects Swift clients. [Robert Payne](https://github.com/robertjpayne) [(#593)](https://github.com/Instagram/IGListKit/pull/593)
Example:
```swift
// OLD
class MySectionController : IGListSectionController { ... }
// NEW
class MySectionController : ListSectionController { ... }
// OLD
IGListDiff([], [], .equality)
// NEW
ListDiff(oldArray: [], newArray: [], .equality)
```
- Updated `didSelect` delegate call in `IGListSingleSectionControllerDelegate` to include object. [Sherlouk](https://github.com/Sherlouk) [(#397)](https://github.com/Instagram/IGListKit/pull/397)
```objc
// OLD
- (void)didSelectSingleSectionController:(IGListSingleSectionController *)sectionController;
// NEW
- (void)didSelectSectionController:(IGListSingleSectionController *)sectionController
withObject:(id)object;
```
- `IGListUpdatingDelegate` now conforms to `NSObject`, bringing it in line with other framework protocols. [Adlai Holler](https://github.com/Adlai-Holler) [(#435)](https://github.com/Instagram/IGListKit/pull/435)
- Changed `hasChanges` methods in `IGListIndexPathResult` and `IGListIndexSetResult` to read-only properties. [Bofei Zhu](https://github.com/zhubofei) [(#453)](https://github.com/Instagram/IGListKit/pull/453)
- Replaced `IGListGridCollectionViewLayout` with `IGListCollectionViewLayout`. [Ryan Nystrom](https://github.com/rnystrom) ([#482](https://github.com/Instagram/IGListKit/pull/482), [#450](https://github.com/Instagram/IGListKit/pull/450))
- Renamed `IGListAdapterUpdaterDelegate` method to `listAdapterUpdater:didPerformBatchUpdates:collectionView:`. [Vincent Peng](https://github.com/vincent-peng) [(#491)](https://github.com/Instagram/IGListKit/pull/491)
- Moved section controller mutations to `IGListBatchContext`, provided as a parameter when calling `-performBatchAnimated:updates:completion` on a section controller's `collectionContext`. All updates (insert, delete, reload item/section controller) must now be done inside a batch update block. [Ryan Nystrom](https://github.com/rnystrom) [(a15ea08)](https://github.com/Instagram/IGListKit/commit/a15ea0861492c8476bc9b1b92b0d9835814091c7)
```objc
// OLD
[self.collectionContext performBatchAnimated:YES updates:^{
self.expanded = YES;
[self.collectionContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:1]];
} completion:nil];
// NEW
[self.collectionContext performBatchAnimated:YES updates:^(id<IGListBatchContext> batchContext) {
self.expanded = YES;
[batchContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:1]];
} completion:nil];
// OLD
[self.collectionContext reloadSectionController:self];
// NEW
[self.collectionContext performBatchAnimated:YES updates:^(id<IGListBatchContext> batchContext) {
[batchContext reloadSectionController:self];
} completion:nil];
```
- `-[IGListCollectionContext containerSize]` no longer accounts for the content inset of the collection view when returning a size. If you require that behavior, you can now use `-[IGListCollectionContext insetContainerSize]`. [Ryan Nystrom](https://github.com/rnystrom) [(623ff2a)](https://github.com/Instagram/IGListKit/commit/623ff2a8a85e0e2e8d0331ae3250d67985cd06b6)
- `IGListCollectionView` has been **completely removed** in favor of using plain old `UICollectionView`. See discussion at [#409](https://github.com/Instagram/IGListKit/issues/409) for details. [Jesse Squires](https://github.com/jessesquires) [(2284ce3)](https://github.com/Instagram/IGListKit/commit/2284ce389708f62d99f48ff2ec15644f1ec59537)
- `IGListBatchUpdateData` replaced its `NSSet` properties with `NSArray` instead. [Ryan Nystrom](https://github.com/rnystrom) [(#616)](https://github.com/Instagram/IGListKit/pull/616)
- `IGListUpdatingDelegate` now requires method `-reloadItemInCollectionView:fromIndexPath:toIndexPath:` to handle reloading cells between index paths. [Ryan Nystrom](https://github.com/rnystrom) [(#657)](https://github.com/Instagram/IGListKit/pull/657)
- `-[IGListCollectionContext sectionForSectionController:]` has been removed and replaced with the `NSInteger sectionIndex` property on `IGListSectionController`. [Andrew Monshizadeh](https://github.com/amonshiz) [#671](http://github.com/Instagram/IGListKit/pull/671)
### Enhancements
- Added an initializer on `IGListAdapter` that does not take a `workingRangeSize` and defaults it to 0. [BasThomas](https://github.com/BasThomas) [(#686)](https://github.com/Instagram/IGListKit/pull/686)
- Added `-[IGListAdapter visibleCellsForObject:]` API. [Sherlouk](https://github.com/Sherlouk) [(#442)](https://github.com/Instagram/IGListKit/pull/442)
- Added `-[IGListAdapter sectionControllerForSection:]` API. [Adlai-Holler](https://github.com/Adlai-Holler) [(#477)](https://github.com/Instagram/IGListKit/pull/477)
- You can now manually move items (cells) within a section controller, ex: `[self.collectionContext moveInSectionController:self fromIndex:0 toIndex:1]`. [Ryan Nystrom](https://github.com/rnystrom) [(#418)](https://github.com/Instagram/IGListKit/pull/418)
- Invalidate the layout of a section controller and control the transition with `UIView` animation APIs. [Ryan Nystrom](https://github.com/rnystrom) [(#499)](https://github.com/Instagram/IGListKit/pull/499)
- Added `-[IGListAdapter visibleIndexPathsForSectionController:]` API. [Malecks](https://github.com/Malecks) [(#465)](https://github.com/Instagram/IGListKit/pull/465)
- Added `IGListBindingSectionController` which automatically binds view models to cells and animates updates at the cell level. [Ryan Nystrom](https://github.com/rnystrom) [(#494)](https://github.com/Instagram/IGListKit/pull/494)
- Added `IGListGenericSectionController` to take advantage of Objective-C (and Swift) generics and automatically store strongly-typed references to the object powering your section controller. [Ryan Nystrom](https://github.com/rnystrom) ([301f147](https://github.com/Instagram/IGListKit/commit/301f1471c9a7a802320e07890f5e98f15ada4e2e))
- Added a debug option for IGListKit that you can print to lldb via `po [IGListDebugger dump]`. [Ryan Nystrom](https://github.com/rnystrom) [(#617)](https://github.com/Instagram/IGListKit/pull/617)
### Fixes
- Gracefully handle a `nil` section controller returned by an `IGListAdapterDataSource`. [Ryan Nystrom](https://github.com/rnystrom) [(#488)](https://github.com/Instagram/IGListKit/pull/488)
- 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)
- Fix bug where `IGListStackedSectionController`'s children need to know `numberOrItems` before didUpdate is called. [(#348)](https://github.com/Instagram/IGListKit/pull/390)
- Fix bug where `-[UICollectionViewCell ig_setStackedSectionControllerIndex:]` should use `OBJC_ASSOCIATION_COPY_NONATOMIC` for NSNumber. [PhilCai](https://github.com/PhilCai1993) [(#424)](https://github.com/Instagram/IGListKit/pull/426)
- Fix potential bug with suppressing animations (by passing `NO`) during `-[IGListAdapter performUpdatesAnimated: completion:]` where user would see UI glitches/flashing. [Jesse Squires](https://github.com/jessesquires) [(019c990)](https://github.com/Instagram/IGListKit/commit/019c990312eea4203c7388a83b50685d426aa372)
- Fix bug where scroll position would be incorrect in call to `-[IGListAdapter scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:animated:` with scrollDirection/scrollPosition of UICollectionViewScrollDirectionVertical/UICollectionViewScrollPositionCenteredVertically or UICollectionViewScrollDirectionHorizontal/UICollectionViewScrollPositionCenteredHorizontally and with a collection view with nonzero contentInset. [David Yamnitsky](https://github.com/nitsky) [(5cc0fcd)](https://github.com/Instagram/IGListKit/commit/5cc0fcd1d77d6296f57ce1c298301b9881cb4d4a)
- Fix a crash when reusing collection views between embedded `IGListAdapter`s. [Ryan Nystrom](https://github.com/rnystrom) [(#517)](https://github.com/Instagram/IGListKit/pull/517)
- Only collect batch updates when explicitly inside the batch update block, execute them otherwise. Fixes dropped updates. [Ryan Nystrom](https://github.com/rnystrom) [(#494)](https://github.com/Instagram/IGListKit/pull/494)
- Remove objects that return `nil` diff identifiers before updating. [Ryan Nystrom](https://github.com/rnystrom) [(af984ca)](https://github.com/Instagram/IGListKit/commit/af984ca81d4d8c4ba3012be1a45f69670a832ccf)
- Fix a potential crash when a section is moved and deleted at the same time. [Ryan Nystrom](https://github.com/rnystrom) [(#577)](https://github.com/Instagram/IGListKit/pull/577)
- Prevent section controllers and supplementary sources from returning negative sizes that crash `UICollectionViewFlowLayout`. [Ryan Nystrom](https://github.com/rnystrom) [(#583)](https://github.com/Instagram/IGListKit/pull/583)
- Add nullability annotations to a few more headers. [Adlai Holler](https://github.com/Adlai-Holler) [(#626)](https://github.com/Instagram/IGListKit/pull/626)
- Fix a crash when inserting or deleting from the same index within the same batch-update application. [Ryan Nystrom](https://github.com/rnystrom) [(#616)](https://github.com/Instagram/IGListKit/pull/616)
- `IGListSectionType` protocol was removed and its methods were absorted into the `IGListSectionController` base class with default implementations. [Ryan Nystrom](https://github.com/rnystrom) ([3102852](https://github.com/Instagram/IGListKit/commit/3102852ce258274e8727f9094695a9c331e1abf3))
- When setting the collection view on `IGListAdapter`, its layout is now properly invalidated. [Jesse Squires](https://github.com/jessesquires) [(#677)](https://github.com/Instagram/IGListKit/pull/677)
- Fixes a bug when reusing `UICollectionView`s with multiple `IGListAdapter`s in an embedded environment that would accidentally `nil` the `collectionView` property of another adapter. [Ryan Nystrom](https://github.com/rnystrom) [(#721)](https://github.com/Instagram/IGListKit/pull/721)
- Fixes a bug where maintaining a reference to a section controller but not the list adapter in an async block could lead to calling `-[IGListAdapter sectionForSectionController:]` (or checking `-[IGListSectionController sectionIndex]`) and receiving an incorrect value. With the adapter check the value would be 0 because the adapter was `nil` and for the section controller property the value would be the last set index value. [Andrew Monshizadeh](https://github.com/amonshiz) [(#709)](https://github.com/Instagram/IGListKit/issues/709)
2.1.0
-----
This release closes the [2.1.0 milestone](https://github.com/Instagram/IGListKit/milestone/2).
### Enhancements
- Added support for macOS. Note: this is *only* for the Diffing components. There is **no support** for `IGListAdapter`, `IGListSectionController`, and other components at this time. [Guilherme Rambo](https://github.com/insidegui) [(#235)](https://github.com/Instagram/IGListKit/pull/235)
- Added a [macOS example](https://github.com/Instagram/IGListKit/tree/main/Examples/Examples-macOS) project. [Guilherme Rambo](https://github.com/insidegui) [(#337)](https://github.com/Instagram/IGListKit/pull/337)
- Disables `prefetchEnabled` by default on `IGListCollectionView`. [Sven Bacia](https://github.com/svenbacia) [(#323)](https://github.com/Instagram/IGListKit/pull/323)
- Working ranges now work with `IGListStackedSectionController`. [Ryan Nystrom](https://github.com/rnystrom) [(#356)](https://github.com/Instagram/IGListKit/pull/356)
- Added CocoaPods subspec for diffing, `IGListKit/Diffing` and an [installation guide](https://instagram.github.io/IGListKit/installation.html). [Sherlouk](https://github.com/Sherlouk) [(#368)](https://github.com/Instagram/IGListKit/pull/368)
- Added `allowsBackgroundReloading` flag (default `YES`) to `IGListAdapterUpdater` so users can configure this behavior as needed. [Adlai-Holler](https://github.com/Adlai-Holler) [(#375)](https://github.com/Instagram/IGListKit/pull/375)
- `-[IGListAdapter updater]` is now public (read-only). [Adlai-Holler](https://github.com/Adlai-Holler) [(#379)](https://github.com/Instagram/IGListKit/pull/379)
### Fixes
- Avoid `UICollectionView` crashes when queueing a reload and insert/delete on the same item as well as reloading an item in a section that is animating. [Ryan Nystrom](https://github.com/rnystrom) [(#325)](https://github.com/Instagram/IGListKit/pull/325)
- Prevent adapter data source from deallocating after queueing an update. [Ryan Nystrom](https://github.com/rnystrom) [(4cc91a2)](https://github.com/Instagram/IGListKit/commit/4cc91a25c8b262953e4f2d8e5dc78ee15c6265b2)
- Fix out-of-bounds bug when child section controllers in a stack remove cells. [Ryan Nystrom](https://github.com/rnystrom) [(#358)](https://github.com/Instagram/IGListKit/pull/358)
- Fix a grid layout bug when item has full-width and iter-item spacing is not zero. [Bofei Zhu](https://github.com/zhubofei) [(#361)](https://github.com/Instagram/IGListKit/pull/361)
2.0.0
-----
This release closes the [2.0.0 milestone](https://github.com/Instagram/IGListKit/milestone/1?closed=1). We've increased test coverage to 97%. Thanks to the [27 contributors](https://github.com/Instagram/IGListKit/graphs/contributors) who helped with this release!
You can find a [migration guide here](https://instagram.github.io/IGListKit/migration.html) to assist with migrating between 1.0 and 2.0.
### Breaking Changes
- Diff result method on `IGListIndexPathResult` changed. `-resultWithUpdatedMovesAsDeleteInserts` was removed and replaced with `-resultForBatchUpdates` [(b5aa5e3)](https://github.com/Instagram/IGListKit/commit/b5aa5e39002854c947e777c11ae241f67f24d19c)
```
// OLD
- (IGListIndexPathResult *)resultWithUpdatedMovesAsDeleteInserts;
// NEW
- (IGListIndexPathResult *)resultForBatchUpdates;
```
- `IGListDiffable` equality method changed from `isEqual:` to `isEqualToDiffableObject:` [(ab890fc)](https://github.com/Instagram/IGListKit/commit/ab890fc6070f170a2db5a383a6296e62dcf75678)
- The default `NSObject<IGListDiffable>` category was removed and replaced with `NSString<IGListDiffable>` and `NSNumber<IGListDiffable>` categories. All other models will need to conform to `IGListDiffable`. [(3947600)](https://github.com/Instagram/IGListKit/commit/394760081c7c2daa5ae6c18e00cdeaf2b67e22c1)
- Added support for specifying an end position when scrolling. [Bofei Zhu](https://github.com/zhubofei) [(#196)](https://github.com/Instagram/IGListKit/pull/196). The `IGListAdapter` scrolling method changed:
```objc
// OLD
- (void)scrollToObject:(id)object
supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
scrollDirection:(UICollectionViewScrollDirection)scrollDirection
animated:(BOOL)animated;
// NEW
- (void)scrollToObject:(id)object
supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
scrollDirection:(UICollectionViewScrollDirection)scrollDirection
scrollPosition:(UICollectionViewScrollPosition)scrollPosition
animated:(BOOL)animated;
```
### Fixes
- Consider supplementary views with display and end-display events. [Ryan Nystrom](https://github.com/rnystrom) [(#470)](https://github.com/Instagram/IGListKit/pull/470)
- Changed `NSUInteger` to `NSInteger` in all public APIs. [Suraya Shivji](https://github.com/surayashivji) [(#200)](https://github.com/Instagram/IGListKit/issues/200)
### Enhancements
- Added support for supplementaryViews created from nibs. [Rawlinxx](https://github.com/rawlinxx) [(#90)](https://github.com/Instagram/IGListKit/pull/90)
- Added support for cells created from nibs. [Sven Bacia](https://github.com/svenbacia) [(#56)](https://github.com/Instagram/IGListKit/pull/56)
- Added an additional initializer for `IGListSingleSectionController` to be able to support single sections created from nibs. An example can be found [here](https://github.com/Instagram/IGListKit/tree/main/Examples/Examples-iOS/IGListKitExamples/ViewControllers/SingleSectionViewController.swift). [(#56)](https://github.com/Instagram/IGListKit/pull/56)
```objc
- (instancetype)initWithNibName:(NSString *)nibName
bundle:(nullable NSBundle *)bundle
configureBlock:(IGListSingleSectionCellConfigureBlock)configureBlock
sizeBlock:(IGListSingleSectionCellSizeBlock)sizeBlock;
```
- Added `-isFirstSection` and `-isLastSection` APIs to `IGListSectionController` [(316fbe2)](https://github.com/Instagram/IGListKit/commit/316fbe2b8b2508b58a0f38387c3a343b9c37e282)
- Added support for cells and supplementaryViews created from storyboard. There's a new required method on the `IGListCollectionContext` protocol to do this. [Bofei Zhu](https://github.com/zhubofei) [(#92)](https://github.com/Instagram/IGListKit/pull/92)
```objc
// IGListCollectionContext
- (__kindof UICollectionViewCell *)dequeueReusableCellFromStoryboardWithIdentifier:(NSString *)identifier
forSectionController:(IGListSectionController<IGListSectionType> *)sectionController
atIndex:(NSInteger)index;
```
- Added `tvOS` support. [Jesse Squires](https://github.com/jessesquires) [(#137)](https://github.com/Instagram/IGListKit/pull/137)
- Added `-[IGListAdapter visibleObjects]` API. [Ryan Nystrom](https://github.com/rnystrom) [(386ae07)](https://github.com/Instagram/IGListKit/commit/386ae0786445c06e1eabf074a4181614332f155f)
- Added `-[IGListAdapter objectForSectionController:]` API. [Ayush Saraswat](https://github.com/saraswatayu) [(#204)](https://github.com/Instagram/IGListKit/pull/204)
- Added `IGListGridCollectionViewLayout`, a section-based grid layout. [Bofei Zhu](https://github.com/zhubofei) [(#225)](https://github.com/Instagram/IGListKit/pull/225)
- Added support for scrolling to an index in a section controller from within that section controller. There's a new required method on the `IGListCollectionContext` protocol to do this. [Jesse Squires](https://github.com/jessesquires) [(e5afb5b)](https://github.com/Instagram/IGListKit/commit/e5afb5b4d0cfc70a2736b02279b6bc239ddf1e5d)
```objc
// IGListCollectionContext
- (void)scrollToSectionController:(IGListSectionController<IGListSectionType> *)sectionController
atIndex:(NSInteger)index
scrollPosition:(UICollectionViewScrollPosition)scrollPosition
animated:(BOOL)animated;
```
### Fixes
- Fixed `-[IGListAdapter reloadDataWithCompletion:]` not returning early when `collectionView` or `dataSource` is `nil` and `completion` is `nil`. [Ben Asher](https://github.com/benasher44) [(#51)](https://github.com/Instagram/IGListKit/pull/51)
- Prevent `UICollectionView` bug when accessing a cell during working range updates. [Ryan Nystrom](https://github.com/rnystrom) [(#216)](https://github.com/Instagram/IGListKit/pull/216)
- Skip reloading for objects that are not found when calling `-[IGListAdapter reloadObjects:]`. [Ryan Nystrom](https://github.com/rnystrom) [(ca15e29)](https://github.com/Instagram/IGListKit/commit/ca15e29cf1dadc6c396fe8f14f16c27f6a38519c)
- Fixes a crash when a reload is queued for an object that is deleted in the same runloop turn. [Ryan Nystrom](https://github.com/rnystrom) [(7c3d499)](https://github.com/Instagram/IGListKit/commit/7c3d4999ebde36ee4666e5aee99716d1ed1fb2d8)
- Fixed a bug where `IGListStackSectionController` would only set its supplementary source once. [Ryan Nystrom](https://github.com/rnystrom) [(#286)](https://github.com/Instagram/IGListKit/pull/286)
- Fixed a bug where `IGListStackSectionController` passed the wrong section controller for will-drag scroll events. [Ryan Nystrom](https://github.com/rnystrom) [(#286)](https://github.com/Instagram/IGListKit/pull/286)
- Fixed a crash when deselecting a cell through a child section controller in an `IGListStackSectionController`. [Ryan Nystrom](https://github.com/rnystrom) [(#295)](https://github.com/Instagram/IGListKit/pull/295)
### Documentation
- We now have 100% documentation coverage. Docs been refined and clarified. [Jesse Squires](https://github.com/jessesquires) [(#207)](https://github.com/Instagram/IGListKit/pull/207)
- Added new Guides: [Getting Started](https://instagram.github.io/IGListKit/getting-started.html), [Migration](https://instagram.github.io/IGListKit/migration.html)
- Added examples for Today & iMessage extensions. [Sherlouk](https://github.com/Sherlouk) [(#112)](https://github.com/Instagram/IGListKit/pull/112)
- Added `tvOS` example pack. [Sherlouk](https://github.com/Sherlouk) [(#141)](https://github.com/Instagram/IGListKit/pull/141)
1.0.0
-----
Initial release. :tada:
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <opensource-conduct@fb.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: Dangerfile
================================================
not_declared_trivial = !(github.pr_title.include? "#trivial")
has_source_changes = !git.modified_files.grep(/Source/).empty?
# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]"
# Warn when there is a big PR
warn("Big PR") if git.lines_of_code > 500
# Changelog entries are required for changes to library files
no_changelog_entry = !git.modified_files.include?("CHANGELOG.md")
if has_source_changes && no_changelog_entry && not_declared_trivial && git.lines_of_code > 10
fail("Any source code changes should have an entry in CHANGELOG.md.")
end
# Milestones are required to track what's included in each release
if has_source_changes && not_declared_trivial
has_milestone = !github.pr_json['milestone'].nil?
warn('All pull requests should have a milestone attached, unless marked *#trivial*.', sticky: false) unless has_milestone
end
# Docs are regenerated when releasing
has_doc_changes = !git.modified_files.grep(/docs\//).empty?
has_doc_gen_title = github.pr_title.include? "#docgen"
if has_doc_changes && !has_doc_gen_title
fail("Docs are regenerated when creating new releases.")
message("Docs are generated by using [Jazzy](https://github.com/realm/jazzy). If you want to contribute, please update [markdown guides](https://github.com/Instagram/IGListKit/tree/main/Guides)")
end
# Warn if Source files were added or removed but examples are not updated
added_source_files = !git.added_files.grep(/Source/).empty?
deleted_source_files = !git.deleted_files.grep(/Source/).empty?
ios_pods_not_updated = !git.modified_files.include?("Examples/Examples-iOS/Podfile.lock")
macos_pods_not_updated = !git.modified_files.include?("Examples/Examples-macOS/Podfile.lock")
tvos_pods_not_updated = !git.modified_files.include?("Examples/Examples-tvOS/Podfile.lock")
if (added_source_files || deleted_source_files) && (ios_pods_not_updated || macos_pods_not_updated || tvos_pods_not_updated)
warn("Adding or removing library source files requires updating the examples. Please run `./scripts/pod_setup.sh` from the root directory and commit the changes.")
end
swiftlint.verbose = true
swiftlint.config_file = '.swiftlint.yml'
swiftlint.lint_files(inline_mode: true)
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/AppDelegate.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var isLaunched = false
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let demosViewController = DemosViewController()
let splitViewController = UISplitViewController()
splitViewController.delegate = self
splitViewController.viewControllers = [UINavigationController(rootViewController: demosViewController)]
splitViewController.preferredDisplayMode = .oneBesideSecondary
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = splitViewController
window?.makeKeyAndVisible()
UICollectionView.appearance().backgroundColor = UIColor.background
return true
}
}
extension AppDelegate: UISplitViewControllerDelegate {
func splitViewController(_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController) -> Bool {
// We set up 2 view controllers on launch to enable the split view controller when launching on iPad.
// However, for iPhone, discard the second view controller so the Demos view controller is visible at launch.
if !isLaunched {
isLaunched = true
return true
}
return false
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"filename" : "AppIcon.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="332-e4-q4q">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Navigation Controller-->
<scene sceneID="poO-K0-5eC">
<objects>
<navigationController id="332-e4-q4q" sceneMemberID="viewController">
<simulatedScreenMetrics key="simulatedDestinationMetrics"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="mqI-0B-dj6">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="g8o-Tr-qN9" kind="relationship" relationship="rootViewController" id="o4N-Oy-Tdk"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="JfD-hh-Oex" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-359" y="369"/>
</scene>
<!--View Controller-->
<scene sceneID="eSO-yw-CxQ">
<objects>
<viewController id="g8o-Tr-qN9" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="maR-va-yyC"/>
<viewControllerLayoutGuide type="bottom" id="tDB-f3-oGv"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="jgk-vn-mfX">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="fla-GE-9dz"/>
<simulatedScreenMetrics key="simulatedDestinationMetrics"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vae-Ar-iZP" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="67" y="369"/>
</scene>
</scenes>
</document>
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/DelegateProtocols/PostSectionControllerDelegate.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import UIKit
/// To allow communication between PostSectionController and FeedViewController
protocol PostSectionControllerDelegate: AnyObject {
func postSectionController(_ sectionController: PostSectionController, didSelectOptionsFor post: Post, from sourceView: UIView)
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Extensions/UIActivityIndicatorView+Extension.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import UIKit
extension UIActivityIndicatorView {
class var defaultStyle: UIActivityIndicatorView.Style {
if #available(iOS 13.0, *) {
return .medium
} else {
return .gray
}
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Extensions/UIColor+Extension.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import UIKit
extension UIColor {
class var background: UIColor {
if #available(iOS 13.0, *) {
return .systemBackground
} else {
return .white
}
}
class var groupedBackground: UIColor {
if #available(iOS 13.0, *) {
return .systemGroupedBackground
} else {
return .groupTableViewBackground
}
}
class var secondaryGroupedBackground: UIColor {
if #available(iOS 13.0, *) {
return .secondarySystemGroupedBackground
} else {
return .white
}
}
class var secondaryBackground: UIColor {
if #available(iOS 13.0, *) {
return .secondarySystemBackground
} else {
return .lightGray
}
}
class var defaultSeparator: UIColor {
if #available(iOS 13.0, *) {
return UIColor.separator
} else {
return UIColor(red: 200 / 255.0,
green: 199 / 255.0,
blue: 204 / 255.0,
alpha: 1)
}
}
class var titleLabel: UIColor {
if #available(iOS 13.0, *) {
return .label
} else {
return .darkText
}
}
class var detailLabel: UIColor {
if #available(iOS 13.0, *) {
return .secondaryLabel
} else {
return .lightGray
}
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/IGListKitExamples.entitlements
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>IGListKit</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<false/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
</dict>
</plist>
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/APIService.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import Foundation
// MARK: - Data Provider
// In IGListKit architecture, the data provider is separated from the UI components
// This enables clean separation of concerns and makes testing easier
class APIService {
static let shared = APIService()
// Pagination state
private var currentPage = 1
private var isLoading = false
private var hasMoreData = true
// Fetch posts with pagination support
// This is called by the view controller to load data
// IGListKit will handle the diffing and UI updates based on the results
func fetchPosts(completion: @escaping ([Post]) -> Void) {
guard !isLoading, hasMoreData else { return }
self.isLoading = true
// Simulate network delay
DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
let posts = self.generateMockPosts(page: self.currentPage)
if self.currentPage >= 5 {
self.hasMoreData = false
}
self.currentPage += 1
self.isLoading = false
DispatchQueue.main.async {
completion(posts)
}
}
}
// Reset pagination state for refreshing
func resetPagination() {
self.currentPage = 1
self.hasMoreData = true
}
// Generate mock data for the demo app
// In a real app, this would be replaced with API calls
func generateMockPosts(page: Int) -> [Post] {
let baseCount = (page - 1) * 5
return (1...5).map { index in
let id = "\(baseCount + index)"
return Post(
id: id,
username: "user\(Int.random(in: 100...999))",
userAvatarURL: URL(string: "https://randomuser.me/api/portraits/men/\(Int.random(in: 1...99)).jpg"),
imageURL: URL(string: "https://picsum.photos/id/\(baseCount + index + 10)/500/500"),
title: "Post #\(id)",
description: "This is a beautiful photo I took while traveling. What do you think? #travel #photography #nature",
likes: Int.random(in: 10...1000),
timeStamp: Date().addingTimeInterval(-Double(Int.random(in: 1...86400) * (baseCount + index)))
)
}
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/ActivityItem.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
final class ActivityItem: ListDiffable {
let bodyText: String
let header: String?
let footer: String?
init(bodyText: String, header: String? = nil, footer: String? = nil) {
self.bodyText = bodyText
self.header = header
self.footer = footer
}
// MARK: ListDiffable
func diffIdentifier() -> NSObjectProtocol {
return bodyText as NSObjectProtocol
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
guard self !== object else { return true }
guard let object = object as? ActivityItem else { return false }
return bodyText == object.bodyText
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/FeedItem.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
final class FeedItem: ListDiffable {
let pk: Int
let user: User
let comments: [String]
init(pk: Int, user: User, comments: [String]) {
self.pk = pk
self.user = user
self.comments = comments
}
// MARK: ListDiffable
func diffIdentifier() -> NSObjectProtocol {
return pk as NSObjectProtocol
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
guard self !== object else { return true }
guard let object = object as? FeedItem else { return false }
return user.isEqual(toDiffableObject: object.user) && comments == object.comments
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/GridItem.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import Foundation
final class GridItem: NSObject {
let color: UIColor
let itemCount: Int
var items: [String] = []
init(color: UIColor, itemCount: Int) {
self.color = color
self.itemCount = itemCount
super.init()
self.items = computeItems()
}
private func computeItems() -> [String] {
return [Int](1...itemCount).map {
String(describing: $0)
}
}
}
extension GridItem: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return self
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return self === object ? true : self.isEqual(object)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/HorizontalCardsSection.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import Foundation
final class HorizontalCardsSection: NSObject {
let cardCount: Int
private(set) var items: [String] = []
init(cardCount: Int) {
self.cardCount = cardCount
super.init()
self.items = computeItems()
}
private func computeItems() -> [String] {
return [Int](1...cardCount).map {
String(describing: $0)
}
}
}
extension HorizontalCardsSection: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return self
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return self === object ? true : self.isEqual(object)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/LoadingCellModel.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import UIKit
import IGListKit
final class LoadingCellModel {
let identifier = "loading-cell"
}
// MARK: - ListDiffable Implementation
// Even simple models like this loading indicator need to conform to ListDiffable
// in order to be used with IGListKit
extension LoadingCellModel: ListDiffable {
// The diffIdentifier uniquely identifies this object
// For a singleton loading indicator, a static string ID is sufficient
func diffIdentifier() -> any NSObjectProtocol {
return self.identifier as NSObjectProtocol
}
// isEqual compares properties that affect the visual representation
// For this simple case, comparing identifiers is enough
func isEqual(toDiffableObject object: (any ListDiffable)?) -> Bool {
guard let object = object as? LoadingCellModel else { return false }
return self.identifier == object.identifier
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/Month.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import Foundation
import IGListKit
final class Month {
let name: String
let days: Int
// day int mapped to an array of appointment names
let appointments: [Int: [NSString]]
init(name: String, days: Int, appointments: [Int: [NSString]]) {
self.name = name
self.days = days
self.appointments = appointments
}
}
extension Month: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return name as NSObjectProtocol
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return true
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/Post.h
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@import IGListDiffKit;
@interface Post : NSObject <IGListDiffable>
@property (nonatomic, strong, readonly) NSString *username;
@property (nonatomic, strong, readonly) NSArray<NSString *> *comments;
- (instancetype)initWithUsername:(NSString *)username
comments:(NSArray<NSString *> *)comments NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/Post.m
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "Post.h"
@implementation Post
- (instancetype)initWithUsername:(NSString *)username
comments:(NSArray<NSString *> *)comments {
if (self = [super init]) {
_username = [username copy];
_comments = [comments copy];
}
return self;
}
#pragma mark - IGListDiffable
- (id<NSObject>)diffIdentifier {
return self;
}
- (BOOL)isEqualToDiffableObject:(id)object {
// since the diff identifier returns self, object should only be compared with same instance
return self == object;
}
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/PostModel.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class Post {
let id: String
let username: String
let userAvatarURL: URL?
let imageURL: URL?
let title: String
let description: String
let likes: Int
let timeStamp: Date
init(id: String, username: String, userAvatarURL: URL?, imageURL: URL?, title: String, description: String, likes: Int, timeStamp: Date) {
self.id = id
self.username = username
self.userAvatarURL = userAvatarURL
self.imageURL = imageURL
self.title = title
self.description = description
self.likes = likes
self.timeStamp = timeStamp
}
}
// MARK: - ListDiffable Implementation
// ListDiffable is the core protocol in IGListKit for data diffing
// It's similar to Equatable but with more specific requirements for efficient diffing
extension Post: ListDiffable {
// This method returns a unique identifier for the object
// IGListKit uses this to track objects across updates
// It should be unique and stable across updates (like a database ID)
func diffIdentifier() -> NSObjectProtocol {
return self.id as NSObjectProtocol
}
// This method compares all properties that might cause visual changes
// If this returns false for objects with the same diffIdentifier,
// IGListKit will reload that section instead of leaving it alone
func isEqual(toDiffableObject object: (any ListDiffable)?) -> Bool {
guard let object = object as? Post else { return false }
return self.id == object.id &&
self.username == object.username &&
self.userAvatarURL == object.userAvatarURL &&
self.imageURL == object.imageURL &&
self.title == object.title &&
self.description == object.description &&
self.likes == object.likes
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.h
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* This file is generated using the remodel generation script.
* The name of the input file is PersonModel.value
*/
#import <Foundation/Foundation.h>
@import IGListDiffKit;
@interface PersonModel : NSObject <IGListDiffable, NSCopying>
@property (nonatomic, readonly, copy) NSString *firstName;
@property (nonatomic, readonly, copy) NSString *lastName;
@property (nonatomic, readonly, copy) NSString *uniqueId;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName uniqueId:(NSString *)uniqueId NS_DESIGNATED_INITIALIZER;
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.m
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* This file is generated using the remodel generation script.
* The name of the input file is PersonModel.value
*/
#if ! __has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
#import "PersonModel.h"
@implementation PersonModel
- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName uniqueId:(NSString *)uniqueId
{
if ((self = [super init])) {
_firstName = [firstName copy];
_lastName = [lastName copy];
_uniqueId = [uniqueId copy];
}
return self;
}
- (id)copyWithZone:(nullable NSZone *)zone
{
return self;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ - \n\t firstName: %@; \n\t lastName: %@; \n\t uniqueId: %@; \n", [super description], _firstName, _lastName, _uniqueId];
}
- (id<NSObject>)diffIdentifier
{
return _uniqueId;
}
- (NSUInteger)hash
{
NSUInteger subhashes[] = {[_firstName hash], [_lastName hash], [_uniqueId hash]};
NSUInteger result = subhashes[0];
for (int ii = 1; ii < 3; ++ii) {
unsigned long long base = (((unsigned long long)result) << 32 | subhashes[ii]);
base = (~base) + (base << 18);
base ^= (base >> 31);
base *= 21;
base ^= (base >> 11);
base += (base << 6);
base ^= (base >> 22);
result = base;
}
return result;
}
- (BOOL)isEqual:(PersonModel *)object
{
if (self == object) {
return YES;
} else if (self == nil || object == nil || ![object isKindOfClass:[self class]]) {
return NO;
}
return
(_firstName == object->_firstName ? YES : [_firstName isEqual:object->_firstName]) &&
(_lastName == object->_lastName ? YES : [_lastName isEqual:object->_lastName]) &&
(_uniqueId == object->_uniqueId ? YES : [_uniqueId isEqual:object->_uniqueId]);
}
- (BOOL)isEqualToDiffableObject:(nullable id<IGListDiffable>)object
{
return [self isEqual:object];
}
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.value
================================================
PersonModel includes(IGListDiffable) {
NSString *firstName
NSString *lastName
%diffIdentifier
NSString *uniqueId
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/SelectionModel.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
enum SelectionModelType: Int {
case none, fullWidth, nib
}
final class SelectionModel: NSObject {
let options: [String]
let type: SelectionModelType
init(options: [String], type: SelectionModelType = .none) {
self.options = options
self.type = type
}
}
extension SelectionModel: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return self
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return isEqual(object)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/SwipeActionSection.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import Foundation
final class SwipeActionSection: NSObject {
}
extension SwipeActionSection: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return self
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return self === object ? true : self.isEqual(object)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/User.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
final class User: ListDiffable {
let pk: Int
let name: String
let handle: String
init(pk: Int, name: String, handle: String) {
self.pk = pk
self.name = name
self.handle = handle
}
// MARK: ListDiffable
func diffIdentifier() -> NSObjectProtocol {
return pk as NSObjectProtocol
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
guard self !== object else { return true }
guard let object = object as? User else { return false }
return name == object.name && handle == object.handle
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/DayViewModel.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import Foundation
import IGListKit
final class DayViewModel {
let day: Int
let today: Bool
let selected: Bool
let appointments: Int
init(day: Int, today: Bool, selected: Bool, appointments: Int) {
self.day = day
self.today = today
self.selected = selected
self.appointments = appointments
}
}
extension DayViewModel: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return day as NSObjectProtocol
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
if self === object { return true }
guard let object = object as? DayViewModel else { return false }
return today == object.today && selected == object.selected && appointments == object.appointments
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/MonthTitleViewModel.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import Foundation
import IGListKit
final class MonthTitleViewModel {
let name: String
init(name: String) {
self.name = name
}
}
extension MonthTitleViewModel: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return name as NSObjectProtocol
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
if self === object { return true }
guard object is MonthTitleViewModel else { return false }
// name is checked in the diffidentifier, so we can assume its equal
return true
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/DemoSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class DemoItem: NSObject {
let name: String
let imageName: String
let controllerClass: UIViewController.Type
let controllerIdentifier: String?
init(
name: String,
imageName: String,
controllerClass: UIViewController.Type,
controllerIdentifier: String? = nil
) {
self.name = name
self.imageName = imageName
self.controllerClass = controllerClass
self.controllerIdentifier = controllerIdentifier
}
}
extension DemoItem: ListDiffable {
func diffIdentifier() -> NSObjectProtocol {
return name as NSObjectProtocol
}
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
if self === object { return true }
guard let object = object as? DemoItem else { return false }
return controllerClass == object.controllerClass && controllerIdentifier == object.controllerIdentifier
}
}
final class DemoSectionController: ListSectionController {
private var object: DemoItem?
override func sizeForItem(at index: Int) -> CGSize {
guard let context = collectionContext else {
return .zero
}
let inset = context.containerInset
let safeArea = viewController?.view.safeAreaInsets ?? .zero
let width = context.containerSize.width - (inset.left + inset.right + safeArea.left + safeArea.right)
return CGSize(width: width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object?.name
cell.imageName = object?.imageName
cell.style = .grouped
cell.isTopCell = isFirstSection
cell.isBottomCell = isLastSection
if let splitViewController = viewController?.splitViewController {
cell.disclosureImageView.isHidden = splitViewController.viewControllers.count > 1
}
cell.separator.isHidden = cell.isSelected
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? DemoItem
}
override func didSelectItem(at index: Int) {
setSeparatorsHidden(true)
let navigationController = UINavigationController()
navigationController.navigationBar.prefersLargeTitles = true
if let identifier = object?.controllerIdentifier {
let storyboard = UIStoryboard(name: "Demo", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: identifier)
controller.title = object?.name
navigationController.viewControllers = [controller]
viewController?.showDetailViewController(navigationController, sender: self)
} else if let controller = object?.controllerClass.init() {
controller.title = object?.name
navigationController.viewControllers = [controller]
viewController?.showDetailViewController(navigationController, sender: self)
}
}
override func didDeselectItem(at index: Int) {
setSeparatorsHidden(false)
}
private func setSeparatorsHidden(_ hidden: Bool) {
if let cell = collectionContext.cellForItem(at: 0, sectionController: self) as? LabelCell {
cell.separator.isHidden = hidden
}
if section > 0,
let listAdapter = collectionContext as? ListAdapter,
let previousSectionController = listAdapter.sectionController(forSection: section - 1),
let previousCell = collectionContext.cellForItem(at: 0, sectionController: previousSectionController) as? LabelCell {
previousCell.separator.isHidden = hidden
}
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/DisplaySectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
import UIKit
final class DisplaySectionController: ListSectionController, ListDisplayDelegate {
override init() {
super.init()
displayDelegate = self
inset = UIEdgeInsets(top: 0, left: 0, bottom: 30, right: 0)
}
override func numberOfItems() -> Int {
return 4
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = "Section \(self.section), cell \(index)"
return cell
}
// MARK: ListDisplayDelegate
func listAdapter(_ listAdapter: ListAdapter, willDisplay sectionController: ListSectionController) {
print("Will display section \(self.section)")
}
func listAdapter(_ listAdapter: ListAdapter,
willDisplay sectionController: ListSectionController,
cell: UICollectionViewCell,
at index: Int) {
print("Did will display cell \(index) in section \(self.section)")
}
func listAdapter(_ listAdapter: ListAdapter, didEndDisplaying sectionController: ListSectionController) {
print("Did end displaying section \(self.section)")
}
func listAdapter(_ listAdapter: ListAdapter,
didEndDisplaying sectionController: ListSectionController,
cell: UICollectionViewCell,
at index: Int) {
print("Did end displaying cell \(index) in section \(self.section)")
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/EmbeddedSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
import UIKit
final class EmbeddedSectionController: ListSectionController {
private var number: Int?
override init() {
super.init()
self.inset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)
}
override func sizeForItem(at index: Int) -> CGSize {
let height = collectionContext?.containerSize.height ?? 0
return CGSize(width: height, height: height)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: CenterLabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
let value = number ?? 0
cell.text = "\(value + 1)"
cell.backgroundColor = UIColor(red: 237 / 255.0, green: 73 / 255.0, blue: 86 / 255.0, alpha: 1)
return cell
}
override func didUpdate(to object: Any) {
number = object as? Int
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/ExpandableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
import UIKit
final class ExpandableSectionController: ListSectionController {
private var expanded = false
private var object: String?
override func sizeForItem(at index: Int) -> CGSize {
let width = collectionContext!.containerSize.width
let height = expanded ? LabelCell.textHeight(object ?? "", width: width) : LabelCell.singleLineHeight
return CGSize(width: width, height: height)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? String
}
override func didSelectItem(at index: Int) {
expanded = !expanded
UIView.animate(withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 0.4,
initialSpringVelocity: 0.6,
options: [],
animations: {
self.collectionContext?.invalidateLayout(for: self)
})
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/FeedItemSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
final class FeedItemSectionController: ListSectionController, ListSupplementaryViewSource {
private var feedItem: FeedItem!
override init() {
super.init()
supplementaryViewSource = self
}
// MARK: IGListSectionController Overrides
override func numberOfItems() -> Int {
return feedItem.comments.count
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = feedItem.comments[index]
return cell
}
override func didUpdate(to object: Any) {
feedItem = object as? FeedItem
}
// MARK: ListSupplementaryViewSource
func supportedElementKinds() -> [String] {
return [UICollectionView.elementKindSectionHeader, UICollectionView.elementKindSectionFooter]
}
func viewForSupplementaryElement(ofKind elementKind: String, at index: Int) -> UICollectionReusableView {
switch elementKind {
case UICollectionView.elementKindSectionHeader:
return userHeaderView(atIndex: index)
case UICollectionView.elementKindSectionFooter:
return userFooterView(atIndex: index)
default:
fatalError()
}
}
func sizeForSupplementaryView(ofKind elementKind: String, at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 40)
}
// MARK: Private
private func userHeaderView(atIndex index: Int) -> UICollectionReusableView {
let view: UserHeaderView = collectionContext.dequeueReusableSupplementaryView(
ofKind: UICollectionView.elementKindSectionHeader,
forSectionController: self,
nibName: "UserHeaderView",
bundle: nil,
atIndex: index)
view.handle = "@" + feedItem.user.handle
view.name = feedItem.user.name
return view
}
private func userFooterView(atIndex index: Int) -> UICollectionReusableView {
let view: UserFooterView = collectionContext.dequeueReusableSupplementaryView(
ofKind: UICollectionView.elementKindSectionFooter,
forSectionController: self,
nibName: "UserFooterView",
bundle: nil,
atIndex: index)
view.commentsCount = "\(feedItem.comments.count)"
return view
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/GridSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
import UIKit
final class GridSectionController: ListSectionController {
private var object: GridItem?
private let isReorderable: Bool
required init(isReorderable: Bool = false) {
self.isReorderable = isReorderable
super.init()
self.minimumInteritemSpacing = 1
self.minimumLineSpacing = 1
}
override func numberOfItems() -> Int {
return object?.itemCount ?? 0
}
override func sizeForItem(at index: Int) -> CGSize {
let itemsPerRow = 4.0
let width = (collectionContext?.containerSize.width ?? 0) - ((itemsPerRow - 1) * self.minimumLineSpacing)
let itemSize = floor(width / itemsPerRow)
return CGSize(width: itemSize, height: itemSize)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: CenterLabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object?.items[index] ?? "undefined"
cell.backgroundColor = object?.color
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? GridItem
}
override func canMoveItem(at index: Int) -> Bool {
return isReorderable
}
override func moveObject(from sourceIndex: Int, to destinationIndex: Int) {
guard let object = object else { return }
let item = object.items.remove(at: sourceIndex)
object.items.insert(item, at: destinationIndex)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/HorizontalSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class HorizontalSectionController: ListSectionController, ListAdapterDataSource {
private var number: Int?
lazy var adapter: ListAdapter = {
let adapter = ListAdapter(updater: ListAdapterUpdater(),
viewController: self.viewController)
adapter.dataSource = self
return adapter
}()
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 100)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: EmbeddedCollectionViewCell = collectionContext.dequeueReusableCell(for: self, at: index)
adapter.collectionView = cell.collectionView
return cell
}
override func didUpdate(to object: Any) {
number = object as? Int
}
// MARK: ListAdapterDataSource
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
guard let number = number else { return [] }
return (0..<number).map { $0 as ListDiffable }
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return EmbeddedSectionController()
}
func emptyView(for listAdapter: ListAdapter) -> UIView? {
return nil
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/LabelSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
import UIKit
final class LabelSectionController: ListSectionController {
private var object: String?
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object
return cell
}
override func didUpdate(to object: Any) {
self.object = String(describing: object)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/ListeningSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
final class ListeningSectionController: ListSectionController, IncrementListener {
private var value: Int = 0
init(announcer: IncrementAnnouncer) {
super.init()
announcer.addListener(listener: self)
}
func configureCell(cell: LabelCell) {
cell.text = "Section: \(self.section), value: \(value)"
}
// MARK: ListSectionController Overrides
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
configureCell(cell: cell)
return cell
}
// MARK: IncrementListener
func didIncrement(announcer: IncrementAnnouncer, value: Int) {
self.value = value
guard let cell = collectionContext?.cellForItem(at: 0, sectionController: self) as? LabelCell else { return }
configureCell(cell: cell)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/LoadingSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
// MARK: - LoadingSectionController
// A simpler section controller that manages the loading indicator
// Note that each type of content gets its own section controller
// This is a key concept in IGListKit - each model type gets a dedicated controller
final class LoadingSectionController: ListSectionController {
override init() {
super.init()
self.inset = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 0)
}
// Set the size for the loading indicator cell
override func sizeForItem(at index: Int) -> CGSize {
let width = collectionContext?.containerSize.width ?? 0
return CGSize(width: width, height: 60)
}
// Create and return the loading cell
override func cellForItem(at index: Int) -> UICollectionViewCell {
guard let cell = collectionContext?.dequeueReusableCell(of: LoadingCell.self, for: self, at: index) else {
fatalError("Failed to dequeue LoadingCell")
}
return cell
}
// Nothing to update for this simple controller
override func didUpdate(to object: Any) {
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/MonthSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class MonthSectionController: ListBindingSectionController<ListDiffable>, ListBindingSectionControllerDataSource, ListBindingSectionControllerSelectionDelegate {
private var selectedDay: Int = -1
override init() {
super.init()
dataSource = self
selectionDelegate = self
}
// MARK: ListBindingSectionControllerDataSource
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, viewModelsFor object: Any) -> [ListDiffable] {
guard let month = object as? Month else { return [] }
let date = Date()
let today = Calendar.current.component(.day, from: date)
var viewModels = [ListDiffable]()
viewModels.append(MonthTitleViewModel(name: month.name))
for day in 1..<(month.days + 1) {
let viewModel = DayViewModel(
day: day,
today: day == today,
selected: day == selectedDay,
appointments: month.appointments[day]?.count ?? 0
)
viewModels.append(viewModel)
}
for appointment in month.appointments[selectedDay] ?? [] {
viewModels.append(appointment)
}
return viewModels
}
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>,
cellForViewModel viewModel: Any,
at index: Int) -> UICollectionViewCell & ListBindable {
switch viewModel {
case is DayViewModel:
return collectionContext.dequeueReusableCell(for: self, at: index) as CalendarDayCell
case is MonthTitleViewModel:
return collectionContext.dequeueReusableCell(for: self, at: index) as MonthTitleCell
default:
return collectionContext.dequeueReusableCell(for: self, at: index) as LabelCell
}
}
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>,
sizeForViewModel viewModel: Any,
at index: Int) -> CGSize {
guard let width = collectionContext?.containerSize.width else { return .zero }
if viewModel is DayViewModel {
let square = width / 7.0
return CGSize(width: square, height: square)
} else if viewModel is MonthTitleViewModel {
return CGSize(width: width, height: 30.0)
} else {
return CGSize(width: width, height: 55.0)
}
}
// MARK: ListBindingSectionControllerSelectionDelegate
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didSelectItemAt index: Int, viewModel: Any) {
guard let dayViewModel = viewModel as? DayViewModel else { return }
if dayViewModel.day == selectedDay {
selectedDay = -1
} else {
selectedDay = dayViewModel.day
}
update(animated: true)
}
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didDeselectItemAt index: Int, viewModel: Any) {}
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didHighlightItemAt index: Int, viewModel: Any) {}
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didUnhighlightItemAt index: Int, viewModel: Any) {}
@available(iOS 13.0, *)
func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, contextMenuConfigurationForItemAt index: Int, point: CGPoint, viewModel: Any) -> UIContextMenuConfiguration? {
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
// Create an action for sharing
let share = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up")) { _ in
// Show share sheet
}
// Create an action for copy
let rename = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc")) { _ in
// Perform copy
}
// Create an action for delete with destructive attributes (highligh in red)
let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
// Perform delete
}
// Create a UIMenu with all the actions as children
return UIMenu(title: "", children: [share, rename, delete])
}
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.h
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
@import IGListKit;
@interface PersonSectionController : IGListSectionController
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.m
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "PersonSectionController.h"
#import "PersonCell.h"
#import "PersonModel.h"
@implementation PersonSectionController {
PersonModel *_person;
}
#pragma mark - IGListSectionController Overrides
- (NSInteger)numberOfItems {
return 1;
}
- (CGSize)sizeForItemAtIndex:(NSInteger)index {
const CGFloat width = self.collectionContext.containerSize.width;
const CGFloat height = 74.0;
return CGSizeMake(width, height);
}
- (UICollectionViewCell *)cellForItemAtIndex:(NSInteger)index {
const Class cellClass = [PersonCell class];
PersonCell *cell = (PersonCell *)[self.collectionContext dequeueReusableCellOfClass:cellClass forSectionController:self atIndex:index];
cell.person = _person;
return cell;
}
- (void)didUpdateToObject:(id)object {
_person = (PersonModel *)object;
}
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.h
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
@import IGListKit;
@interface PostSectionController : IGListSectionController
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.m
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "PostSectionController.h"
#import "CommentCell.h"
#import "InteractiveCell.h"
#import "PhotoCell.h"
#import "Post.h"
#import "UserInfoCell.h"
static NSInteger cellsBeforeComments = 3;
@implementation PostSectionController {
Post *_post;
}
#pragma mark - IGListSectionController Overrides
- (NSInteger)numberOfItems {
return cellsBeforeComments + _post.comments.count;
}
- (CGSize)sizeForItemAtIndex:(NSInteger)index {
const CGFloat width = self.collectionContext.containerSize.width;
CGFloat height;
if (index == 0 || index == 2) {
height = 41.0;
} else if (index == 1) {
height = width; // square
} else {
height = 25.0;
}
return CGSizeMake(width, height);
}
- (UICollectionViewCell *)cellForItemAtIndex:(NSInteger)index {
Class cellClass;
if (index == 0) {
cellClass = [UserInfoCell class];
} else if (index == 1) {
cellClass = [PhotoCell class];
} else if (index == 2) {
cellClass = [InteractiveCell class];
} else {
cellClass = [CommentCell class];
}
id cell = [self.collectionContext dequeueReusableCellOfClass:cellClass forSectionController:self atIndex:index];
if ([cell isKindOfClass:[CommentCell class]]) {
[(CommentCell *)cell setComment:_post.comments[index - cellsBeforeComments]];
} else if ([cell isKindOfClass:[UserInfoCell class]]) {
[(UserInfoCell *)cell setName:_post.username];
}
return cell;
}
- (void)didUpdateToObject:(id)object {
_post = object;
}
@end
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
// MARK: - ListSectionController
// In IGListKit, section controllers manage a single type of data object
// and are responsible for:
// - Creating and configuring cells
// - Handling cell selection
// - Determining cell sizes
// - Managing section-specific actions
final class PostSectionController: ListSectionController {
var post: Post?
weak var delegate: PostSectionControllerDelegate?
override init() {
super.init()
// Setting insets for the entire section
self.inset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
}
// Determines the size of cells in this section
// IGListKit calls this method to calculate cell dimensions
override func sizeForItem(at index: Int) -> CGSize {
// collectionContext is a bridge that connects the section controller
// to the actual UICollectionView it exists within
let width = collectionContext?.containerSize.width ?? 0
return CGSize(width: width, height: width + 200)
}
// Creates and configures a cell for this section
// Similar to cellForRowAt in UICollectionViewDataSource
override func cellForItem(at index: Int) -> UICollectionViewCell {
guard let cell = collectionContext?.dequeueReusableCell(of: PostCell.self, for: self, at: index) as? PostCell,
let post = post else {
fatalError("Failed to dequeue PostCell")
}
cell.configure(with: post)
cell.optionsButtonTapped = { [weak self] (button: UIButton) in
guard let self = self, let post = self.post else { return }
self.delegate?.postSectionController(self, didSelectOptionsFor: post, from: button)
}
return cell
}
// Handles selection of cells in this section
override func didSelectItem(at index: Int) {
guard let post = post else { return }
print("Post ID:\(post.id) was tapped.")
}
// Called when the data object for this section controller is updated
// This is where you store a reference to your model object
override func didUpdate(to object: Any) {
post = object as? Post
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/RemoveSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
protocol RemoveSectionControllerDelegate: AnyObject {
func removeSectionControllerWantsRemoved(_ sectionController: RemoveSectionController)
}
final class RemoveSectionController: ListSectionController, RemoveCellDelegate {
weak var delegate: RemoveSectionControllerDelegate?
private var number: Int?
override init() {
super.init()
inset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: RemoveCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = "Cell: \((number ?? 0) + 1)"
cell.delegate = self
return cell
}
override func didUpdate(to object: Any) {
number = object as? Int
}
// MARK: RemoveCellDelegate
func removeCellDidTapButton(_ cell: RemoveCell) {
delegate?.removeSectionControllerWantsRemoved(self)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/ReorderableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
import UIKit
final class ReorderableSectionController: ListSectionController {
private var object: String?
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object
return cell
}
override func didUpdate(to object: Any) {
self.object = String(describing: object)
}
override func canMoveItem(at index: Int) -> Bool {
return true
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/SearchSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
protocol SearchSectionControllerDelegate: AnyObject {
func searchSectionController(_ sectionController: SearchSectionController, didChangeText text: String)
}
final class SearchSectionController: ListSectionController, UISearchBarDelegate, ListScrollDelegate {
weak var delegate: SearchSectionControllerDelegate?
override init() {
super.init()
scrollDelegate = self
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 44)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: SearchCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.searchBar.delegate = self
return cell
}
// MARK: UISearchBarDelegate
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
delegate?.searchSectionController(self, didChangeText: searchText)
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
delegate?.searchSectionController(self, didChangeText: searchBar.text!)
}
// MARK: ListScrollDelegate
func listAdapter(_ listAdapter: ListAdapter, didScroll sectionController: ListSectionController) {
if let searchBar = (collectionContext?.cellForItem(at: 0, sectionController: self) as? SearchCell)?.searchBar {
searchBar.resignFirstResponder()
}
}
func listAdapter(_ listAdapter: ListAdapter, willBeginDragging sectionController: ListSectionController) {}
func listAdapter(_ listAdapter: ListAdapter,
didEndDragging sectionController: ListSectionController,
willDecelerate decelerate: Bool) {}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/SelfSizingSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import IGListSwiftKit
import UIKit
final class SelfSizingSectionController: ListSectionController {
private var model: SelectionModel!
override init() {
super.init()
inset = UIEdgeInsets(top: 0, left: 0, bottom: 40, right: 0)
minimumLineSpacing = 4
minimumInteritemSpacing = 4
}
override func numberOfItems() -> Int {
return model.options.count
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let text = model.options[index]
let cell: UICollectionViewCell
switch model.type {
case .none:
let manualCell: ManuallySelfSizingCell = collectionContext.dequeueReusableCell(
for: self,
at: index
)
manualCell.text = text
cell = manualCell
case .fullWidth:
let manualCell: FullWidthSelfSizingCell = collectionContext.dequeueReusableCell(
for: self,
at: index
)
manualCell.text = text
cell = manualCell
case .nib:
let nibCell: NibSelfSizingCell = collectionContext.dequeueReusableCell(
withNibName: "NibSelfSizingCell",
bundle: nil,
for: self,
at: index
)
nibCell.contentLabel.text = text
cell = nibCell
}
return cell
}
override func didUpdate(to object: Any) {
self.model = object as? SelectionModel
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/StoryboardLabelSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
protocol StoryboardLabelSectionControllerDelegate: AnyObject {
func removeSectionControllerWantsRemoved(_ sectionController: StoryboardLabelSectionController)
}
final class StoryboardLabelSectionController: ListSectionController {
private var object: Person?
weak var delegate: StoryboardLabelSectionControllerDelegate?
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: (self.object?.name.count)! * 7, height: (self.object?.name.count)! * 7)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: StoryboardCell = collectionContext.dequeueReusableCellFromStoryboard(
withIdentifier: "cell",
for: self,
at: index)
cell.text = object?.name
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? Person
}
override func didSelectItem(at index: Int) {
delegate?.removeSectionControllerWantsRemoved(self)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/UserSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class UserSectionController: ListSectionController {
private var user: User?
private let isReorderable: Bool
required init(isReorderable: Bool = false) {
self.isReorderable = isReorderable
super.init()
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: DetailLabelCell = collectionContext.dequeueReusableCell(
for: self,
at: index
)
cell.title = user?.name
cell.detail = "@" + (user?.handle ?? "")
return cell
}
override func didUpdate(to object: Any) {
self.user = object as? User
}
override func canMoveItem(at index: Int) -> Bool {
return isReorderable
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ActivityComposableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
import SwiftUI
final class ActivityComposableSectionController: ListSectionController, CompositionLayoutCapable, ListSupplementaryViewSource {
private var activity: ActivityItem?
override init() {
super.init()
supplementaryViewSource = self
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 60)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: UICollectionViewCell = collectionContext.dequeueReusableCell(
for: self,
at: index
)
cell.contentConfiguration = UIHostingConfiguration(content: {
HStack {
Circle()
.fill(
LinearGradient(colors: [ .blue.opacity(0.3), .red.opacity(0.3)],
startPoint: .topLeading,
endPoint: .bottomTrailing)
)
.frame(width: 44)
.padding(16)
Text(activity?.bodyText ?? "No body")
Spacer()
RoundedRectangle(cornerRadius: 10)
.fill(
RadialGradient(colors: [ .green.opacity(0.3), .yellow.opacity(0.3)],
center: .center,
startRadius: 5,
endRadius: 75)
)
.frame(width: 44, height: 44)
.padding(16)
}
})
.margins(.all, 0)
return cell
}
func supportedElementKinds() -> [String] {
return [UICollectionView.elementKindSectionHeader, UICollectionView.elementKindSectionFooter]
}
func viewForSupplementaryElement(ofKind elementKind: String, at index: Int) -> UICollectionReusableView {
let view: UICollectionViewListCell = collectionContext.dequeueReusableSupplementaryView(
ofKind: elementKind,
forSectionController: self,
atIndex: index)
view.contentConfiguration = UIHostingConfiguration(content: {
switch elementKind {
case UICollectionView.elementKindSectionHeader:
Text("Activity Start")
case UICollectionView.elementKindSectionFooter:
Text("Activity End")
default: EmptyView()
}
})
return view
}
func sizeForSupplementaryView(ofKind elementKind: String, at index: Int) -> CGSize {
if activity?.header != nil && elementKind == UICollectionView.elementKindSectionHeader {
return CGSize(width: collectionContext.containerSize.width, height: 40)
}
if activity?.footer != nil && elementKind == UICollectionView.elementKindSectionFooter {
return CGSize(width: collectionContext.containerSize.width, height: 40)
}
return .zero
}
override func didUpdate(to object: Any) {
self.activity = object as? ActivityItem
}
// MARK: CompositionLayoutCapable
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
var maxItemHeight: CGFloat = 0.0
var anyItemHasEstimatedHeight = false
let itemCount: Int = numberOfItems()
let items = (0..<itemCount).map { itemIndex in
let itemSize = sizeForItem(at: itemIndex)
let layoutSize = NSCollectionLayoutSize(widthDimension: .absolute(itemSize.width),
heightDimension: .estimated(itemSize.height))
maxItemHeight = max(maxItemHeight, itemSize.height)
return NSCollectionLayoutItem(layoutSize: layoutSize)
}
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(maxItemHeight))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: items)
if minimumInteritemSpacing > 0.0 {
group.interItemSpacing = NSCollectionLayoutSpacing.fixed(minimumInteritemSpacing)
}
let layoutSection = NSCollectionLayoutSection(group: group)
if let suplementaryViewProvider = supplementaryViewSource {
layoutSection.boundarySupplementaryItems = suplementaryViewProvider.supportedElementKinds().map { kind in
let size = suplementaryViewProvider.sizeForSupplementaryView(ofKind: kind, at: 0)
let layoutSize = NSCollectionLayoutSize(widthDimension: .absolute(size.width), heightDimension: .absolute(size.height))
let alignment: NSRectAlignment
switch kind {
case UICollectionView.elementKindSectionHeader: alignment = .top
case UICollectionView.elementKindSectionFooter: alignment = .bottom
default: alignment = .none
}
return NSCollectionLayoutBoundarySupplementaryItem(layoutSize: layoutSize, elementKind: kind, alignment: alignment)
}
}
if inset != .zero {
layoutSection.contentInsets = NSDirectionalEdgeInsets(top: inset.top,
leading: inset.left,
bottom: inset.bottom,
trailing: inset.right)
}
if minimumLineSpacing > 0.0 {
layoutSection.interGroupSpacing = minimumLineSpacing
}
return layoutSection
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ExpandableComposableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
/// Like ExpandableSectionController, but supports UICollectionViewCompositionalLayout
final class ExpandableComposableSectionController: ListSectionController, CompositionLayoutCapable {
private var expanded = false
private var object: String?
override func sizeForItem(at index: Int) -> CGSize {
// Size handled by cell
return CGSize.zero
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object
cell.expanded = expanded
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? String
}
override func didSelectItem(at index: Int) {
expanded = !expanded
guard let cell = collectionContext.cellForItem(at: index, sectionController: self) as? CompositionLayoutCell else {
return
}
cell.expanded = expanded
UIView.animate(withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 0.4,
initialSpringVelocity: 0.6,
options: [],
animations: {
self.collectionContext?.invalidateLayout(for: self)
})
}
// MARK: CompositionLayoutCapable
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
let config = UICollectionLayoutListConfiguration(appearance: .plain)
return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/GridComposableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class GridComposableSectionController: ListSectionController, CompositionLayoutCapable {
private var object: GridItem?
override func numberOfItems() -> Int {
return object?.itemCount ?? 0
}
override func sizeForItem(at index: Int) -> CGSize {
// Size handled by cell
return CGSize.zero
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object?.items[index] ?? "undefined"
cell.contentView.backgroundColor = object?.color
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? GridItem
}
// MARK: CompositionLayoutCapable
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
// Item
let columnCount: CGFloat = 3
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0 / columnCount),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
// Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalWidth(1.0 / columnCount))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
subitems: [item])
// Section
return NSCollectionLayoutSection(group: group)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/HorizontalComposableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class HorizontalComposableSectionController: ListSectionController, CompositionLayoutCapable {
private var object: HorizontalCardsSection?
override func numberOfItems() -> Int {
return object?.cardCount ?? 0
}
override func sizeForItem(at index: Int) -> CGSize {
// Size handled by cell
return CGSize.zero
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = object?.items[index] ?? "undefined"
cell.contentView.backgroundColor = UIColor.secondarySystemBackground
cell.contentView.layer.cornerRadius = 8
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? HorizontalCardsSection
}
// MARK: CompositionLayoutCapable
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
// Item
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16)
// Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(160))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
// Section
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: 16, leading: 16, bottom: 16, trailing: 16)
section.orthogonalScrollingBehavior = .continuousGroupLeadingBoundary
return section
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SelectionComposableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
import SwiftUI
final class TextViewModel: ObservableObject {
@Published var text: String
@Published var extraPadding: Bool = false
init(text: String) {
self.text = text
}
}
struct ExpandTextView: View {
@ObservedObject var viewModel: TextViewModel
var body: some View {
Text(viewModel.text)
.padding(viewModel.extraPadding ? 20 : 10)
.border(.gray.opacity(0.2), width: 1)
}
}
final class SelectionComposableSectionController: ListSectionController, CompositionLayoutCapable {
private var viewModels: [TextViewModel] = []
override func numberOfItems() -> Int {
return viewModels.count
}
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: 100, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: UICollectionViewCell = collectionContext.dequeueReusableCell(
for: self,
at: index
)
let viewModel = viewModels[index]
cell.contentConfiguration = UIHostingConfiguration(content: {
ExpandTextView(viewModel: viewModel)
})
.margins(.all, 0)
return cell
}
override func didSelectItem(at index: Int) {
withAnimation {
viewModels[index].extraPadding.toggle()
}
}
override func didUpdate(to object: Any) {
guard let selection = object as? SelectionModel else {
return
}
viewModels = selection.options.map { TextViewModel(text: $0) }
}
// MARK: CompositionLayoutCapable
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
var maxItemHeight: CGFloat = 0.0
let itemCount: Int = numberOfItems()
let items = (0..<itemCount).map { itemIndex in
let itemSize = sizeForItem(at: itemIndex)
let layoutSize = NSCollectionLayoutSize(widthDimension: .estimated(itemSize.width),
heightDimension: .estimated(itemSize.height))
maxItemHeight = max(maxItemHeight, itemSize.height)
return NSCollectionLayoutItem(layoutSize: layoutSize)
}
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(maxItemHeight))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: items)
if minimumInteritemSpacing > 0.0 {
group.interItemSpacing = NSCollectionLayoutSpacing.fixed(minimumInteritemSpacing)
}
let layoutSection = NSCollectionLayoutSection(group: group)
if let suplementaryViewProvider = supplementaryViewSource {
layoutSection.boundarySupplementaryItems = suplementaryViewProvider.supportedElementKinds().map { kind in
let size = suplementaryViewProvider.sizeForSupplementaryView(ofKind: kind, at: 0)
let layoutSize = NSCollectionLayoutSize(widthDimension: .absolute(size.width), heightDimension: .absolute(size.height))
let alignment: NSRectAlignment
switch kind {
case UICollectionView.elementKindSectionHeader: alignment = .top
case UICollectionView.elementKindSectionFooter: alignment = .bottom
default: alignment = .none
}
return NSCollectionLayoutBoundarySupplementaryItem(layoutSize: layoutSize, elementKind: kind, alignment: alignment)
}
}
if inset != .zero {
layoutSection.contentInsets = NSDirectionalEdgeInsets(top: inset.top,
leading: inset.left,
bottom: inset.bottom,
trailing: inset.right)
}
if minimumLineSpacing > 0.0 {
layoutSection.interGroupSpacing = minimumLineSpacing
}
return layoutSection
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SwipeActionComposabelSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class SwipeActionComposabelSectionController: ListSectionController, CompositionLayoutCapable {
private var object: SwipeActionSection?
private var items = ["1. Swipe to delete me", "2. Swipe to delete me", "3. Swipe to delete me"]
override func numberOfItems() -> Int {
return items.count
}
override func sizeForItem(at index: Int) -> CGSize {
// Compositional layout doesn't request sizes per NSIndexPath
return CGSize.zero
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
cell.text = items[index]
return cell
}
override func didUpdate(to object: Any) {
self.object = object as? SwipeActionSection
}
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
var config = UICollectionLayoutListConfiguration(appearance: .plain)
config.trailingSwipeActionsConfigurationProvider = {[weak self] indexPath in
// Sections should match, but just in case
guard let self = self, indexPath.section == self.section else {
return nil
}
return self.swipeActionFor(index: indexPath.item)
}
return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
}
// MARK: CompositionLayoutCapable
private func swipeActionFor(index: Int) -> UISwipeActionsConfiguration? {
let action = UIContextualAction(style: .destructive, title: "Delete") {[weak self] _, _, block in
self?.deleteItem(index: index, block: block)
}
return UISwipeActionsConfiguration(actions: [action])
}
private func deleteItem(index: Int, block: @escaping (Bool) -> Void) {
self.collectionContext.performBatch(animated: true) {updates in
self.items.remove(at: index)
updates.delete(in: self, at: IndexSet(integer: index))
} completion: { completed in
block(completed)
}
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/UserComposableSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class UserComposableSectionController: ListSectionController, CompositionLayoutCapable {
private var user: User?
override func sizeForItem(at index: Int) -> CGSize {
// Size handled by cell
return CGSize.zero
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell: DetailLabelCell = collectionContext.dequeueReusableCell(
for: self,
at: index
)
cell.title = user?.name
cell.detail = "@" + (user?.handle ?? "")
return cell
}
override func didUpdate(to object: Any) {
self.user = object as? User
}
// MARK: CompositionLayoutCapable
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
let config = UICollectionLayoutListConfiguration(appearance: .plain)
return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/WorkingRangeSectionController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class WorkingRangeSectionController: ListSectionController, ListWorkingRangeDelegate {
private var height: Int?
private var downloadedImage: UIImage?
private var task: URLSessionDataTask?
private var urlString: String? {
guard let height = height,
let size = collectionContext?.containerSize
else { return nil }
let width = Int(size.width)
return "https://unsplash.it/" + width.description + "/" + height.description
}
deinit {
task?.cancel()
}
override init() {
super.init()
workingRangeDelegate = self
}
override func numberOfItems() -> Int {
return 2
}
override func sizeForItem(at index: Int) -> CGSize {
let width: CGFloat = collectionContext?.containerSize.width ?? 0
let height: CGFloat = CGFloat(index == 0 ? 55 : (self.height ?? 0))
return CGSize(width: width, height: height)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cellClass: UICollectionViewCell.Type = index == 0 ? LabelCell.self : ImageCell.self
let cell = collectionContext.dequeueReusableCell(of: cellClass, for: self, at: index)
if let cell = cell as? LabelCell {
cell.text = urlString
} else if let cell = cell as? ImageCell {
cell.setImage(image: downloadedImage)
}
return cell
}
override func didUpdate(to object: Any) {
self.height = object as? Int
}
// MARK: ListWorkingRangeDelegate
func listAdapter(_ listAdapter: ListAdapter, sectionControllerWillEnterWorkingRange sectionController: ListSectionController) {
guard downloadedImage == nil,
task == nil,
let urlString = urlString,
let url = URL(string: urlString)
else { return }
print("Downloading image \(urlString) for section \(self.section)")
task = URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data, let image = UIImage(data: data) else {
return print("Error downloading \(urlString): " + String(describing: error))
}
DispatchQueue.main.async {
self.downloadedImage = image
if let cell = self.collectionContext?.cellForItem(at: 1, sectionController: self) as? ImageCell {
cell.setImage(image: image)
}
}
}
task?.resume()
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerDidExitWorkingRange sectionController: ListSectionController) {}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Storyboard/Demo.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Storyboard View Controller-->
<scene sceneID="oB3-c8-g1U">
<objects>
<viewController storyboardIdentifier="demo" id="5n3-mX-NaJ" customClass="StoryboardViewController" customModule="IGListKitExamples" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="VEL-Rj-Wcy"/>
<viewControllerLayoutGuide type="bottom" id="wYR-29-GPY"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="s2P-10-T78">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="LKS-vo-Ytk">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<collectionViewLayout key="collectionViewLayout" id="fUa-Xb-tfX" customClass="IGListCollectionViewLayout"/>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="Eqn-FQ-8Sv" customClass="StoryboardCell" customModule="IGListKitExamples" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="6" translatesAutoresizingMaskIntoConstraints="NO" id="1vx-C5-AAO">
<rect key="frame" x="5" y="18" width="40" height="15"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<color key="backgroundColor" red="0.8912609816" green="0.35455638169999998" blue="0.39968371390000001" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="1vx-C5-AAO" secondAttribute="trailing" constant="5" id="IUH-Vl-wp7"/>
<constraint firstItem="1vx-C5-AAO" firstAttribute="leading" secondItem="Eqn-FQ-8Sv" secondAttribute="leading" constant="5" id="Mex-qB-ubM"/>
<constraint firstItem="1vx-C5-AAO" firstAttribute="centerY" secondItem="Eqn-FQ-8Sv" secondAttribute="centerY" id="jSJ-a7-q5U"/>
</constraints>
<connections>
<outlet property="textLabel" destination="1vx-C5-AAO" id="QUu-x5-Hgm"/>
</connections>
</collectionViewCell>
</cells>
</collectionView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="LKS-vo-Ytk" firstAttribute="top" secondItem="s2P-10-T78" secondAttribute="top" id="IQP-dj-gaM"/>
<constraint firstItem="LKS-vo-Ytk" firstAttribute="leading" secondItem="s2P-10-T78" secondAttribute="leading" id="cc8-Hj-dNE"/>
<constraint firstAttribute="bottom" secondItem="LKS-vo-Ytk" secondAttribute="bottom" id="hhH-sV-DXp"/>
<constraint firstAttribute="trailing" secondItem="LKS-vo-Ytk" secondAttribute="trailing" id="tnZ-7G-n7P"/>
</constraints>
</view>
<connections>
<outlet property="collectionView" destination="LKS-vo-Ytk" id="rhv-M3-HDp"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="WwB-xb-Qef" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-146.40000000000001" y="90.404797601199405"/>
</scene>
<!--Single Section Storyboard View Controller-->
<scene sceneID="VLx-Fb-fo0">
<objects>
<viewController storyboardIdentifier="singleSectionDemo" id="frc-YL-WX9" customClass="SingleSectionStoryboardViewController" customModule="IGListKitExamples" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="VaC-h1-D9B"/>
<viewControllerLayoutGuide type="bottom" id="jSR-p6-C72"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="bMx-bC-IhF">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Lqf-9C-lS3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="vuu-gE-rAa">
<size key="itemSize" width="309" height="65"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="fD7-7i-CX0" customClass="StoryboardCell" customModule="IGListKitExamples" customModuleProvider="target">
<rect key="frame" x="33" y="0.0" width="309" height="65"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="309" height="65"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y2N-aR-93q">
<rect key="frame" x="15" y="22" width="42" height="21"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<constraints>
<constraint firstItem="y2N-aR-93q" firstAttribute="leading" secondItem="fD7-7i-CX0" secondAttribute="leading" constant="15" id="kVn-2C-bNo"/>
<constraint firstItem="y2N-aR-93q" firstAttribute="centerY" secondItem="fD7-7i-CX0" secondAttribute="centerY" id="zXx-Fd-B4q"/>
</constraints>
<connections>
<outlet property="textLabel" destination="y2N-aR-93q" id="SPh-KG-DJQ"/>
</connections>
</collectionViewCell>
</cells>
</collectionView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="Lqf-9C-lS3" firstAttribute="leading" secondItem="bMx-bC-IhF" secondAttribute="leading" id="2B9-1H-mjw"/>
<constraint firstItem="Lqf-9C-lS3" firstAttribute="top" secondItem="bMx-bC-IhF" secondAttribute="top" id="4rw-Vn-NT0"/>
<constraint firstAttribute="trailing" secondItem="Lqf-9C-lS3" secondAttribute="trailing" id="6St-9C-UOf"/>
<constraint firstAttribute="bottom" secondItem="Lqf-9C-lS3" secondAttribute="bottom" id="Hwt-35-Ha0"/>
</constraints>
</view>
<connections>
<outlet property="collectionView" destination="Lqf-9C-lS3" id="me8-q7-8f5"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="T5T-i5-O9g" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-825" y="90"/>
</scene>
</scenes>
</document>
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Systems/IncrementAnnouncer.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import UIKit
@objc protocol IncrementListener: AnyObject {
func didIncrement(announcer: IncrementAnnouncer, value: Int)
}
final class IncrementAnnouncer: NSObject {
private var value: Int = 0
private let map: NSHashTable<IncrementListener> = NSHashTable<IncrementListener>.weakObjects()
func addListener(listener: IncrementListener) {
map.add(listener)
}
func increment() {
value += 1
for listener in map.allObjects {
listener.didIncrement(announcer: self, value: value)
}
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/ViewControllers/AnnouncingDepsViewController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class AnnouncingDepsViewController: UIViewController, ListAdapterDataSource {
lazy var adapter: ListAdapter = {
return ListAdapter(updater: ListAdapterUpdater(), viewController: self, workingRangeSize: 1)
}()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
let data: [NSNumber] = Array(0..<20).map { NSNumber(value: $0) }
let announcer = IncrementAnnouncer()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
adapter.collectionView = collectionView
adapter.dataSource = self
// disable prefetching so cells are configured as they come on screen
if #available(iOS 10.0, *) {
collectionView.isPrefetchingEnabled = false
}
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
target: self,
action: #selector(AnnouncingDepsViewController.onAdd))
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.frame = view.bounds
}
@objc func onAdd() {
announcer.increment()
}
// MARK: ListAdapterDataSource
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return data
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return ListeningSectionController(announcer: announcer)
}
func emptyView(for listAdapter: ListAdapter) -> UIView? {
return nil
}
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/ViewControllers/CalendarViewController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
final class CalendarViewController: UIViewController, ListAdapterDataSource {
lazy var adapter: ListAdapter = {
return ListAdapter(updater: ListAdapterUpdater(), viewController: self)
}()
let collectionView = UICollectionView(
frame: .zero,
collectionViewLayout: ListCollectionViewLayout(stickyHeaders: false, topContentInset: 0, stretchToEdge: false)
)
var months = [Month]()
override func viewDidLoad() {
super.viewDidLoad()
let date = Date()
let currentMonth = Calendar.current.component(.month, from: date)
let month = Month(
name: DateFormatter().monthSymbols[currentMonth - 1],
days: 30,
appointments: [
2: ["Hair"],
4: ["Nails"],
7: ["Doctor appt", "Pick up groceries"],
12: ["Call back the cable company", "Find a babysitter"],
13: ["Dinner at The Smith"],
17: ["Buy running shoes", "Buy a fitbit", "Start running"],
20: ["Call mom"],
21: ["Contribute to IGListKit"],
25: ["Interview"],
26: ["Quit running", "Buy ice cream"]
]
)
months.append(month)
view.addSubview(collectionView)
adapter.collectionView = collectionView
adapter.dataSource = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.frame = view.bounds
}
// MARK: ListAdapterDataSource
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return months
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return MonthSectionController()
}
func emptyView(for listAdapter: ListAdapter) -> UIView? { return nil }
}
================================================
FILE: Examples/Examples-iOS/IGListKitExamples/ViewControllers/CompositionLayoutViewController.swift
================================================
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import IGListKit
import UIKit
/// Enables SectionControllers to return their own layout. In the future, we might want IGListKit
/// to handle this, but for now, lets keep it simple.
protocol CompositionLayoutCapable {
func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection?
}
/// Like MixedDataViewController, but using UICollectionViewCompositionalLayout
final class CompositionLayoutViewController: UIViewController, ListAdapterDataSource {
private var collectionView: UICollectionView?
private lazy var adapter: ListAdapter = {
return ListAdapter(updater: ListAdapterUpdater(), viewController: self)
}()
private let data: [Any] = [
ActivityItem(bodyText: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", header: "Activity Start"),
ActivityI
gitextract_na4i75rs/
├── .github/
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── RELEASE_CHECKLIST.md
│ └── workflows/
│ └── CI.yml
├── .gitignore
├── .slather.yml
├── .swiftlint.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dangerfile
├── Examples/
│ ├── Examples-iOS/
│ │ ├── IGListKitExamples/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ └── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── LaunchScreen.storyboard
│ │ │ ├── DelegateProtocols/
│ │ │ │ └── PostSectionControllerDelegate.swift
│ │ │ ├── Extensions/
│ │ │ │ ├── UIActivityIndicatorView+Extension.swift
│ │ │ │ └── UIColor+Extension.swift
│ │ │ ├── IGListKitExamples.entitlements
│ │ │ ├── Info.plist
│ │ │ ├── Models/
│ │ │ │ ├── APIService.swift
│ │ │ │ ├── ActivityItem.swift
│ │ │ │ ├── FeedItem.swift
│ │ │ │ ├── GridItem.swift
│ │ │ │ ├── HorizontalCardsSection.swift
│ │ │ │ ├── LoadingCellModel.swift
│ │ │ │ ├── Month.swift
│ │ │ │ ├── Post.h
│ │ │ │ ├── Post.m
│ │ │ │ ├── PostModel.swift
│ │ │ │ ├── RemodelGeneratedModels/
│ │ │ │ │ ├── PersonModel.h
│ │ │ │ │ ├── PersonModel.m
│ │ │ │ │ └── PersonModel.value
│ │ │ │ ├── SelectionModel.swift
│ │ │ │ ├── SwipeActionSection.swift
│ │ │ │ ├── User.swift
│ │ │ │ └── ViewModels/
│ │ │ │ ├── DayViewModel.swift
│ │ │ │ └── MonthTitleViewModel.swift
│ │ │ ├── SectionControllers/
│ │ │ │ ├── DemoSectionController.swift
│ │ │ │ ├── DisplaySectionController.swift
│ │ │ │ ├── EmbeddedSectionController.swift
│ │ │ │ ├── ExpandableSectionController.swift
│ │ │ │ ├── FeedItemSectionController.swift
│ │ │ │ ├── GridSectionController.swift
│ │ │ │ ├── HorizontalSectionController.swift
│ │ │ │ ├── LabelSectionController.swift
│ │ │ │ ├── ListeningSectionController.swift
│ │ │ │ ├── LoadingSectionController.swift
│ │ │ │ ├── MonthSectionController.swift
│ │ │ │ ├── PersonSectionController.h
│ │ │ │ ├── PersonSectionController.m
│ │ │ │ ├── PostSectionController.h
│ │ │ │ ├── PostSectionController.m
│ │ │ │ ├── PostSectionController.swift
│ │ │ │ ├── RemoveSectionController.swift
│ │ │ │ ├── ReorderableSectionController.swift
│ │ │ │ ├── SearchSectionController.swift
│ │ │ │ ├── SelfSizingSectionController.swift
│ │ │ │ ├── StoryboardLabelSectionController.swift
│ │ │ │ ├── UserSectionController.swift
│ │ │ │ ├── With Composable Layout/
│ │ │ │ │ ├── ActivityComposableSectionController.swift
│ │ │ │ │ ├── ExpandableComposableSectionController.swift
│ │ │ │ │ ├── GridComposableSectionController.swift
│ │ │ │ │ ├── HorizontalComposableSectionController.swift
│ │ │ │ │ ├── SelectionComposableSectionController.swift
│ │ │ │ │ ├── SwipeActionComposabelSectionController.swift
│ │ │ │ │ └── UserComposableSectionController.swift
│ │ │ │ └── WorkingRangeSectionController.swift
│ │ │ ├── Storyboard/
│ │ │ │ └── Demo.storyboard
│ │ │ ├── Systems/
│ │ │ │ └── IncrementAnnouncer.swift
│ │ │ ├── ViewControllers/
│ │ │ │ ├── AnnouncingDepsViewController.swift
│ │ │ │ ├── CalendarViewController.swift
│ │ │ │ ├── CompositionLayoutViewController.swift
│ │ │ │ ├── DemosViewController.swift
│ │ │ │ ├── DiffTableViewController.swift
│ │ │ │ ├── DisplayViewController.swift
│ │ │ │ ├── EmptyViewController.swift
│ │ │ │ ├── FeedViewController.swift
│ │ │ │ ├── IGListKitExamples-Bridging-Header.h
│ │ │ │ ├── LoadMoreViewController.swift
│ │ │ │ ├── MixedDataViewController.swift
│ │ │ │ ├── NestedAdapterViewController.swift
│ │ │ │ ├── ObjcDemoViewController.h
│ │ │ │ ├── ObjcDemoViewController.m
│ │ │ │ ├── ObjcGeneratedModelDemoViewController.h
│ │ │ │ ├── ObjcGeneratedModelDemoViewController.m
│ │ │ │ ├── ReorderableViewController.swift
│ │ │ │ ├── SearchViewController.swift
│ │ │ │ ├── SelfSizingCellsViewController.swift
│ │ │ │ ├── SingleSectionStoryboardViewController.swift
│ │ │ │ ├── SingleSectionViewController.swift
│ │ │ │ ├── StoryboardViewController.swift
│ │ │ │ ├── SupplementaryViewController.swift
│ │ │ │ └── WorkingRangeViewController.swift
│ │ │ └── Views/
│ │ │ ├── CalendarDayCell.swift
│ │ │ ├── CenterLabelCell.swift
│ │ │ ├── CommentCell.h
│ │ │ ├── CommentCell.m
│ │ │ ├── CompositionLayoutCell.swift
│ │ │ ├── DetailLabelCell.swift
│ │ │ ├── EmbeddedCollectionViewCell.swift
│ │ │ ├── FullWidthSelfSizingCell.swift
│ │ │ ├── ImageCell.swift
│ │ │ ├── InteractiveCell.h
│ │ │ ├── InteractiveCell.m
│ │ │ ├── LabelCell.swift
│ │ │ ├── LoadingCell.swift
│ │ │ ├── ManuallySelfSizingCell.swift
│ │ │ ├── MonthTitleCell.swift
│ │ │ ├── NibCell.swift
│ │ │ ├── NibCell.xib
│ │ │ ├── NibSelfSizingCell.swift
│ │ │ ├── NibSelfSizingCell.xib
│ │ │ ├── PersonCell.h
│ │ │ ├── PersonCell.m
│ │ │ ├── PhotoCell.h
│ │ │ ├── PhotoCell.m
│ │ │ ├── PostCell.swift
│ │ │ ├── RemoveCell.swift
│ │ │ ├── SearchCell.swift
│ │ │ ├── SpinnerCell.swift
│ │ │ ├── StoryboardCell.swift
│ │ │ ├── UserFooterView.swift
│ │ │ ├── UserFooterView.xib
│ │ │ ├── UserHeaderView.swift
│ │ │ ├── UserHeaderView.xib
│ │ │ ├── UserInfoCell.h
│ │ │ └── UserInfoCell.m
│ │ ├── IGListKitExamples-UITests/
│ │ │ ├── DemosViewControllerUITests.swift
│ │ │ ├── FeedViewController.swift
│ │ │ ├── Info.plist
│ │ │ ├── LoadMoreViewControllerUITests.swift
│ │ │ ├── MixedDataViewControllerUITests.swift
│ │ │ ├── SearchViewControllerUITests.swift
│ │ │ └── UITestCase.swift
│ │ ├── IGListKitExamples.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ ├── IGListKitExamples.xcscheme
│ │ │ ├── IGListKitMessageExample.xcscheme
│ │ │ └── IGListKitTodayExample.xcscheme
│ │ ├── IGListKitMessageExample/
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── Contents.json
│ │ │ │ └── iMessage App Icon.stickersiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Info.plist
│ │ │ └── MessagesViewController.swift
│ │ ├── IGListKitTodayExample/
│ │ │ ├── Info.plist
│ │ │ └── TodayViewController.swift
│ │ └── LICENSE-examples.md
│ ├── Examples-macOS/
│ │ ├── IGListKitExamples/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ └── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj/
│ │ │ │ └── Main.storyboard
│ │ │ ├── Data/
│ │ │ │ └── users.json
│ │ │ ├── Helpers/
│ │ │ │ ├── IndexSet+Extensions.swift
│ │ │ │ ├── Shuffle.swift
│ │ │ │ └── UsersProvider.swift
│ │ │ ├── Info.plist
│ │ │ ├── Models/
│ │ │ │ └── User.swift
│ │ │ ├── View/
│ │ │ │ ├── UserCollectionViewCell.swift
│ │ │ │ └── UserCollectionViewCell.xib
│ │ │ └── ViewControllers/
│ │ │ └── UsersViewController.swift
│ │ ├── IGListKitExamples.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── IGListKitExamples.xcscheme
│ │ └── LICENSE-examples.md
│ └── Examples-tvOS/
│ ├── IGListKitExamples/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── App Icon & Top Shelf Image.brandassets/
│ │ │ │ ├── App Icon - Large.imagestack/
│ │ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── App Icon - Small.imagestack/
│ │ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Top Shelf Image Wide.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Top Shelf Image.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── LaunchImage.launchimage/
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── Models/
│ │ │ └── NSObject+IGListDiffable.swift
│ │ ├── SectionControllers/
│ │ │ ├── CarouselSectionController.swift
│ │ │ ├── DemoSectionController.swift
│ │ │ ├── HorizontalSectionController.swift
│ │ │ └── LabelSectionController.swift
│ │ ├── ViewControllers/
│ │ │ ├── DemosViewController.swift
│ │ │ └── NestedAdapterViewController.swift
│ │ └── Views/
│ │ ├── CarouselCell.swift
│ │ ├── CarouselCell.xib
│ │ ├── DemoCell.swift
│ │ ├── EmbeddedCollectionViewCell.swift
│ │ └── LabelCell.swift
│ ├── IGListKitExamples.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── IGListKitExamples.xcscheme
│ └── LICENSE-examples.md
├── Gemfile
├── Guides/
│ ├── Best Practices and FAQ.md
│ ├── Generating your models using remodel.md
│ ├── Getting Started.md
│ ├── IGListDiffable and Equality.md
│ ├── Installation.md
│ ├── Migration.md
│ ├── Modeling and Binding.md
│ ├── VISION.md
│ ├── Working with Core Data.md
│ └── Working with UICollectionView.md
├── IGListDiffKit.podspec
├── IGListKit.podspec
├── IGListKit.xcodeproj/
│ ├── project.pbxproj
│ └── xcshareddata/
│ └── xcschemes/
│ ├── IGListKit-macOS.xcscheme
│ ├── IGListKit-tvOS.xcscheme
│ └── IGListKit.xcscheme
├── IGListSwiftKit.podspec
├── LICENSE.md
├── Package.swift
├── README.md
├── README.zh.md
├── Source/
│ ├── IGListDiffKit/
│ │ ├── IGListAssert.h
│ │ ├── IGListBatchUpdateData.h
│ │ ├── IGListBatchUpdateData.mm
│ │ ├── IGListCompatibility.h
│ │ ├── IGListDiff.h
│ │ ├── IGListDiff.mm
│ │ ├── IGListDiffKit.h
│ │ ├── IGListDiffable.h
│ │ ├── IGListExperiments.h
│ │ ├── IGListIndexPathResult.h
│ │ ├── IGListIndexPathResult.m
│ │ ├── IGListIndexSetResult.h
│ │ ├── IGListIndexSetResult.m
│ │ ├── IGListMacros.h
│ │ ├── IGListMoveIndex.h
│ │ ├── IGListMoveIndex.m
│ │ ├── IGListMoveIndexPath.h
│ │ ├── IGListMoveIndexPath.m
│ │ ├── Internal/
│ │ │ ├── IGListIndexPathResultInternal.h
│ │ │ ├── IGListIndexSetResultInternal.h
│ │ │ ├── IGListMoveIndexInternal.h
│ │ │ └── IGListMoveIndexPathInternal.h
│ │ ├── NSNumber+IGListDiffable.h
│ │ ├── NSNumber+IGListDiffable.m
│ │ ├── NSString+IGListDiffable.h
│ │ └── NSString+IGListDiffable.m
│ ├── IGListKit/
│ │ ├── IGListAdapter.h
│ │ ├── IGListAdapter.m
│ │ ├── IGListAdapterDataSource.h
│ │ ├── IGListAdapterDelegate.h
│ │ ├── IGListAdapterDelegateAnnouncer.h
│ │ ├── IGListAdapterDelegateAnnouncer.m
│ │ ├── IGListAdapterMoveDelegate.h
│ │ ├── IGListAdapterPerformanceDelegate.h
│ │ ├── IGListAdapterUpdateListener.h
│ │ ├── IGListAdapterUpdater.h
│ │ ├── IGListAdapterUpdater.m
│ │ ├── IGListAdapterUpdaterDelegate.h
│ │ ├── IGListBatchContext.h
│ │ ├── IGListBindable.h
│ │ ├── IGListBindingSectionController.h
│ │ ├── IGListBindingSectionController.m
│ │ ├── IGListBindingSectionControllerDataSource.h
│ │ ├── IGListBindingSectionControllerSelectionDelegate.h
│ │ ├── IGListBindingSingleSectionController.h
│ │ ├── IGListBindingSingleSectionController.m
│ │ ├── IGListCollectionContext.h
│ │ ├── IGListCollectionScrollingTraits.h
│ │ ├── IGListCollectionView.h
│ │ ├── IGListCollectionView.m
│ │ ├── IGListCollectionViewDelegateLayout.h
│ │ ├── IGListCollectionViewLayout.h
│ │ ├── IGListCollectionViewLayout.mm
│ │ ├── IGListCollectionViewLayoutCompatible.h
│ │ ├── IGListCollectionViewLayoutInvalidationContext.h
│ │ ├── IGListCollectionViewLayoutInvalidationContext.m
│ │ ├── IGListDisplayDelegate.h
│ │ ├── IGListGenericSectionController.h
│ │ ├── IGListGenericSectionController.m
│ │ ├── IGListKit.h
│ │ ├── IGListReloadDataUpdater.h
│ │ ├── IGListReloadDataUpdater.m
│ │ ├── IGListScrollDelegate.h
│ │ ├── IGListSectionController.h
│ │ ├── IGListSectionController.m
│ │ ├── IGListSingleSectionController.h
│ │ ├── IGListSingleSectionController.m
│ │ ├── IGListSupplementaryViewSource.h
│ │ ├── IGListTransitionData.h
│ │ ├── IGListTransitionData.m
│ │ ├── IGListTransitionDelegate.h
│ │ ├── IGListUpdatingDelegate.h
│ │ ├── IGListWorkingRangeDelegate.h
│ │ ├── Internal/
│ │ │ ├── IGListAdapter+DebugDescription.h
│ │ │ ├── IGListAdapter+DebugDescription.m
│ │ │ ├── IGListAdapter+UICollectionView.h
│ │ │ ├── IGListAdapter+UICollectionView.m
│ │ │ ├── IGListAdapterDelegateAnnouncerInternal.h
│ │ │ ├── IGListAdapterInternal.h
│ │ │ ├── IGListAdapterProxy.h
│ │ │ ├── IGListAdapterProxy.m
│ │ │ ├── IGListAdapterUpdater+DebugDescription.h
│ │ │ ├── IGListAdapterUpdater+DebugDescription.m
│ │ │ ├── IGListAdapterUpdaterHelpers.h
│ │ │ ├── IGListAdapterUpdaterHelpers.m
│ │ │ ├── IGListAdapterUpdaterInternal.h
│ │ │ ├── IGListArrayUtilsInternal.h
│ │ │ ├── IGListArrayUtilsInternal.m
│ │ │ ├── IGListBatchUpdateData+DebugDescription.h
│ │ │ ├── IGListBatchUpdateData+DebugDescription.m
│ │ │ ├── IGListBatchUpdateState.h
│ │ │ ├── IGListBatchUpdateTransaction.h
│ │ │ ├── IGListBatchUpdateTransaction.m
│ │ │ ├── IGListBindingSectionController+DebugDescription.h
│ │ │ ├── IGListBindingSectionController+DebugDescription.m
│ │ │ ├── IGListCollectionViewLayoutInternal.h
│ │ │ ├── IGListDataSourceChangeTransaction.h
│ │ │ ├── IGListDataSourceChangeTransaction.m
│ │ │ ├── IGListDebugger.h
│ │ │ ├── IGListDebugger.m
│ │ │ ├── IGListDebuggingUtilities.h
│ │ │ ├── IGListDebuggingUtilities.m
│ │ │ ├── IGListDefaultExperiments.h
│ │ │ ├── IGListDisplayHandler.h
│ │ │ ├── IGListDisplayHandler.m
│ │ │ ├── IGListItemUpdatesCollector.h
│ │ │ ├── IGListItemUpdatesCollector.m
│ │ │ ├── IGListPerformDiff.h
│ │ │ ├── IGListPerformDiff.m
│ │ │ ├── IGListReloadIndexPath.h
│ │ │ ├── IGListReloadIndexPath.m
│ │ │ ├── IGListReloadTransaction.h
│ │ │ ├── IGListReloadTransaction.m
│ │ │ ├── IGListSectionControllerInternal.h
│ │ │ ├── IGListSectionMap+DebugDescription.h
│ │ │ ├── IGListSectionMap+DebugDescription.m
│ │ │ ├── IGListSectionMap.h
│ │ │ ├── IGListSectionMap.m
│ │ │ ├── IGListUpdateCoalescer.h
│ │ │ ├── IGListUpdateCoalescer.m
│ │ │ ├── IGListUpdateTransactable.h
│ │ │ ├── IGListUpdateTransactionBuilder.h
│ │ │ ├── IGListUpdateTransactionBuilder.m
│ │ │ ├── IGListViewVisibilityTracker.h
│ │ │ ├── IGListViewVisibilityTracker.m
│ │ │ ├── IGListViewVisibilityTrackerInternal.h
│ │ │ ├── IGListWorkingRangeHandler.h
│ │ │ ├── IGListWorkingRangeHandler.mm
│ │ │ ├── UICollectionView+DebugDescription.h
│ │ │ ├── UICollectionView+DebugDescription.m
│ │ │ ├── UICollectionView+IGListBatchUpdateData.h
│ │ │ ├── UICollectionView+IGListBatchUpdateData.m
│ │ │ ├── UICollectionViewLayout+InteractiveReordering.h
│ │ │ ├── UICollectionViewLayout+InteractiveReordering.m
│ │ │ ├── UIScrollView+IGListKit.h
│ │ │ ├── UIScrollView+IGListKit.m
│ │ │ └── UIViewController+IGListAdapterInternal.h
│ │ ├── UIViewController+IGListAdapter.h
│ │ └── UIViewController+IGListAdapter.m
│ ├── IGListSwiftKit/
│ │ ├── IGListAdapter+Async.swift
│ │ ├── IGListCollectionContext+Refinements.swift
│ │ ├── IGListSingleSectionController+Refinements.swift
│ │ ├── IGListSwiftKit.h
│ │ ├── ListIdentifiable.swift
│ │ └── ListValueSectionController.swift
│ └── Info.plist
├── Tests/
│ ├── Assets/
│ │ ├── IGTestNibCell.xib
│ │ ├── IGTestNibSupplementaryView.xib
│ │ └── IGTestStoryboard.storyboard
│ ├── IGListAdapterDelegateAnnouncerTests.m
│ ├── IGListAdapterE2ETests.m
│ ├── IGListAdapterProxyTests.m
│ ├── IGListAdapterStoryboardTests.m
│ ├── IGListAdapterTests.m
│ ├── IGListAdapterUpdaterTests.m
│ ├── IGListBatchUpdateDataTests.m
│ ├── IGListBindingSectionControllerTests.m
│ ├── IGListBindingSingleSectionControllerTests.m
│ ├── IGListCollectionScrollingTraitsTests.m
│ ├── IGListCollectionViewLayoutTests.m
│ ├── IGListCollectionViewTests.m
│ ├── IGListContentInsetTests.m
│ ├── IGListDebugDescriptionTests.m
│ ├── IGListDebuggerTests.m
│ ├── IGListDiffDescriptionStringTests.m
│ ├── IGListDiffResultTests.m
│ ├── IGListDiffSwiftTests.swift
│ ├── IGListDiffTests.h
│ ├── IGListDiffTests.m
│ ├── IGListDisplayHandlerTests.m
│ ├── IGListGenericSectionControllerTests.m
│ ├── IGListInteractiveMovingTests.m
│ ├── IGListItemUpdatesCollectorTests.m
│ ├── IGListKitTests-Bridging-Header.h
│ ├── IGListPerformDiffTests.m
│ ├── IGListReloadDataUpdaterTests.m
│ ├── IGListSectionControllerTests.m
│ ├── IGListSectionMapTests.m
│ ├── IGListSingleNibItemControllerTests.m
│ ├── IGListSingleSectionControllerTests.m
│ ├── IGListSingleStoryboardItemControllerTests.m
│ ├── IGListTestCase.h
│ ├── IGListTestCase.m
│ ├── IGListTestHelpers.h
│ ├── IGListTransactionTests.m
│ ├── IGListUpdateCoalescerTests.m
│ ├── IGListViewVisibilityTrackerTests.m
│ ├── IGListWorkingRangeHandlerTests.m
│ ├── Info.plist
│ ├── Objects/
│ │ ├── IGLayoutTestDataSource.h
│ │ ├── IGLayoutTestDataSource.m
│ │ ├── IGLayoutTestItem.h
│ │ ├── IGLayoutTestItem.m
│ │ ├── IGLayoutTestSection.h
│ │ ├── IGLayoutTestSection.m
│ │ ├── IGListAdapterUpdateTester.h
│ │ ├── IGListAdapterUpdateTester.m
│ │ ├── IGListTestAdapterDataSource.h
│ │ ├── IGListTestAdapterDataSource.m
│ │ ├── IGListTestAdapterHorizontalDataSource.h
│ │ ├── IGListTestAdapterHorizontalDataSource.m
│ │ ├── IGListTestAdapterReorderingDataSource.h
│ │ ├── IGListTestAdapterReorderingDataSource.m
│ │ ├── IGListTestAdapterStoryboardDataSource.h
│ │ ├── IGListTestAdapterStoryboardDataSource.m
│ │ ├── IGListTestCollectionViewLayout.h
│ │ ├── IGListTestCollectionViewLayout.m
│ │ ├── IGListTestContainerSizeSection.h
│ │ ├── IGListTestContainerSizeSection.m
│ │ ├── IGListTestHorizontalSection.h
│ │ ├── IGListTestHorizontalSection.m
│ │ ├── IGListTestOffsettingLayout.h
│ │ ├── IGListTestOffsettingLayout.m
│ │ ├── IGListTestSection.h
│ │ ├── IGListTestSection.m
│ │ ├── IGListTestStoryboardSection.h
│ │ ├── IGListTestStoryboardSection.m
│ │ ├── IGListTestUICollectionViewDataSource.h
│ │ ├── IGListTestUICollectionViewDataSource.m
│ │ ├── IGTestBindingSingleItemDataSource.h
│ │ ├── IGTestBindingSingleItemDataSource.m
│ │ ├── IGTestBindingWithoutDeselectionDelegate.h
│ │ ├── IGTestBindingWithoutDeselectionDelegate.m
│ │ ├── IGTestCell.h
│ │ ├── IGTestCell.m
│ │ ├── IGTestDelegateController.h
│ │ ├── IGTestDelegateController.m
│ │ ├── IGTestDelegateDataSource.h
│ │ ├── IGTestDelegateDataSource.m
│ │ ├── IGTestDiffingDataSource.h
│ │ ├── IGTestDiffingDataSource.m
│ │ ├── IGTestDiffingObject.h
│ │ ├── IGTestDiffingObject.m
│ │ ├── IGTestDiffingSectionController.h
│ │ ├── IGTestDiffingSectionController.m
│ │ ├── IGTestInvalidateLayoutDataSource.h
│ │ ├── IGTestInvalidateLayoutDataSource.m
│ │ ├── IGTestInvalidateLayoutObject.h
│ │ ├── IGTestInvalidateLayoutObject.m
│ │ ├── IGTestInvalidateLayoutSectionController.h
│ │ ├── IGTestInvalidateLayoutSectionController.m
│ │ ├── IGTestNibSupplementaryView.h
│ │ ├── IGTestNibSupplementaryView.m
│ │ ├── IGTestNumberBindableCell.h
│ │ ├── IGTestNumberBindableCell.m
│ │ ├── IGTestObject.h
│ │ ├── IGTestObject.m
│ │ ├── IGTestReorderableSection.h
│ │ ├── IGTestReorderableSection.m
│ │ ├── IGTestSingleItemDataSource.h
│ │ ├── IGTestSingleItemDataSource.m
│ │ ├── IGTestSingleNibItemDataSource.h
│ │ ├── IGTestSingleNibItemDataSource.m
│ │ ├── IGTestSingleStoryboardItemDataSource.h
│ │ ├── IGTestSingleStoryboardItemDataSource.m
│ │ ├── IGTestSingleWithoutDeselectionDelegate.h
│ │ ├── IGTestSingleWithoutDeselectionDelegate.m
│ │ ├── IGTestStoryboardCell.h
│ │ ├── IGTestStoryboardCell.m
│ │ ├── IGTestStoryboardSupplementarySource.h
│ │ ├── IGTestStoryboardSupplementarySource.m
│ │ ├── IGTestStoryboardSupplementaryView.h
│ │ ├── IGTestStoryboardSupplementaryView.m
│ │ ├── IGTestStoryboardViewController.h
│ │ ├── IGTestStoryboardViewController.m
│ │ ├── IGTestStringBindableCell.h
│ │ ├── IGTestStringBindableCell.m
│ │ ├── IGTestSupplementarySource.h
│ │ └── IGTestSupplementarySource.m
│ └── UIViewControllerIGListAdapterTests.m
├── docs/
│ ├── Categories/
│ │ └── UIViewController(IGListAdapter).html
│ ├── Categories.html
│ ├── Classes/
│ │ ├── IGListAdapter.html
│ │ ├── IGListAdapterDelegateAnnouncer.html
│ │ ├── IGListAdapterUpdater.html
│ │ ├── IGListBatchUpdateData.html
│ │ ├── IGListBindingSectionController.html
│ │ ├── IGListBindingSingleSectionController.html
│ │ ├── IGListCollectionView.html
│ │ ├── IGListCollectionViewLayout.html
│ │ ├── IGListCollectionViewLayoutInvalidationContext.html
│ │ ├── IGListGenericSectionController.html
│ │ ├── IGListIndexPathResult.html
│ │ ├── IGListIndexSetResult.html
│ │ ├── IGListMoveIndex.html
│ │ ├── IGListMoveIndexPath.html
│ │ ├── IGListSectionController.html
│ │ ├── IGListSingleSectionController.html
│ │ └── IGListTransitionData.html
│ ├── Classes.html
│ ├── Constants.html
│ ├── Enums/
│ │ ├── IGListAdapterUpdateType.html
│ │ ├── IGListDiffOption.html
│ │ └── IGListExperiment.html
│ ├── Enums.html
│ ├── Functions.html
│ ├── Guides.html
│ ├── Protocols/
│ │ ├── IGListAdapterDataSource.html
│ │ ├── IGListAdapterDelegate.html
│ │ ├── IGListAdapterMoveDelegate.html
│ │ ├── IGListAdapterPerformanceDelegate.html
│ │ ├── IGListAdapterUpdateListener.html
│ │ ├── IGListAdapterUpdaterDelegate.html
│ │ ├── IGListBatchContext.html
│ │ ├── IGListBindable.html
│ │ ├── IGListBindingSectionControllerDataSource.html
│ │ ├── IGListBindingSectionControllerSelectionDelegate.html
│ │ ├── IGListCollectionContext.html
│ │ ├── IGListCollectionViewDelegateLayout.html
│ │ ├── IGListCollectionViewLayoutCompatible.html
│ │ ├── IGListDiffable.html
│ │ ├── IGListDisplayDelegate.html
│ │ ├── IGListScrollDelegate.html
│ │ ├── IGListSingleSectionControllerDelegate.html
│ │ ├── IGListSupplementaryViewSource.html
│ │ ├── IGListTransitionDelegate.html
│ │ ├── IGListUpdatingDelegate.html
│ │ └── IGListWorkingRangeDelegate.html
│ ├── Protocols.html
│ ├── Structs/
│ │ ├── IGListAdaptiveCoalescingExperimentConfig.html
│ │ ├── IGListAdaptiveDiffingExperimentConfig.html
│ │ └── IGListCollectionScrollingTraits.html
│ ├── Structs.html
│ ├── Type Definitions/
│ │ ├── IGListAdaptiveCoalescingExperimentConfig/
│ │ │ └── IGListAdaptiveCoalescingExperimentConfig.html
│ │ ├── IGListAdaptiveCoalescingExperimentConfig.html
│ │ ├── IGListAdaptiveDiffingExperimentConfig/
│ │ │ └── IGListAdaptiveDiffingExperimentConfig.html
│ │ ├── IGListAdaptiveDiffingExperimentConfig.html
│ │ ├── IGListCollectionScrollingTraits/
│ │ │ └── IGListCollectionScrollingTraits.html
│ │ └── IGListCollectionScrollingTraits.html
│ ├── Type Definitions.html
│ ├── best-practices-and-faq.html
│ ├── css/
│ │ ├── highlight.css
│ │ └── jazzy.css
│ ├── generating-your-models-using-remodel.html
│ ├── getting-started.html
│ ├── iglistdiffable-and-equality.html
│ ├── index.html
│ ├── installation.html
│ ├── js/
│ │ ├── jazzy.js
│ │ ├── jazzy.search.js
│ │ └── typeahead.jquery.js
│ ├── migration.html
│ ├── modeling-and-binding.html
│ ├── search.json
│ ├── undocumented.json
│ ├── vision.html
│ ├── working-with-core-data.html
│ └── working-with-uicollectionview.html
├── remodel-plugin/
│ ├── features/
│ │ └── iglistdiffable.feature
│ └── src/
│ ├── __tests__/
│ │ └── plugins/
│ │ └── iglistdiffable-test.ts
│ └── plugins/
│ ├── iglistdiffable-utils.ts
│ └── iglistdiffable.ts
└── scripts/
├── build_docs.sh
├── generate_spm_sources_layout.sh
├── lint.sh
└── version.sh
SYMBOL INDEX (72 symbols across 14 files)
FILE: Source/IGListDiffKit/IGListExperiments.h
type IGListAdaptiveDiffingExperimentConfig (line 37) | struct IGListAdaptiveDiffingExperimentConfig {
type IGListAdaptiveCoalescingExperimentConfig (line 52) | struct IGListAdaptiveCoalescingExperimentConfig {
function IGListExperimentEnabled (line 73) | NS_SWIFT_NAME(ListExperimentEnabled(mask:option:))
FILE: Source/IGListKit/IGListCollectionScrollingTraits.h
type IGListCollectionScrollingTraits (line 15) | struct IGListCollectionScrollingTraits {
FILE: Source/IGListKit/Internal/IGListAdapterInternal.h
function NSString (line 21) | NSString *IGListReusableViewIdentifier(Class viewClass, NSString * _Null...
FILE: Source/IGListKit/Internal/IGListBatchUpdateState.h
type IGListBatchUpdateStateIdle (line 10) | typedef NS_ENUM (NSInteger, IGListBatchUpdateState) {
FILE: Source/IGListKit/Internal/IGListCollectionViewLayoutInternal.h
function CGRect (line 10) | static inline CGRect IGListRectIntegralScaled(CGRect rect) {
FILE: Source/IGListKit/Internal/IGListDefaultExperiments.h
function IGListExperiment (line 17) | static inline IGListExperiment IGListDefaultExperiments(void) {
FILE: Source/IGListKit/Internal/IGListUpdateTransactable.h
function NS_ASSUME_NONNULL_BEGIN (line 19) | NS_ASSUME_NONNULL_BEGIN
FILE: Tests/IGListTestHelpers.h
function NSIndexPath (line 10) | static inline NSIndexPath *genIndexPath(NSInteger section, NSInteger ite...
FILE: docs/js/jazzy.js
function toggleItem (line 15) | function toggleItem($link, $content) {
function itemLinkToContent (line 21) | function itemLinkToContent($link) {
function openCurrentItemIfClosed (line 26) | function openCurrentItemIfClosed() {
FILE: docs/js/jazzy.search.js
function displayTemplate (line 10) | function displayTemplate(result) {
function suggestionTemplate (line 14) | function suggestionTemplate(result) {
FILE: docs/js/typeahead.jquery.js
function reverseArgs (line 55) | function reverseArgs(index, value) {
function template (line 100) | function template() {
function _p8 (line 153) | function _p8(s) {
function build (line 178) | function build(o) {
function buildHtml (line 197) | function buildHtml(c) {
function buildSelectors (line 203) | function buildSelectors(classes) {
function buildCss (line 210) | function buildCss() {
function EventBus (line 267) | function EventBus(o) {
function on (line 304) | function on(method, types, cb, context) {
function onAsync (line 321) | function onAsync(types, cb, context) {
function onSync (line 324) | function onSync(types, cb, context) {
function off (line 327) | function off(types) {
function trigger (line 338) | function trigger(types) {
function getFlush (line 352) | function getFlush(callbacks, context, args) {
function getNextTick (line 362) | function getNextTick() {
function bindContext (line 379) | function bindContext(fn, context) {
function hightlightTextNode (line 433) | function hightlightTextNode(textNode) {
function traverse (line 445) | function traverse(el, hightlightTextNode) {
function accent_replacer (line 457) | function accent_replacer(chr) {
function getRegex (line 460) | function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensiti...
function Input (line 485) | function Input(o, www) {
function buildOverflowHelper (line 685) | function buildOverflowHelper($input) {
function areQueriesEquivalent (line 702) | function areQueriesEquivalent(a, b) {
function withModifier (line 705) | function withModifier($e) {
function Dataset (line 718) | function Dataset(o, www) {
function sync (line 859) | function sync(suggestions) {
function async (line 871) | function async(suggestions) {
function getDisplayFn (line 896) | function getDisplayFn(display) {
function getTemplates (line 903) | function getTemplates(templates, displayFn) {
function isValidName (line 919) | function isValidName(str) {
function Menu (line 925) | function Menu(o, www) {
function updateDataset (line 1047) | function updateDataset(dataset) {
function clearDataset (line 1055) | function clearDataset(dataset) {
function destroyDataset (line 1063) | function destroyDataset(dataset) {
function Status (line 1072) | function Status(options) {
function DefaultMenu (line 1122) | function DefaultMenu() {
function Typeahead (line 1165) | function Typeahead(o, www) {
function c (line 1448) | function c(ctx) {
function attach (line 1474) | function attach() {
function ttEach (line 1633) | function ttEach($els, fn) {
function buildHintFromInput (line 1639) | function buildHintFromInput($input, www) {
function prepInput (line 1648) | function prepInput($input, www) {
function getBackgroundStyles (line 1663) | function getBackgroundStyles($el) {
function revert (line 1675) | function revert($input) {
function $elOrNull (line 1688) | function $elOrNull(obj) {
FILE: remodel-plugin/src/__tests__/plugins/iglistdiffable-test.ts
function igListDiffableIsEqualMethod (line 20) | function igListDiffableIsEqualMethod(): ObjC.Method {
function igListDiffableDiffIdentifierMethodWithCode (line 50) | function igListDiffableDiffIdentifierMethodWithCode(code: string): ObjC....
FILE: remodel-plugin/src/plugins/iglistdiffable-utils.ts
function isEqualToDiffableObjectMethod (line 14) | function isEqualToDiffableObjectMethod(): ObjC.Method {
function functionReturnValueForIvarWithFunctionName (line 44) | function functionReturnValueForIvarWithFunctionName(
function formattedStringValueForIvarWithFormatSpecifier (line 51) | function formattedStringValueForIvarWithFormatSpecifier(
function nullableObjectValueWithFallback (line 68) | function nullableObjectValueWithFallback(
function wrappedInNSValueForTypeName (line 77) | function wrappedInNSValueForTypeName(iVarString: string, typeName: strin...
function objectValueForAttribute (line 81) | function objectValueForAttribute(
FILE: remodel-plugin/src/plugins/iglistdiffable.ts
function diffIdentiferAttributeFilter (line 16) | function diffIdentiferAttributeFilter(
function diffIdentifierMethodImplementation (line 24) | function diffIdentifierMethodImplementation(
function diffIdentifierMethod (line 45) | function diffIdentifierMethod(objectType: ObjectSpec.Type): ObjC.Method {
function createPlugin (line 68) | function createPlugin(): ObjectSpec.Plugin {
Condensed preview — 574 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,255K chars).
[
{
"path": ".github/CONTRIBUTING.md",
"chars": 3435,
"preview": "# Contributing to IGListKit\n\nWe want to make contributing to this project as easy and transparent as\npossible, and activ"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 704,
"preview": "## New issue checklist\n\n- [ ] I have reviewed the [`README`](https://github.com/Instagram/IGListKit/blob/main/README.md)"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 412,
"preview": "## Changes in this pull request\n\nIssue fixed: #\n\n### Checklist\n\n- [ ] All tests pass. Demo project builds and runs.\n- [ "
},
{
"path": ".github/RELEASE_CHECKLIST.md",
"chars": 817,
"preview": "# Release Checklist\n\nHere are the steps for creating and publishing a new release for `IGListKit`.\n\n- Final review and u"
},
{
"path": ".github/workflows/CI.yml",
"chars": 11138,
"preview": "name: \"IGListKit CI\"\n\non:\n push:\n branches:\n - main\n pull_request:\n branches:\n - '*'\n\njobs:\n macOS:\n "
},
{
"path": ".gitignore",
"chars": 1241,
"preview": ".DS_Store\n\nPodfile.lock\nGemfile.lock\n\n# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Obj"
},
{
"path": ".slather.yml",
"chars": 193,
"preview": "ci_service: github\ncoverage_service: coveralls\nxcodeproj: IGListKit.xcodeproj\nworkspace: IGListKit.xcworkspace\nscheme: I"
},
{
"path": ".swiftlint.yml",
"chars": 823,
"preview": "included:\n - Examples\n - Source/IGListSwiftKit\n\nexcluded:\n - Pods\n\nopt_in_rules:\n - empty_count\n - number_separator"
},
{
"path": "CHANGELOG.md",
"chars": 57790,
"preview": "# CHANGELOG\n\nThe changelog for `IGListKit`. Also see the [releases](https://github.com/instagram/IGListKit/releases) on "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3356,
"preview": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and"
},
{
"path": "Dangerfile",
"chars": 2286,
"preview": "not_declared_trivial = !(github.pr_title.include? \"#trivial\")\nhas_source_changes = !git.modified_files.grep(/Source/).em"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/AppDelegate.swift",
"chars": 1736,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 211,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"AppIcon.png\",\n \"idiom\" : \"universal\",\n \"platform\" : \"ios\",\n \"s"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Base.lproj/LaunchScreen.storyboard",
"chars": 2825,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/DelegateProtocols/PostSectionControllerDelegate.swift",
"chars": 471,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Extensions/UIActivityIndicatorView+Extension.swift",
"chars": 427,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Extensions/UIColor+Extension.swift",
"chars": 1654,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/IGListKitExamples.entitlements",
"chars": 295,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Info.plist",
"chars": 1323,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/APIService.swift",
"chars": 2449,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/ActivityItem.swift",
"chars": 866,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/FeedItem.swift",
"chars": 854,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/GridItem.swift",
"chars": 899,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/HorizontalCardsSection.swift",
"chars": 871,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/LoadingCellModel.swift",
"chars": 1083,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/Month.swift",
"chars": 778,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/Post.h",
"chars": 653,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/Post.m",
"chars": 744,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/PostModel.swift",
"chars": 2068,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.h",
"chars": 836,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.m",
"chars": 2109,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.value",
"chars": 122,
"preview": "PersonModel includes(IGListDiffable) {\n NSString *firstName\n NSString *lastName\n %diffIdentifier\n NSString *uniqueId"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/SelectionModel.swift",
"chars": 727,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/SwipeActionSection.swift",
"chars": 532,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/User.swift",
"chars": 810,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/DayViewModel.swift",
"chars": 978,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/MonthTitleViewModel.swift",
"chars": 768,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/DemoSectionController.swift",
"chars": 3979,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/DisplaySectionController.swift",
"chars": 1940,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/EmbeddedSectionController.swift",
"chars": 1096,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/ExpandableSectionController.swift",
"chars": 1394,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/FeedItemSectionController.swift",
"chars": 2792,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/GridSectionController.swift",
"chars": 1706,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/HorizontalSectionController.swift",
"chars": 1538,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/LabelSectionController.swift",
"chars": 802,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/ListeningSectionController.swift",
"chars": 1276,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/LoadingSectionController.swift",
"chars": 1302,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/MonthSectionController.swift",
"chars": 4751,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.h",
"chars": 278,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.m",
"chars": 1018,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.h",
"chars": 276,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.m",
"chars": 1740,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.swift",
"chars": 2363,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/RemoveSectionController.swift",
"chars": 1318,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/ReorderableSectionController.swift",
"chars": 889,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/SearchSectionController.swift",
"chars": 1973,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/SelfSizingSectionController.swift",
"chars": 1897,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/StoryboardLabelSectionController.swift",
"chars": 1234,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/UserSectionController.swift",
"chars": 1102,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ActivityComposableSectionController.swift",
"chars": 5984,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ExpandableComposableSectionController.swift",
"chars": 1907,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/GridComposableSectionController.swift",
"chars": 1969,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/HorizontalComposableSectionController.swift",
"chars": 2111,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SelectionComposableSectionController.swift",
"chars": 4394,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SwipeActionComposabelSectionController.swift",
"chars": 2379,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/UserComposableSectionController.swift",
"chars": 1211,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/WorkingRangeSectionController.swift",
"chars": 2876,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Storyboard/Demo.storyboard",
"chars": 12303,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Systems/IncrementAnnouncer.swift",
"chars": 746,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/AnnouncingDepsViewController.swift",
"chars": 1918,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/CalendarViewController.swift",
"chars": 2118,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/CompositionLayoutViewController.swift",
"chars": 5232,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/DemosViewController.swift",
"chars": 6277,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/DiffTableViewController.swift",
"chars": 2998,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/DisplayViewController.swift",
"chars": 1253,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/EmptyViewController.swift",
"chars": 2675,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/FeedViewController.swift",
"chars": 6661,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/IGListKitExamples-Bridging-Header.h",
"chars": 275,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/LoadMoreViewController.swift",
"chars": 2927,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/MixedDataViewController.swift",
"chars": 4909,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/NestedAdapterViewController.swift",
"chars": 1650,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcDemoViewController.h",
"chars": 275,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcDemoViewController.m",
"chars": 3229,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcGeneratedModelDemoViewController.h",
"chars": 289,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcGeneratedModelDemoViewController.m",
"chars": 3817,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ReorderableViewController.swift",
"chars": 2839,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SearchViewController.swift",
"chars": 3241,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SelfSizingCellsViewController.swift",
"chars": 3372,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SingleSectionStoryboardViewController.swift",
"chars": 2381,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SingleSectionViewController.swift",
"chars": 2736,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/StoryboardViewController.swift",
"chars": 2897,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SupplementaryViewController.swift",
"chars": 1754,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/WorkingRangeViewController.swift",
"chars": 1504,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/CalendarDayCell.swift",
"chars": 2068,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/CenterLabelCell.swift",
"chars": 814,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/CommentCell.h",
"chars": 314,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/CommentCell.m",
"chars": 1277,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/CompositionLayoutCell.swift",
"chars": 1949,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/DetailLabelCell.swift",
"chars": 1440,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/EmbeddedCollectionViewCell.swift",
"chars": 831,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/FullWidthSelfSizingCell.swift",
"chars": 2749,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/ImageCell.swift",
"chars": 1444,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/InteractiveCell.h",
"chars": 272,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/InteractiveCell.m",
"chars": 3060,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/LabelCell.swift",
"chars": 6498,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/LoadingCell.swift",
"chars": 1249,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/ManuallySelfSizingCell.swift",
"chars": 2757,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/MonthTitleCell.swift",
"chars": 1081,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/NibCell.swift",
"chars": 423,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/NibCell.xib",
"chars": 4817,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/NibSelfSizingCell.swift",
"chars": 477,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/NibSelfSizingCell.xib",
"chars": 4367,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/PersonCell.h",
"chars": 336,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/PersonCell.m",
"chars": 3879,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/PhotoCell.h",
"chars": 266,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/PhotoCell.m",
"chars": 897,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/PostCell.swift",
"chars": 10845,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/RemoveCell.swift",
"chars": 1580,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/SearchCell.swift",
"chars": 609,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/SpinnerCell.swift",
"chars": 1196,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/StoryboardCell.swift",
"chars": 460,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/UserFooterView.swift",
"chars": 497,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/UserFooterView.xib",
"chars": 4227,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/UserHeaderView.swift",
"chars": 672,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/UserHeaderView.xib",
"chars": 4184,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/UserInfoCell.h",
"chars": 312,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples/Views/UserInfoCell.m",
"chars": 1960,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples-UITests/DemosViewControllerUITests.swift",
"chars": 4006,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples-UITests/FeedViewController.swift",
"chars": 4413,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples-UITests/Info.plist",
"chars": 701,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples-UITests/LoadMoreViewControllerUITests.swift",
"chars": 1027,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples-UITests/MixedDataViewControllerUITests.swift",
"chars": 3355,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples-UITests/SearchViewControllerUITests.swift",
"chars": 1583,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples-UITests/UITestCase.swift",
"chars": 3369,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/project.pbxproj",
"chars": 96204,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme",
"chars": 3817,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1500\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitMessageExample.xcscheme",
"chars": 4603,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1500\"\n wasCreatedForAppExtension = \"YES\"\n ve"
},
{
"path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitTodayExample.xcscheme",
"chars": 4541,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1500\"\n wasCreatedForAppExtension = \"YES\"\n ve"
},
{
"path": "Examples/Examples-iOS/IGListKitMessageExample/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-iOS/IGListKitMessageExample/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json",
"chars": 985,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"60x45\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "Examples/Examples-iOS/IGListKitMessageExample/Info.plist",
"chars": 1001,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Examples/Examples-iOS/IGListKitMessageExample/MessagesViewController.swift",
"chars": 1644,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/IGListKitTodayExample/Info.plist",
"chars": 988,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Examples/Examples-iOS/IGListKitTodayExample/TodayViewController.swift",
"chars": 1995,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-iOS/LICENSE-examples.md",
"chars": 637,
"preview": "Copyright (c) Meta Platforms, Inc. and affiliates.\n\nThe examples provided by Facebook are for non-commercial testing and"
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/AppDelegate.swift",
"chars": 438,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 903,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"mac\",\n \"size\" : \"16x16\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Base.lproj/Main.storyboard",
"chars": 67054,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" t"
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Data/users.json",
"chars": 4730,
"preview": "[{\n\t\"name\": \"AMELIA\"\n}, \n{\n\t\"name\": \"OLIVIA\"\n}, \n{\n\t\"name\": \"EMILY\"\n}, \n{\n\t\"name\": \"AVA\"\n}, \n{\n\t\"name\": \"ISLA\"\n}, \n{\n\t\"n"
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Helpers/IndexSet+Extensions.swift",
"chars": 321,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Helpers/Shuffle.swift",
"chars": 980,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Helpers/UsersProvider.swift",
"chars": 837,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Info.plist",
"chars": 1032,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/Models/User.swift",
"chars": 737,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/View/UserCollectionViewCell.swift",
"chars": 709,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/View/UserCollectionViewCell.xib",
"chars": 5916,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "Examples/Examples-macOS/IGListKitExamples/ViewControllers/UsersViewController.swift",
"chars": 5113,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-macOS/IGListKitExamples.xcodeproj/project.pbxproj",
"chars": 18628,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Examples/Examples-macOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme",
"chars": 3901,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1500\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "Examples/Examples-macOS/LICENSE-examples.md",
"chars": 637,
"preview": "Copyright (c) Meta Platforms, Inc. and affiliates.\n\nThe examples provided by Facebook are for non-commercial testing and"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/AppDelegate.swift",
"chars": 686,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json",
"chars": 250,
"preview": "{\n \"layers\" : [\n {\n \"filename\" : \"Front.imagestacklayer\"\n },\n {\n \"filename\" : \"Middle.imagestacklaye"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json",
"chars": 250,
"preview": "{\n \"layers\" : [\n {\n \"filename\" : \"Front.imagestacklayer\"\n },\n {\n \"filename\" : \"Middle.imagestacklaye"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json",
"chars": 667,
"preview": "{\n \"assets\" : [\n {\n \"size\" : \"1280x768\",\n \"idiom\" : \"tv\",\n \"filename\" : \"App Icon - Large.imagestack\""
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json",
"chars": 137,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"tv\",\n \"scale\" : \"1x\"\n }\n ],\n \"info\" : {\n \"version\" : 1,\n \"author"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/LaunchImage.launchimage/Contents.json",
"chars": 244,
"preview": "{\n \"images\" : [\n {\n \"orientation\" : \"landscape\",\n \"idiom\" : \"tv\",\n \"extent\" : \"full-screen\",\n \"m"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Info.plist",
"chars": 926,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Models/NSObject+IGListDiffable.swift",
"chars": 459,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/CarouselSectionController.swift",
"chars": 1468,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/DemoSectionController.swift",
"chars": 2127,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/HorizontalSectionController.swift",
"chars": 1814,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/LabelSectionController.swift",
"chars": 916,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/ViewControllers/DemosViewController.swift",
"chars": 1429,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/ViewControllers/NestedAdapterViewController.swift",
"chars": 1526,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Views/CarouselCell.swift",
"chars": 688,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Views/CarouselCell.xib",
"chars": 3083,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder.AppleTV.XIB\" version=\""
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Views/DemoCell.swift",
"chars": 1077,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Views/EmbeddedCollectionViewCell.swift",
"chars": 901,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples/Views/LabelCell.swift",
"chars": 2000,
"preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples.xcodeproj/project.pbxproj",
"chars": 20985,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Examples/Examples-tvOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme",
"chars": 3317,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1500\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "Examples/Examples-tvOS/LICENSE-examples.md",
"chars": 637,
"preview": "Copyright (c) Meta Platforms, Inc. and affiliates.\n\nThe examples provided by Facebook are for non-commercial testing and"
},
{
"path": "Gemfile",
"chars": 174,
"preview": "source 'https://rubygems.org'\n\ngem 'cocoapods', '~> 1.16.2'\ngem 'danger', '~> 9.3.1'\ngem 'danger-swiftlint', '~> 0.33.0'"
},
{
"path": "Guides/Best Practices and FAQ.md",
"chars": 8761,
"preview": "# Best Practices and FAQs\n\nThis guide provides notes and details on best practices in using `IGListKit`, general tips, a"
},
{
"path": "Guides/Generating your models using remodel.md",
"chars": 4903,
"preview": "# Generating your IGListDiffable models using remodel\n\nWith the `IGListDiffable` plugin for [remodel by facebook](https:"
},
{
"path": "Guides/Getting Started.md",
"chars": 7253,
"preview": "# Getting Started\n\nThis guide provides a brief overview for how to get started using `IGListKit`.\n\n## Creating your firs"
}
]
// ... and 374 more files (download for full content)
About this extraction
This page contains the full source code of the Instagram/IGListKit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 574 files (4.8 MB), approximately 1.3M tokens, and a symbol index with 72 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.