diff --git a/.gitignore b/.gitignore index fa9f161..5453843 100755 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,8 @@ xcuserdata/ Carthage/Checkouts Carthage/Build +/**/Carthage/Checkouts +/**/Carthage/Build # fastlane # diff --git a/CollectionViewTools.podspec b/CollectionViewTools.podspec index 748ef14..66e6094 100644 --- a/CollectionViewTools.podspec +++ b/CollectionViewTools.podspec @@ -8,7 +8,8 @@ Pod::Spec.new do |s| s.name = 'CollectionViewTools' - s.version = '0.1.1' + s.version = '0.1.5' + s.tag = '0.1.5' s.summary = 'Powerful tool for making UICollectionView usage simple and comfortable.' # This description is used to generate tags and improve search results. @@ -26,10 +27,10 @@ Effective framework, similar to TableViewTools for making your UICollectionView s.author = { 'Dmitry Frishbuter' => 'dmitry.frishbuter@rosberry.com' } s.source = { :git => 'https://github.com/rosberry/CollectionViewTools.git', :tag => s.version.to_s } - s.ios.deployment_target = '8.2' + s.ios.deployment_target = '10.3' s.source_files = 'Sources/**/*' - + # s.resource_bundles = { # 'CollectionViewTools' => ['Assets/*.png'] # } diff --git a/CollectionViewTools.xcodeproj/project.pbxproj b/CollectionViewTools.xcodeproj/project.pbxproj index b642019..f35dab0 100644 --- a/CollectionViewTools.xcodeproj/project.pbxproj +++ b/CollectionViewTools.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 017B9F0C2409129800C765BD /* TestAsyncCollectionViewCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017B9F0B2409129800C765BD /* TestAsyncCollectionViewCellItem.swift */; }; 019849BB2508E6C800D217B4 /* Collection+Safe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019849BA2508E6C800D217B4 /* Collection+Safe.swift */; }; 01F2086323F67657009B069E /* TestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2086223F67657009B069E /* TestViewController.swift */; }; + 01F2E324267B2B550019B822 /* CellUpdateMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2E323267B2B550019B822 /* CellUpdateMode.swift */; }; 0A37632F1F6251A600A80613 /* CollectionViewTools.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A3763251F6251A600A80613 /* CollectionViewTools.framework */; }; 0A3763341F6251A600A80613 /* CollectionViewManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3763331F6251A600A80613 /* CollectionViewManagerTests.swift */; }; 0A3763671F62545A00A80613 /* ClosureWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3763521F62545A00A80613 /* ClosureWrapper.swift */; }; @@ -89,6 +90,7 @@ 017B9F0B2409129800C765BD /* TestAsyncCollectionViewCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAsyncCollectionViewCellItem.swift; sourceTree = ""; }; 019849BA2508E6C800D217B4 /* Collection+Safe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Safe.swift"; sourceTree = ""; }; 01F2086223F67657009B069E /* TestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestViewController.swift; sourceTree = ""; }; + 01F2E323267B2B550019B822 /* CellUpdateMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellUpdateMode.swift; sourceTree = ""; }; 06B2AE0E21F6FFE8004A9CBB /* CollectionViewTools.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = CollectionViewTools.podspec; sourceTree = ""; }; 0A3763251F6251A600A80613 /* CollectionViewTools.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CollectionViewTools.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0A37632E1F6251A600A80613 /* CollectionViewToolsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CollectionViewToolsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -226,6 +228,7 @@ children = ( 0A37635C1F62545A00A80613 /* Info.plist */, 0A3763541F62545A00A80613 /* CollectionViewTools.h */, + 01F2E323267B2B550019B822 /* CellUpdateMode.swift */, 0A3763531F62545A00A80613 /* CollectionViewManager.swift */, 01078BF925C11F7700A11E1D /* SectionItemsProvider */, 0E0F4096222D4F0600B88DF3 /* Diff */, @@ -509,6 +512,7 @@ 0176C9D1258A0541006CA94C /* CollectionViewViewCell.swift in Sources */, 015A8AA9231394FC002600FF /* CellItemFactory.swift in Sources */, 01078C0225C1270D00A11E1D /* ViewCellItemsFactory.swift in Sources */, + 01F2E324267B2B550019B822 /* CellUpdateMode.swift in Sources */, 0A37636B1F62545A00A80613 /* CollectionViewManager+UICollectionViewDataSourcePrefetching.swift in Sources */, 0A3763741F62545A00A80613 /* CollectionViewReusableViewItem.swift in Sources */, 0E0F40A1222D4F0600B88DF3 /* CollectionViewDiffAdaptor.swift in Sources */, diff --git a/Example/Cartfile b/Example/Cartfile index da8f15e..6b0f006 100644 --- a/Example/Cartfile +++ b/Example/Cartfile @@ -1 +1,2 @@ github "Instagram/IGListKit" +github "onmyway133/DeepDiff" \ No newline at end of file diff --git a/Example/Cartfile.resolved b/Example/Cartfile.resolved index f8b0dc2..a4cb627 100644 --- a/Example/Cartfile.resolved +++ b/Example/Cartfile.resolved @@ -1 +1,2 @@ github "Instagram/IGListKit" "3.4.0" +github "onmyway133/DeepDiff" "2.3.3" diff --git a/Example/Carthage/xcfilelists/CollectionViewToolsDiffExample-inputPaths.xcfilelist b/Example/Carthage/xcfilelists/CollectionViewToolsDiffExample-inputPaths.xcfilelist new file mode 100644 index 0000000..64147b4 --- /dev/null +++ b/Example/Carthage/xcfilelists/CollectionViewToolsDiffExample-inputPaths.xcfilelist @@ -0,0 +1,2 @@ +$(SRCROOT)/Carthage/Build/iOS/DeepDiff.framework +$(SRCROOT)/Carthage/Build/iOS/IGListKit.framework \ No newline at end of file diff --git a/Example/Carthage/xcfilelists/CollectionViewToolsDiffExample-outputPaths.xcfilelist b/Example/Carthage/xcfilelists/CollectionViewToolsDiffExample-outputPaths.xcfilelist new file mode 100644 index 0000000..ea3b83e --- /dev/null +++ b/Example/Carthage/xcfilelists/CollectionViewToolsDiffExample-outputPaths.xcfilelist @@ -0,0 +1,2 @@ +$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/DeepDiff.framework +$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/IGListKit.framework \ No newline at end of file diff --git a/Example/Carthage/xcfilelists/CollectionViewToolsExample-inputPaths.xcfilelist b/Example/Carthage/xcfilelists/CollectionViewToolsExample-inputPaths.xcfilelist new file mode 100644 index 0000000..e69de29 diff --git a/Example/Carthage/xcfilelists/CollectionViewToolsExample-outputPaths.xcfilelist b/Example/Carthage/xcfilelists/CollectionViewToolsExample-outputPaths.xcfilelist new file mode 100644 index 0000000..e69de29 diff --git a/Example/Carthage/xcfilelists/FactoriesExample-inputPaths.xcfilelist b/Example/Carthage/xcfilelists/FactoriesExample-inputPaths.xcfilelist new file mode 100644 index 0000000..9be57aa --- /dev/null +++ b/Example/Carthage/xcfilelists/FactoriesExample-inputPaths.xcfilelist @@ -0,0 +1 @@ +$(SRCROOT)/Carthage/Build/iOS/DeepDiff.framework \ No newline at end of file diff --git a/Example/Carthage/xcfilelists/FactoriesExample-outputPaths.xcfilelist b/Example/Carthage/xcfilelists/FactoriesExample-outputPaths.xcfilelist new file mode 100644 index 0000000..25f89c8 --- /dev/null +++ b/Example/Carthage/xcfilelists/FactoriesExample-outputPaths.xcfilelist @@ -0,0 +1 @@ +$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/DeepDiff.framework \ No newline at end of file diff --git a/Example/CollectionViewToolsExample.xcodeproj/project.pbxproj b/Example/CollectionViewToolsExample.xcodeproj/project.pbxproj index 38fe241..6e388b7 100644 --- a/Example/CollectionViewToolsExample.xcodeproj/project.pbxproj +++ b/Example/CollectionViewToolsExample.xcodeproj/project.pbxproj @@ -3,31 +3,48 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ 01078BF725C11F5500A11E1D /* CollectionViewTools.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01078BF625C11F5500A11E1D /* CollectionViewTools.framework */; }; 01078BF825C11F5500A11E1D /* CollectionViewTools.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 01078BF625C11F5500A11E1D /* CollectionViewTools.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 0142A91E25249F3400A1CBC0 /* ContentViewSectionItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0142A91D25249F3400A1CBC0 /* ContentViewSectionItemsFactory.swift */; }; - 0147997925D4E84100287F51 /* DescriptionViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997525D4E84100287F51 /* DescriptionViewState.swift */; }; - 0147997A25D4E84100287F51 /* ViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997625D4E84100287F51 /* ViewState.swift */; }; - 0147997B25D4E84100287F51 /* Expandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997725D4E84100287F51 /* Expandable.swift */; }; - 0147997C25D4E84100287F51 /* DividerViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997825D4E84100287F51 /* DividerViewState.swift */; }; - 015F03FB258772A50033F11C /* LazySectionItemsExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 015F03FA258772A50033F11C /* LazySectionItemsExampleViewController.swift */; }; + 0113EA90267A171200E5A399 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A3763891F62556300A80613 /* Assets.xcassets */; }; + 0113EA92267A171600E5A399 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0A37638B1F62556400A80613 /* LaunchScreen.storyboard */; }; + 0113EA95267A17FC00E5A399 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3763821F62556300A80613 /* AppDelegate.swift */; }; 015F03FE258775D00033F11C /* HeaderViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1078655322E1E5C60075C74A /* HeaderViewItem.swift */; }; 015F040125877EC00033F11C /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1078655622E1E7060075C74A /* HeaderView.swift */; }; 0180E950258A170B0061788E /* ImageContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0180E94F258A170B0061788E /* ImageContentView.swift */; }; 0180E952258A19250061788E /* TextContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0180E951258A19250061788E /* TextContentView.swift */; }; 0180E954258A1F7A0061788E /* SpacerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0180E953258A1F7A0061788E /* SpacerView.swift */; }; - 0186E537252493980032B88D /* FactoryExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01929DAD22F19233004D5605 /* FactoryExampleViewController.swift */; }; - 0186E53A252496E80032B88D /* Content.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E539252496E80032B88D /* Content.swift */; }; - 0186E53C252497500032B88D /* ImageContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E53B252497500032B88D /* ImageContent.swift */; }; - 0186E53E252497EC0032B88D /* TextContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E53D252497EC0032B88D /* TextContent.swift */; }; - 0186E543252498A70032B88D /* ImageViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E542252498A70032B88D /* ImageViewState.swift */; }; - 0186E5452524997D0032B88D /* TextViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E5442524997D0032B88D /* TextViewState.swift */; }; - 0186E54825249A2C0032B88D /* ContentProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E54725249A2C0032B88D /* ContentProvider.swift */; }; 01C2CC1622F4377C00873DC0 /* SpacerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01C2CC1522F4377C00873DC0 /* SpacerCell.swift */; }; + 01F2E282267A1AC00019B822 /* FactoriesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2E281267A1AC00019B822 /* FactoriesViewController.swift */; }; + 01F2E287267A1DCD0019B822 /* ContentViewSectionItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0142A91D25249F3400A1CBC0 /* ContentViewSectionItemsFactory.swift */; }; + 01F2E28D267A1DF50019B822 /* ViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997625D4E84100287F51 /* ViewState.swift */; }; + 01F2E28E267A1DF50019B822 /* ImageViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E542252498A70032B88D /* ImageViewState.swift */; }; + 01F2E28F267A1DF50019B822 /* TextViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E5442524997D0032B88D /* TextViewState.swift */; }; + 01F2E290267A1DF50019B822 /* Expandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997725D4E84100287F51 /* Expandable.swift */; }; + 01F2E291267A1DF50019B822 /* DividerViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997825D4E84100287F51 /* DividerViewState.swift */; }; + 01F2E292267A1DF50019B822 /* DescriptionViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0147997525D4E84100287F51 /* DescriptionViewState.swift */; }; + 01F2E296267A1E130019B822 /* FactoryExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01929DAD22F19233004D5605 /* FactoryExampleViewController.swift */; }; + 01F2E299267A1E1D0019B822 /* LazySectionItemsExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 015F03FA258772A50033F11C /* LazySectionItemsExampleViewController.swift */; }; + 01F2E29C267A1EA60019B822 /* TextContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E53D252497EC0032B88D /* TextContent.swift */; }; + 01F2E29D267A1EA60019B822 /* Content.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E539252496E80032B88D /* Content.swift */; }; + 01F2E29E267A1EA60019B822 /* ImageContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E53B252497500032B88D /* ImageContent.swift */; }; + 01F2E2A0267A1ED30019B822 /* TextContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0180E951258A19250061788E /* TextContentView.swift */; }; + 01F2E2A1267A1ED30019B822 /* ImageContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0180E94F258A170B0061788E /* ImageContentView.swift */; }; + 01F2E2A3267A1ED80019B822 /* TextContentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 629A60E846B05B88D62C7880 /* TextContentCollectionViewCell.swift */; }; + 01F2E2A5267A1EEC0019B822 /* SpacerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0180E953258A1F7A0061788E /* SpacerView.swift */; }; + 01F2E2A7267A1F020019B822 /* ContentProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0186E54725249A2C0032B88D /* ContentProvider.swift */; }; + 01F2E2B0267A20650019B822 /* DeepDiff.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01F2E2AF267A20650019B822 /* DeepDiff.framework */; }; + 01F2E2B4267A20720019B822 /* CollectionViewTools.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01F2E2B3267A20720019B822 /* CollectionViewTools.framework */; }; + 01F2E2B5267A20720019B822 /* CollectionViewTools.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 01F2E2B3267A20720019B822 /* CollectionViewTools.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 01F2E2B8267A21080019B822 /* SoftCellUpdateExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2E2B7267A21080019B822 /* SoftCellUpdateExampleViewController.swift */; }; + 01F2E2BA267A257E0019B822 /* HorizontalCollectionSectionItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2E2B9267A257E0019B822 /* HorizontalCollectionSectionItemsFactory.swift */; }; + 01F2E2BC267A26A90019B822 /* Pack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2E2BB267A26A90019B822 /* Pack.swift */; }; + 01F2E2BE267A278A0019B822 /* Template.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2E2BD267A278A0019B822 /* Template.swift */; }; + 01F4E588268AC93700DC9E72 /* SimpleImageContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F4E587268AC93700DC9E72 /* SimpleImageContentView.swift */; }; + 01F4E58A268ACA4200DC9E72 /* FavoritableTextContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F4E589268ACA4200DC9E72 /* FavoritableTextContentView.swift */; }; 01FF0AE4253969C200F76477 /* SpacerCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FF0AE3253969C200F76477 /* SpacerCellItem.swift */; }; 0A3763831F62556300A80613 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3763821F62556300A80613 /* AppDelegate.swift */; }; 0A37638A1F62556300A80613 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A3763891F62556300A80613 /* Assets.xcassets */; }; @@ -79,6 +96,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + 01F2E2B6267A20720019B822 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 01F2E2B5267A20720019B822 /* CollectionViewTools.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; 0E5676E422C5DEC0008A88EA /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -94,6 +122,8 @@ /* Begin PBXFileReference section */ 01078BF625C11F5500A11E1D /* CollectionViewTools.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CollectionViewTools.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0113EA78267A159100E5A399 /* FactoriesExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FactoriesExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0113EA94267A17B200E5A399 /* FactoriesInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = FactoriesInfo.plist; sourceTree = ""; }; 0142A91D25249F3400A1CBC0 /* ContentViewSectionItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewSectionItemsFactory.swift; sourceTree = ""; }; 0147997525D4E84100287F51 /* DescriptionViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DescriptionViewState.swift; sourceTree = ""; }; 0147997625D4E84100287F51 /* ViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewState.swift; sourceTree = ""; }; @@ -111,6 +141,15 @@ 0186E54725249A2C0032B88D /* ContentProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentProvider.swift; sourceTree = ""; }; 01929DAD22F19233004D5605 /* FactoryExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FactoryExampleViewController.swift; sourceTree = ""; }; 01C2CC1522F4377C00873DC0 /* SpacerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpacerCell.swift; sourceTree = ""; }; + 01F2E281267A1AC00019B822 /* FactoriesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FactoriesViewController.swift; sourceTree = ""; }; + 01F2E2AF267A20650019B822 /* DeepDiff.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeepDiff.framework; path = Carthage/Build/iOS/DeepDiff.framework; sourceTree = ""; }; + 01F2E2B3267A20720019B822 /* CollectionViewTools.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CollectionViewTools.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 01F2E2B7267A21080019B822 /* SoftCellUpdateExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftCellUpdateExampleViewController.swift; sourceTree = ""; }; + 01F2E2B9267A257E0019B822 /* HorizontalCollectionSectionItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalCollectionSectionItemsFactory.swift; sourceTree = ""; }; + 01F2E2BB267A26A90019B822 /* Pack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pack.swift; sourceTree = ""; }; + 01F2E2BD267A278A0019B822 /* Template.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Template.swift; sourceTree = ""; }; + 01F4E587268AC93700DC9E72 /* SimpleImageContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleImageContentView.swift; sourceTree = ""; }; + 01F4E589268ACA4200DC9E72 /* FavoritableTextContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritableTextContentView.swift; sourceTree = ""; }; 01FF0AE3253969C200F76477 /* SpacerCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpacerCellItem.swift; sourceTree = ""; }; 0A37637F1F62556300A80613 /* CollectionViewToolsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CollectionViewToolsExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0A3763821F62556300A80613 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -145,6 +184,15 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 0113EA75267A159100E5A399 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 01F2E2B0267A20650019B822 /* DeepDiff.framework in Frameworks */, + 01F2E2B4267A20720019B822 /* CollectionViewTools.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 0A37637C1F62556300A80613 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -170,6 +218,7 @@ isa = PBXGroup; children = ( 0142A91D25249F3400A1CBC0 /* ContentViewSectionItemsFactory.swift */, + 01F2E2B9267A257E0019B822 /* HorizontalCollectionSectionItemsFactory.swift */, ); path = Factories; sourceTree = ""; @@ -187,6 +236,8 @@ 0180E94F258A170B0061788E /* ImageContentView.swift */, 0180E951258A19250061788E /* TextContentView.swift */, 0180E953258A1F7A0061788E /* SpacerView.swift */, + 01F4E587268AC93700DC9E72 /* SimpleImageContentView.swift */, + 01F4E589268ACA4200DC9E72 /* FavoritableTextContentView.swift */, ); path = Views; sourceTree = ""; @@ -197,6 +248,8 @@ 0186E539252496E80032B88D /* Content.swift */, 0186E53B252497500032B88D /* ImageContent.swift */, 0186E53D252497EC0032B88D /* TextContent.swift */, + 01F2E2BB267A26A90019B822 /* Pack.swift */, + 01F2E2BD267A278A0019B822 /* Template.swift */, ); path = Models; sourceTree = ""; @@ -222,6 +275,21 @@ path = Services; sourceTree = ""; }; + 01F2E280267A1AAD0019B822 /* Factories */ = { + isa = PBXGroup; + children = ( + 0186E538252496D50032B88D /* Models */, + 0186E53F2524981F0032B88D /* ContentViewState */, + 0186E546252499CF0032B88D /* Services */, + 0142A91A25249EC600A1CBC0 /* Factories */, + 01F2E281267A1AC00019B822 /* FactoriesViewController.swift */, + 01929DAD22F19233004D5605 /* FactoryExampleViewController.swift */, + 015F03FA258772A50033F11C /* LazySectionItemsExampleViewController.swift */, + 01F2E2B7267A21080019B822 /* SoftCellUpdateExampleViewController.swift */, + ); + path = Factories; + sourceTree = ""; + }; 0A3763761F62556300A80613 = { isa = PBXGroup; children = ( @@ -237,6 +305,7 @@ children = ( 0A37637F1F62556300A80613 /* CollectionViewToolsExample.app */, 0EB8E65F229BF9370000B921 /* CollectionViewToolsDiffExample.app */, + 0113EA78267A159100E5A399 /* FactoriesExample.app */, ); name = Products; sourceTree = ""; @@ -247,6 +316,7 @@ 0A3763821F62556300A80613 /* AppDelegate.swift */, 0EB8E663229BFBDB0000B921 /* Main */, 0E4CB5892296733A002A3C59 /* Diff */, + 01F2E280267A1AAD0019B822 /* Factories */, 0ACA6FC71F626AED00782C1E /* CellItems */, 0ACA6FCA1F626D1700782C1E /* Cells */, 0180E94E258A16E90061788E /* Views */, @@ -257,6 +327,7 @@ 0A37638E1F62556400A80613 /* Info.plist */, 629A6B7B0DC722197E2D2AC9 /* SectionItems */, 0EB8E661229BFA710000B921 /* DiffInfo.plist */, + 0113EA94267A17B200E5A399 /* FactoriesInfo.plist */, 0E506C05228EBA4400E16640 /* Cartfile */, 0E506C06228EBA4500E16640 /* Cartfile.resolved */, ); @@ -266,6 +337,8 @@ 0ACA6FC41F62659500782C1E /* Frameworks */ = { isa = PBXGroup; children = ( + 01F2E2B3267A20720019B822 /* CollectionViewTools.framework */, + 01F2E2AF267A20650019B822 /* DeepDiff.framework */, 01078BF625C11F5500A11E1D /* CollectionViewTools.framework */, 10A34923232B7EED0064FB8C /* DeepDiff.framework */, 1028238E22E9B0950061C54F /* IGListKit.framework */, @@ -327,14 +400,8 @@ 0EB8E663229BFBDB0000B921 /* Main */ = { isa = PBXGroup; children = ( - 0142A91A25249EC600A1CBC0 /* Factories */, - 0186E546252499CF0032B88D /* Services */, - 0186E53F2524981F0032B88D /* ContentViewState */, - 0186E538252496D50032B88D /* Models */, 10E7BC7223756EE5009095ED /* MainViewController.swift */, 10FF9F5D23040224003B7169 /* DetailViewController.swift */, - 01929DAD22F19233004D5605 /* FactoryExampleViewController.swift */, - 015F03FA258772A50033F11C /* LazySectionItemsExampleViewController.swift */, ); path = Main; sourceTree = ""; @@ -368,6 +435,25 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 0113EA77267A159100E5A399 /* FactoriesExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0113EA8C267A159200E5A399 /* Build configuration list for PBXNativeTarget "FactoriesExample" */; + buildPhases = ( + 0113EA74267A159100E5A399 /* Sources */, + 0113EA75267A159100E5A399 /* Frameworks */, + 0113EA76267A159100E5A399 /* Resources */, + F297C92578FA954187F1C925 /* Carthage */, + 01F2E2B6267A20720019B822 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = FactoriesExample; + productName = FactoriesExample; + productReference = 0113EA78267A159100E5A399 /* FactoriesExample.app */; + productType = "com.apple.product-type.application"; + }; 0A37637E1F62556300A80613 /* CollectionViewToolsExample */ = { isa = PBXNativeTarget; buildConfigurationList = 0A37639C1F62556400A80613 /* Build configuration list for PBXNativeTarget "CollectionViewToolsExample" */; @@ -413,10 +499,15 @@ 0A3763771F62556300A80613 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0830; + LastSwiftUpdateCheck = 1240; LastUpgradeCheck = 1020; ORGANIZATIONNAME = Rosberry; TargetAttributes = { + 0113EA77267A159100E5A399 = { + CreatedOnToolsVersion = 12.4; + DevelopmentTeam = GPVA8JVMU3; + ProvisioningStyle = Automatic; + }; 0A37637E1F62556300A80613 = { CreatedOnToolsVersion = 8.3.3; DevelopmentTeam = GPVA8JVMU3; @@ -444,11 +535,21 @@ targets = ( 0A37637E1F62556300A80613 /* CollectionViewToolsExample */, 0EB8E640229BF9370000B921 /* CollectionViewToolsDiffExample */, + 0113EA77267A159100E5A399 /* FactoriesExample */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 0113EA76267A159100E5A399 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0113EA90267A171200E5A399 /* Assets.xcassets in Resources */, + 0113EA92267A171600E5A399 /* LaunchScreen.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 0A37637D1F62556300A80613 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -495,81 +596,118 @@ files = ( ); inputFileListPaths = ( + "$(SRCROOT)/Carthage/xcfilelists/CollectionViewToolsDiffExample-inputPaths.xcfilelist", ); inputPaths = ( - "$(SRCROOT)/../Carthage/Build/iOS/DeepDiff.framework", - "$(SRCROOT)/Carthage/Build/iOS/IGListKit.framework", ); name = Carthage; outputFileListPaths = ( + "$(SRCROOT)/Carthage/xcfilelists/CollectionViewToolsDiffExample-outputPaths.xcfilelist", ); outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/DeepDiff.framework", - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/IGListKit.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + shellScript = "/usr/local/bin/carthage copy-frameworks"; showEnvVarsInLog = 0; }; - SU6GBKOWJH8IOEGFXJRK654W /* Carthage */ = { + F297C92578FA954187F1C925 /* Carthage */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "$(SRCROOT)/Carthage/xcfilelists/FactoriesExample-inputPaths.xcfilelist", ); inputPaths = ( - "$(SRCROOT)/../Carthage/Build/iOS/DeepDiff.framework", ); name = Carthage; outputFileListPaths = ( + "$(SRCROOT)/Carthage/xcfilelists/FactoriesExample-outputPaths.xcfilelist", ); outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/DeepDiff.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + }; + SU6GBKOWJH8IOEGFXJRK654W /* Carthage */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "$(SRCROOT)/Carthage/xcfilelists/CollectionViewToolsExample-inputPaths.xcfilelist", + ); + inputPaths = ( + ); + name = Carthage; + outputFileListPaths = ( + "$(SRCROOT)/Carthage/xcfilelists/CollectionViewToolsExample-outputPaths.xcfilelist", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 0113EA74267A159100E5A399 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 01F2E29C267A1EA60019B822 /* TextContent.swift in Sources */, + 01F2E2A3267A1ED80019B822 /* TextContentCollectionViewCell.swift in Sources */, + 01F2E2A5267A1EEC0019B822 /* SpacerView.swift in Sources */, + 01F2E2A0267A1ED30019B822 /* TextContentView.swift in Sources */, + 01F4E588268AC93700DC9E72 /* SimpleImageContentView.swift in Sources */, + 01F2E296267A1E130019B822 /* FactoryExampleViewController.swift in Sources */, + 01F4E58A268ACA4200DC9E72 /* FavoritableTextContentView.swift in Sources */, + 01F2E2BE267A278A0019B822 /* Template.swift in Sources */, + 0113EA95267A17FC00E5A399 /* AppDelegate.swift in Sources */, + 01F2E282267A1AC00019B822 /* FactoriesViewController.swift in Sources */, + 01F2E28E267A1DF50019B822 /* ImageViewState.swift in Sources */, + 01F2E290267A1DF50019B822 /* Expandable.swift in Sources */, + 01F2E291267A1DF50019B822 /* DividerViewState.swift in Sources */, + 01F2E2A7267A1F020019B822 /* ContentProvider.swift in Sources */, + 01F2E29D267A1EA60019B822 /* Content.swift in Sources */, + 01F2E292267A1DF50019B822 /* DescriptionViewState.swift in Sources */, + 01F2E2A1267A1ED30019B822 /* ImageContentView.swift in Sources */, + 01F2E299267A1E1D0019B822 /* LazySectionItemsExampleViewController.swift in Sources */, + 01F2E28D267A1DF50019B822 /* ViewState.swift in Sources */, + 01F2E2BA267A257E0019B822 /* HorizontalCollectionSectionItemsFactory.swift in Sources */, + 01F2E287267A1DCD0019B822 /* ContentViewSectionItemsFactory.swift in Sources */, + 01F2E2BC267A26A90019B822 /* Pack.swift in Sources */, + 01F2E28F267A1DF50019B822 /* TextViewState.swift in Sources */, + 01F2E2B8267A21080019B822 /* SoftCellUpdateExampleViewController.swift in Sources */, + 01F2E29E267A1EA60019B822 /* ImageContent.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 0A37637B1F62556300A80613 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0186E53E252497EC0032B88D /* TextContent.swift in Sources */, 0ACA6FC91F626AF900782C1E /* ImageCellItem.swift in Sources */, - 0147997A25D4E84100287F51 /* ViewState.swift in Sources */, 0180E954258A1F7A0061788E /* SpacerView.swift in Sources */, 0180E950258A170B0061788E /* ImageContentView.swift in Sources */, - 0147997B25D4E84100287F51 /* Expandable.swift in Sources */, 10E7BC7323756EE5009095ED /* MainViewController.swift in Sources */, 0180E952258A19250061788E /* TextContentView.swift in Sources */, 01C2CC1622F4377C00873DC0 /* SpacerCell.swift in Sources */, - 0186E5452524997D0032B88D /* TextViewState.swift in Sources */, 0ACA6FCC1F626D2E00782C1E /* ImageCollectionViewCell.swift in Sources */, 01FF0AE4253969C200F76477 /* SpacerCellItem.swift in Sources */, - 0186E537252493980032B88D /* FactoryExampleViewController.swift in Sources */, 015F03FE258775D00033F11C /* HeaderViewItem.swift in Sources */, 0A3763831F62556300A80613 /* AppDelegate.swift in Sources */, 629A6E35B86008DC359DB40B /* TextCellItem.swift in Sources */, - 0186E54825249A2C0032B88D /* ContentProvider.swift in Sources */, - 0186E53A252496E80032B88D /* Content.swift in Sources */, 0E1EDA57228934A80087253A /* ColorCellItem.swift in Sources */, 015F040125877EC00033F11C /* HeaderView.swift in Sources */, - 0142A91E25249F3400A1CBC0 /* ContentViewSectionItemsFactory.swift in Sources */, 629A6F552D5D656B36F4F52C /* TextContentCollectionViewCell.swift in Sources */, 0E1EDA59228934D50087253A /* ColorCollectionViewCell.swift in Sources */, - 0186E543252498A70032B88D /* ImageViewState.swift in Sources */, - 0147997C25D4E84100287F51 /* DividerViewState.swift in Sources */, - 015F03FB258772A50033F11C /* LazySectionItemsExampleViewController.swift in Sources */, 10FF9F5E23040224003B7169 /* DetailViewController.swift in Sources */, - 0147997925D4E84100287F51 /* DescriptionViewState.swift in Sources */, 629A63FBA018222A355686F6 /* ExampleSectionItem.swift in Sources */, - 0186E53C252497500032B88D /* ImageContent.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -611,6 +749,91 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 0113EA89267A159200E5A399 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = GPVA8JVMU3; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = CollectionViewToolsExample/FactoriesInfo.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.FactoriesExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG FACTORIES"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Debug; + }; + 0113EA8A267A159200E5A399 /* Analyze */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = GPVA8JVMU3; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = CollectionViewToolsExample/FactoriesInfo.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.FactoriesExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG FACTORIES"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Analyze; + }; + 0113EA8B267A159200E5A399 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = GPVA8JVMU3; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = CollectionViewToolsExample/FactoriesInfo.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.FactoriesExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = FACTORIES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Release; + }; 01DA34AD25D69F9100EE469C /* Analyze */ = { isa = XCBuildConfiguration; buildSettings = { @@ -678,7 +901,10 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = CollectionViewToolsExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.collectionViewToolsExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -702,7 +928,10 @@ ); INFOPLIST_FILE = CollectionViewToolsExample/DiffInfo.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); OTHER_SWIFT_FLAGS = "-DDIFF"; PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.collectionViewToolsDiffExample; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -816,7 +1045,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 10.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -829,7 +1059,10 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = CollectionViewToolsExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.collectionViewToolsExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -844,7 +1077,10 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = CollectionViewToolsExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.collectionViewToolsExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -868,7 +1104,10 @@ ); INFOPLIST_FILE = CollectionViewToolsExample/DiffInfo.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); OTHER_SWIFT_FLAGS = "-DDIFF"; PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.collectionViewToolsDiffExample; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -889,7 +1128,10 @@ GCC_PREPROCESSOR_DEFINITIONS = "DIFF=1"; INFOPLIST_FILE = CollectionViewToolsExample/DiffInfo.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); OTHER_SWIFT_FLAGS = "-DDIFF"; PRODUCT_BUNDLE_IDENTIFIER = com.rosberry.collectionViewToolsDiffExample; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -900,6 +1142,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 0113EA8C267A159200E5A399 /* Build configuration list for PBXNativeTarget "FactoriesExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0113EA89267A159200E5A399 /* Debug */, + 0113EA8A267A159200E5A399 /* Analyze */, + 0113EA8B267A159200E5A399 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 0A37637A1F62556300A80613 /* Build configuration list for PBXProject "CollectionViewToolsExample" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Example/CollectionViewToolsExample.xcodeproj/xcshareddata/xcschemes/CollectionViewToolsDiffExample.xcscheme b/Example/CollectionViewToolsExample.xcodeproj/xcshareddata/xcschemes/CollectionViewToolsDiffExample.xcscheme index 04ebbfa..4cb63c0 100644 --- a/Example/CollectionViewToolsExample.xcodeproj/xcshareddata/xcschemes/CollectionViewToolsDiffExample.xcscheme +++ b/Example/CollectionViewToolsExample.xcodeproj/xcshareddata/xcschemes/CollectionViewToolsDiffExample.xcscheme @@ -38,8 +38,6 @@ ReferencedContainer = "container:CollectionViewToolsExample.xcodeproj"> - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/CollectionViewToolsExample/AppDelegate.swift b/Example/CollectionViewToolsExample/AppDelegate.swift index b51c615..6204771 100644 --- a/Example/CollectionViewToolsExample/AppDelegate.swift +++ b/Example/CollectionViewToolsExample/AppDelegate.swift @@ -15,6 +15,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { window?.backgroundColor = .white #if DIFF window?.rootViewController = UINavigationController(rootViewController: DiffViewController()) + #elseif FACTORIES + window?.rootViewController = UINavigationController(rootViewController: FactoriesViewController()) #else window?.rootViewController = UINavigationController(rootViewController: MainViewController()) #endif diff --git a/Example/CollectionViewToolsExample/Assets.xcassets/Contents.json b/Example/CollectionViewToolsExample/Assets.xcassets/Contents.json index da4a164..73c0059 100644 --- a/Example/CollectionViewToolsExample/Assets.xcassets/Contents.json +++ b/Example/CollectionViewToolsExample/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Example/CollectionViewToolsExample/Assets.xcassets/favorite.imageset/Contents.json b/Example/CollectionViewToolsExample/Assets.xcassets/favorite.imageset/Contents.json new file mode 100644 index 0000000..e8b8680 --- /dev/null +++ b/Example/CollectionViewToolsExample/Assets.xcassets/favorite.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "lover.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/CollectionViewToolsExample/Assets.xcassets/favorite.imageset/lover.png b/Example/CollectionViewToolsExample/Assets.xcassets/favorite.imageset/lover.png new file mode 100644 index 0000000..590c565 Binary files /dev/null and b/Example/CollectionViewToolsExample/Assets.xcassets/favorite.imageset/lover.png differ diff --git a/Example/CollectionViewToolsExample/Main/ContentViewState/DescriptionViewState.swift b/Example/CollectionViewToolsExample/Factories/ContentViewState/DescriptionViewState.swift similarity index 69% rename from Example/CollectionViewToolsExample/Main/ContentViewState/DescriptionViewState.swift rename to Example/CollectionViewToolsExample/Factories/ContentViewState/DescriptionViewState.swift index 3c6639a..33919f0 100644 --- a/Example/CollectionViewToolsExample/Main/ContentViewState/DescriptionViewState.swift +++ b/Example/CollectionViewToolsExample/Factories/ContentViewState/DescriptionViewState.swift @@ -17,8 +17,12 @@ final class DescriptionViewState: ViewState { } } -extension DescriptionViewState: Equatable { - static func == (lhs: DescriptionViewState, rhs: DescriptionViewState) -> Bool { - lhs.text == rhs.text +extension DescriptionViewState: DiffCompatible { + var diffIdentifier: String { + "\(id)" + } + + func makeDiffComparator() -> Bool { + true } } diff --git a/Example/CollectionViewToolsExample/Main/ContentViewState/DividerViewState.swift b/Example/CollectionViewToolsExample/Factories/ContentViewState/DividerViewState.swift similarity index 54% rename from Example/CollectionViewToolsExample/Main/ContentViewState/DividerViewState.swift rename to Example/CollectionViewToolsExample/Factories/ContentViewState/DividerViewState.swift index 165c7a9..d267e11 100644 --- a/Example/CollectionViewToolsExample/Main/ContentViewState/DividerViewState.swift +++ b/Example/CollectionViewToolsExample/Factories/ContentViewState/DividerViewState.swift @@ -2,14 +2,21 @@ // Copyright © 2020 Rosberry. All rights reserved. // +import CollectionViewTools + final class SpacerState: ViewState { convenience init(content: Content) { self.init(id: content.id) } } -extension SpacerState: Equatable { - static func == (lhs: SpacerState, rhs: SpacerState) -> Bool { +extension SpacerState: DiffCompatible { + + var diffIdentifier: String { + "\(id)" + } + + func makeDiffComparator() -> Bool { true } } diff --git a/Example/CollectionViewToolsExample/Main/ContentViewState/Expandable.swift b/Example/CollectionViewToolsExample/Factories/ContentViewState/Expandable.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/ContentViewState/Expandable.swift rename to Example/CollectionViewToolsExample/Factories/ContentViewState/Expandable.swift diff --git a/Example/CollectionViewToolsExample/Main/ContentViewState/ImageViewState.swift b/Example/CollectionViewToolsExample/Factories/ContentViewState/ImageViewState.swift similarity index 55% rename from Example/CollectionViewToolsExample/Main/ContentViewState/ImageViewState.swift rename to Example/CollectionViewToolsExample/Factories/ContentViewState/ImageViewState.swift index 36a37e9..0293bfb 100644 --- a/Example/CollectionViewToolsExample/Main/ContentViewState/ImageViewState.swift +++ b/Example/CollectionViewToolsExample/Factories/ContentViewState/ImageViewState.swift @@ -2,7 +2,7 @@ // Copyright © 2020 Rosberry. All rights reserved. // -import UIKit +import CollectionViewTools final class ImageViewState: ViewState, Expandable { @@ -21,16 +21,12 @@ final class ImageViewState: ViewState, Expandable { } } -extension ImageViewState: Equatable { - static func == (lhs: ImageViewState, rhs: ImageViewState) -> Bool { - lhs.isExpanded == rhs.isExpanded && lhs.id == rhs.id +extension ImageViewState: DiffCompatible { + var diffIdentifier: String { + "\(id)" } -} -extension ImageViewState: NSCopying { - func copy(with zone: NSZone? = nil) -> Any { - let state = ImageViewState(id: id, image: image, description: description) - state.isExpanded = isExpanded - return state + func makeDiffComparator() -> Bool { + isExpanded } } diff --git a/Example/CollectionViewToolsExample/Main/ContentViewState/TextViewState.swift b/Example/CollectionViewToolsExample/Factories/ContentViewState/TextViewState.swift similarity index 55% rename from Example/CollectionViewToolsExample/Main/ContentViewState/TextViewState.swift rename to Example/CollectionViewToolsExample/Factories/ContentViewState/TextViewState.swift index 06ed72f..72ee77a 100644 --- a/Example/CollectionViewToolsExample/Main/ContentViewState/TextViewState.swift +++ b/Example/CollectionViewToolsExample/Factories/ContentViewState/TextViewState.swift @@ -2,7 +2,7 @@ // Copyright © 2020 Rosberry. All rights reserved. // -import Foundation +import CollectionViewTools final class TextViewState: ViewState, Expandable { let text: String @@ -20,16 +20,12 @@ final class TextViewState: ViewState, Expandable { } } -extension TextViewState: Equatable { - static func == (lhs: TextViewState, rhs: TextViewState) -> Bool { - lhs.isExpanded == rhs.isExpanded && lhs.id == rhs.id +extension TextViewState: DiffCompatible { + var diffIdentifier: String { + "\(id)" } -} -extension TextViewState: NSCopying { - func copy(with zone: NSZone? = nil) -> Any { - let state = TextViewState(id: id, text: text, description: description) - state.isExpanded = isExpanded - return state + func makeDiffComparator() -> Bool { + isExpanded } } diff --git a/Example/CollectionViewToolsExample/Main/ContentViewState/ViewState.swift b/Example/CollectionViewToolsExample/Factories/ContentViewState/ViewState.swift similarity index 60% rename from Example/CollectionViewToolsExample/Main/ContentViewState/ViewState.swift rename to Example/CollectionViewToolsExample/Factories/ContentViewState/ViewState.swift index e983b90..471b548 100644 --- a/Example/CollectionViewToolsExample/Main/ContentViewState/ViewState.swift +++ b/Example/CollectionViewToolsExample/Factories/ContentViewState/ViewState.swift @@ -11,9 +11,3 @@ class ViewState { self.id = id } } - -extension ViewState: CustomDebugStringConvertible { - var debugDescription: String { - "\(id)" - } -} diff --git a/Example/CollectionViewToolsExample/Main/Factories/ContentViewSectionItemsFactory.swift b/Example/CollectionViewToolsExample/Factories/Factories/ContentViewSectionItemsFactory.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/Factories/ContentViewSectionItemsFactory.swift rename to Example/CollectionViewToolsExample/Factories/Factories/ContentViewSectionItemsFactory.swift diff --git a/Example/CollectionViewToolsExample/Factories/Factories/HorizontalCollectionSectionItemsFactory.swift b/Example/CollectionViewToolsExample/Factories/Factories/HorizontalCollectionSectionItemsFactory.swift new file mode 100644 index 0000000..914aba2 --- /dev/null +++ b/Example/CollectionViewToolsExample/Factories/Factories/HorizontalCollectionSectionItemsFactory.swift @@ -0,0 +1,87 @@ +// +// Copyright © 2020 Rosberry. All rights reserved. +// + +import CollectionViewTools + +protocol HorizontalCollectionSectionItemsFactoryOutput: class { + func toggle(pack: Pack) + func toggleFavorite(template: Template) +} + +final class HorizontalCollectionSectionItemsFactory { + + weak var output: HorizontalCollectionSectionItemsFactoryOutput? + + private lazy var packCellItemFactory: ViewCellItemsFactory = { + let factory = ViewCellItemsFactory() + + factory.cellItemConfigurationHandler = { cellItem in + cellItem.itemDidSelectHandler = { [weak self] indexPath in + self?.output?.toggle(pack: cellItem.object) + } + } + + factory.viewConfigurationHandler = { view, cellItem in + view.imageView.image = cellItem.object.thumbnail + view.imageView.contentMode = .scaleAspectFill + view.layer.borderColor = UIColor.green.cgColor + view.layer.borderWidth = cellItem.object.isExpanded ? 1 : 0 + view.layer.cornerRadius = 8 + view.clipsToBounds = true + } + + factory.sizeTypesConfigurationHandler = { cellItem in + .init(width: .fixed(140), height: .fixed(140)) + } + + return factory + }() + + private lazy var templatesCellItemFactory: ViewCellItemsFactory = { + let factory = ViewCellItemsFactory() + + factory.cellItemConfigurationHandler = { cellItem in + cellItem.itemDidSelectHandler = { [weak self] indexPath in + self?.output?.toggleFavorite(template: cellItem.object) + } + } + + factory.viewConfigurationHandler = { view, cellItem in + view.titleLabel.text = cellItem.object.text + view.titleLabel.textColor = .black + if cellItem.object.isFavorite { + view.layer.borderColor = UIColor.red.cgColor + view.favoriteImageView.image = #imageLiteral(resourceName: "favorite") + } + else { + view.layer.borderColor = UIColor.lightGray.cgColor + view.favoriteImageView.image = nil + } + view.layer.borderWidth = 1 + view.layer.cornerRadius = 8 + view.clipsToBounds = true + } + + factory.sizeTypesConfigurationHandler = { cellItem in + .init(width: .fixed(130), height: .fixed(130)) + } + + return factory + }() + + func makeSectionItems(packs: [Pack]) -> [CollectionViewDiffSectionItem] { + packs.map { pack in + let packCellItem = packCellItemFactory.makeCellItem(object: pack) + var cellItems: [CollectionViewDiffCellItem] = [packCellItem] + if pack.isExpanded { + cellItems.append(contentsOf: templatesCellItemFactory.makeCellItems(objects: pack.templates)) + } + let sectionItem = GeneralCollectionViewDiffSectionItem(cellItems: cellItems) + sectionItem.diffIdentifier = pack.id + sectionItem.insets = .init(top: 2, left: 2, bottom: 2, right: 2) + sectionItem.minimumInteritemSpacing = 2 + return sectionItem + } + } +} diff --git a/Example/CollectionViewToolsExample/Factories/FactoriesViewController.swift b/Example/CollectionViewToolsExample/Factories/FactoriesViewController.swift new file mode 100644 index 0000000..88e88dc --- /dev/null +++ b/Example/CollectionViewToolsExample/Factories/FactoriesViewController.swift @@ -0,0 +1,77 @@ +// +// Copyright © 2019 Rosberry. All rights reserved. +// + +import UIKit + +final class FactoriesViewController: UIViewController { + + // MARK: - Subviews + + private lazy var factoryExampleButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("Factory Example", for: .normal) + button.addTarget(self, action: #selector(factoryExampleButtonPressed), for: .touchUpInside) + return button + }() + + private lazy var lazyFactoryExampleButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("Lazy Factory Example", for: .normal) + button.addTarget(self, action: #selector(lazyFactoryExampleButtonPressed), for: .touchUpInside) + return button + }() + + private lazy var softUpdateExampleButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("Soft Cell Update Example", for: .normal) + button.addTarget(self, action: #selector(softCellUpdateExampleButtonPressed), for: .touchUpInside) + return button + }() + + private lazy var buttons: [UIButton] = [ + factoryExampleButton, + lazyFactoryExampleButton, + softUpdateExampleButton + ] + + // MARK: - Lifecycle + + override func viewDidLoad() { + super.viewDidLoad() + buttons.forEach { button in + view.addSubview(button) + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + let inset: CGFloat = 16 + let width = view.bounds.width - 2 * inset + let height: CGFloat = 48 + let topToSafeArea: CGFloat = 48 + view.safeAreaInsets.top + + buttons.enumerated().forEach { index, button in + button.frame = .init(x: inset, y: topToSafeArea + CGFloat(index) * (height + inset), + width: width, height: height) + } + } + + // MARK: - Actions + + @objc private func factoryExampleButtonPressed() { + let viewController = FactoryExampleViewController() + navigationController?.pushViewController(viewController, animated: true) + } + + @objc private func lazyFactoryExampleButtonPressed() { + let viewController = LazySectionItemsExampleViewController() + navigationController?.pushViewController(viewController, animated: true) + } + + @objc private func softCellUpdateExampleButtonPressed() { + let viewController = SoftCellUpdateExampleViewController() + navigationController?.pushViewController(viewController, animated: true) + } +} diff --git a/Example/CollectionViewToolsExample/Main/FactoryExampleViewController.swift b/Example/CollectionViewToolsExample/Factories/FactoryExampleViewController.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/FactoryExampleViewController.swift rename to Example/CollectionViewToolsExample/Factories/FactoryExampleViewController.swift diff --git a/Example/CollectionViewToolsExample/Main/LazySectionItemsExampleViewController.swift b/Example/CollectionViewToolsExample/Factories/LazySectionItemsExampleViewController.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/LazySectionItemsExampleViewController.swift rename to Example/CollectionViewToolsExample/Factories/LazySectionItemsExampleViewController.swift diff --git a/Example/CollectionViewToolsExample/Main/Models/Content.swift b/Example/CollectionViewToolsExample/Factories/Models/Content.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/Models/Content.swift rename to Example/CollectionViewToolsExample/Factories/Models/Content.swift diff --git a/Example/CollectionViewToolsExample/Main/Models/ImageContent.swift b/Example/CollectionViewToolsExample/Factories/Models/ImageContent.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/Models/ImageContent.swift rename to Example/CollectionViewToolsExample/Factories/Models/ImageContent.swift diff --git a/Example/CollectionViewToolsExample/Factories/Models/Pack.swift b/Example/CollectionViewToolsExample/Factories/Models/Pack.swift new file mode 100644 index 0000000..923ebb8 --- /dev/null +++ b/Example/CollectionViewToolsExample/Factories/Models/Pack.swift @@ -0,0 +1,28 @@ +// +// Copyright © 2020 Rosberry. All rights reserved. +// + +import CollectionViewTools + +final class Pack { + let id: String + let thumbnail: UIImage + let templates: [Template] + var isExpanded: Bool = false + + init(id: String, thumbnail: UIImage, templates: [Template]) { + self.id = id + self.thumbnail = thumbnail + self.templates = templates + } +} + +extension Pack: DiffCompatible { + var diffIdentifier: String { + id + } + + func makeDiffComparator() -> Bool { + isExpanded + } +} diff --git a/Example/CollectionViewToolsExample/Factories/Models/Template.swift b/Example/CollectionViewToolsExample/Factories/Models/Template.swift new file mode 100644 index 0000000..713d0a3 --- /dev/null +++ b/Example/CollectionViewToolsExample/Factories/Models/Template.swift @@ -0,0 +1,28 @@ +// +// Copyright © 2020 Rosberry. All rights reserved. +// + +import CollectionViewTools + +final class Template { + + let id: String + let text: String + var isFavorite: Bool = false + + init(id: String, text: String) { + self.id = id + self.text = text + } +} + +extension Template: DiffCompatible { + + var diffIdentifier: String { + id + } + + func makeDiffComparator() -> Bool { + isFavorite + } +} diff --git a/Example/CollectionViewToolsExample/Main/Models/TextContent.swift b/Example/CollectionViewToolsExample/Factories/Models/TextContent.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/Models/TextContent.swift rename to Example/CollectionViewToolsExample/Factories/Models/TextContent.swift diff --git a/Example/CollectionViewToolsExample/Main/Services/ContentProvider.swift b/Example/CollectionViewToolsExample/Factories/Services/ContentProvider.swift similarity index 100% rename from Example/CollectionViewToolsExample/Main/Services/ContentProvider.swift rename to Example/CollectionViewToolsExample/Factories/Services/ContentProvider.swift diff --git a/Example/CollectionViewToolsExample/Factories/SoftCellUpdateExampleViewController.swift b/Example/CollectionViewToolsExample/Factories/SoftCellUpdateExampleViewController.swift new file mode 100644 index 0000000..eb29375 --- /dev/null +++ b/Example/CollectionViewToolsExample/Factories/SoftCellUpdateExampleViewController.swift @@ -0,0 +1,227 @@ +// +// Copyright © 2021 Rosberry. All rights reserved. +// + +import UIKit +import CollectionViewTools + +final class SoftCellUpdateExampleViewController: UIViewController { + + private lazy var manager: CollectionViewManager = .init(collectionView: collectionView) + private lazy var factory: HorizontalCollectionSectionItemsFactory = { + let factory = HorizontalCollectionSectionItemsFactory() + factory.output = self + return factory + }() + + private let packs: [Pack] = [ + .init(id: "1", thumbnail: #imageLiteral(resourceName: "nightlife-1"), templates: [ + .init(id: "1.1", text: "A"), + .init(id: "1.2", text: "B"), + .init(id: "1.3", text: "C"), + .init(id: "1.4", text: "D"), + .init(id: "1.5", text: "E") + ]), + .init(id: "2", thumbnail: #imageLiteral(resourceName: "nightlife-2"), templates: [ + .init(id: "2.1", text: "F"), + .init(id: "2.2", text: "G"), + .init(id: "2.3", text: "H") + ]), + .init(id: "3", thumbnail: #imageLiteral(resourceName: "nightlife-3"), templates: [ + .init(id: "3.1", text: "I"), + .init(id: "3.2", text: "J"), + .init(id: "3.3", text: "K"), + .init(id: "3.4", text: "L") + ]), + .init(id: "4", thumbnail: #imageLiteral(resourceName: "nightlife-3"), templates: [ + .init(id: "4.1", text: "M"), + .init(id: "4.2", text: "N"), + .init(id: "4.3", text: "O"), + .init(id: "4.4", text: "P"), + .init(id: "4.5", text: "Q"), + .init(id: "4.6", text: "R"), + .init(id: "4.7", text: "S"), + .init(id: "4.8", text: "T"), + .init(id: "4.9", text: "U") + ]) + ] + + private var displayedPacks: [Pack] = [] + + // MARK: - Subviews + + private lazy var collectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.minimumInteritemSpacing = 10 + layout.scrollDirection = .horizontal + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.backgroundColor = .white + return collectionView + }() + + private lazy var imageView: UIImageView = { + let imageView = UIImageView() + imageView.layer.borderWidth = 1 + imageView.layer.borderColor = UIColor.green.cgColor + imageView.backgroundColor = .lightGray + imageView.contentMode = .scaleAspectFit + return imageView + }() + + private lazy var switchControl: UISwitch = { + let switchControl = UISwitch() + switchControl.isOn = true + switchControl.backgroundColor = UIColor.red + switchControl.layer.cornerRadius = 15 + switchControl.clipsToBounds = true + switchControl.addTarget(self, action: #selector(switchValueChanged), for: .valueChanged) + return switchControl + }() + + lazy var placeholderLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.textColor = .gray + label.text = "Unfold any pack from bottom placed picker and tap some nested item.\nUse switch at top right corner to change cell update mode" + return label + }() + + // MARK: - Lifecycle + + override func viewDidLoad() { + super.viewDidLoad() + view.addSubview(collectionView) + view.addSubview(imageView) + view.addSubview(switchControl) + view.addSubview(placeholderLabel) + updateCollection() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + let collectionHeight: CGFloat = 150 + let bottom: CGFloat = view.bounds.height - view.safeAreaInsets.bottom + collectionView.frame = .init(x: 0, y: bottom - collectionHeight, + width: view.bounds.width, height: collectionHeight) + + let imageInset: CGFloat = 16 + let top = view.safeAreaInsets.top + let imageWidth = view.bounds.width - 2 * imageInset + let imageHeight = collectionView.frame.minY - view.safeAreaInsets.top - 2 * imageInset + imageView.frame = .init(x: imageInset, y: top + imageInset, width: imageWidth, height: imageHeight) + placeholderLabel.frame = imageView.frame + + switchControl.frame = .init(x: imageWidth - 50, y: top + 40, width: 51, height: 31) + } + + // MARK: - Actions + + @objc private func switchValueChanged() { + switch switchControl.isOn { + case true: + manager.cellUpdateMode = .soft + case false: + manager.cellUpdateMode = .hard + } + } + + // MARK: - Private + + private func updateCollection() { + if let favoritePack = makeFavoritePack() { + displayedPacks = [favoritePack] + self.packs + } + else { + displayedPacks = self.packs + } + let sectionItems = factory.makeSectionItems(packs: displayedPacks) + if manager.sectionItems.isEmpty { + manager.sectionItems = sectionItems + } + else { + manager.update(with: sectionItems, animated: true) + } + } + + private func makeFavoritePack() -> Pack? { + let templates: [Template] = packs.flatMap { pack in + pack.templates.compactMap { template in + guard template.isFavorite else { + return nil + } + let template = Template(id: "f:" + template.id, text: template.text) + template.isFavorite = true + return template + } + } + guard templates.isEmpty == false else { + return nil + } + let pack = Pack(id: "0", thumbnail: #imageLiteral(resourceName: "favorite"), templates: templates) + if let first = displayedPacks.first, + first.id == "0" { + pack.isExpanded = first.isExpanded + } + return pack + } +} + +extension SoftCellUpdateExampleViewController: HorizontalCollectionSectionItemsFactoryOutput { + + func toggle(pack: Pack) { + if pack.isExpanded { + pack.isExpanded.toggle() + placeholderLabel.isHidden = false + } + else { + placeholderLabel.isHidden = true + displayedPacks.forEach { storedPack in + storedPack.isExpanded = pack.id == storedPack.id + } + } + imageView.image = pack.isExpanded ? pack.thumbnail : nil + updateCollection() + for sectionItem in manager.sectionItems { + guard let sectionItem = sectionItem as? CollectionViewDiffSectionItem, + sectionItem.diffIdentifier == pack.id, + let cellItem = sectionItem.cellItems.first else { + continue + } + manager.scroll(to: cellItem, at: .left, animated: true) + return + } + } + + func toggleFavorite(template: Template) { + if template.id.starts(with: "f:") { + togleFavoriteInFavoritesPack(template: template) + } + else { + template.isFavorite.toggle() + updateCollection() + } + } + + func togleFavoriteInFavoritesPack(template: Template) { + let id = template.id.dropFirst(2) + let components = id.split(separator: ".") + guard var packNumber = Int(components[0]), + var templateNumber = Int(components[1]) else { + return + } + packNumber -= 1 + templateNumber -= 1 + guard packs.count > packNumber, + packs[packNumber].templates.count > templateNumber else { + return + } + let template = packs[packNumber].templates[templateNumber] + guard template.id == String(id) else { + return + } + template.isFavorite = false + updateCollection() + } +} diff --git a/Example/CollectionViewToolsExample/FactoriesInfo.plist b/Example/CollectionViewToolsExample/FactoriesInfo.plist new file mode 100644 index 0000000..f26b1bb --- /dev/null +++ b/Example/CollectionViewToolsExample/FactoriesInfo.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + FactoriesExample + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Example/CollectionViewToolsExample/Main/MainViewController.swift b/Example/CollectionViewToolsExample/Main/MainViewController.swift index 8f8d9a2..54d0d18 100644 --- a/Example/CollectionViewToolsExample/Main/MainViewController.swift +++ b/Example/CollectionViewToolsExample/Main/MainViewController.swift @@ -125,10 +125,6 @@ class MainViewController: UIViewController { func makeActionsSectionItem() -> CollectionViewSectionItem { let sectionItem = makeActionsSectionItem(cellItems: [ makeResetActionCellItem(), - // Factory example - makeFactoryExampleActionCellItem(), - // Lazy items example - makeLazySectionItemsExampleActionCellItem(), // Insert cells makePrependCellItemsActionCellItem(), makeAppendCellItemsActionCellItem(), @@ -416,30 +412,6 @@ class MainViewController: UIViewController { } } - // MARK: - Factory example - - func makeFactoryExampleActionCellItem() -> CollectionViewCellItem { - return makeActionCellItem(title: "Factory example") { [weak self] in - guard let `self` = self else { - return - } - let viewController = FactoryExampleViewController() - self.navigationController?.pushViewController(viewController, animated: true) - } - } - - // MARK: - Lazy section items axample - - func makeLazySectionItemsExampleActionCellItem() -> CollectionViewCellItem { - return makeActionCellItem(title: "Lazy items example") { [weak self] in - guard let `self` = self else { - return - } - let viewController = LazySectionItemsExampleViewController() - self.navigationController?.pushViewController(viewController, animated: true) - } - } - // MARK: - Common func makeActionCellItem(title: String, action: @escaping (() -> Void)) -> CollectionViewCellItem { diff --git a/Example/CollectionViewToolsExample/Views/FavoritableTextContentView.swift b/Example/CollectionViewToolsExample/Views/FavoritableTextContentView.swift new file mode 100644 index 0000000..46aaf80 --- /dev/null +++ b/Example/CollectionViewToolsExample/Views/FavoritableTextContentView.swift @@ -0,0 +1,58 @@ +// +// Copyright © 2020 Rosberry. All rights reserved. +// + +import UIKit + +final class FavoritableTextContentView: UIView { + + var isHighlighted: Bool = false { + didSet { + alpha = isHighlighted ? 0.7 : 1.0 + } + } + + lazy var titleLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + return label + }() + + + let favoriteImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + return imageView + }() + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + override func layoutSubviews() { + super.layoutSubviews() + titleLabel.frame = bounds + let side = bounds.width / 3 + favoriteImageView.frame = .init(x: bounds.width - side - 2, y: 2, width: side, height: side) + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + return titleLabel.sizeThatFits(.init(width: size.width, + height: .greatestFiniteMagnitude)) + } + + // MARK: - Private + + private func setup() { + addSubview(titleLabel) + addSubview(favoriteImageView) + backgroundColor = .white + } +} diff --git a/Example/CollectionViewToolsExample/Views/SimpleImageContentView.swift b/Example/CollectionViewToolsExample/Views/SimpleImageContentView.swift new file mode 100644 index 0000000..8fe14b6 --- /dev/null +++ b/Example/CollectionViewToolsExample/Views/SimpleImageContentView.swift @@ -0,0 +1,52 @@ +// +// Copyright © 2020 Rosberry. All rights reserved. +// + +import UIKit + +final class SimpleImageContentView: UIView { + var removeActionHandler: (() -> Void)? + + let imageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + return imageView + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + override func layoutSubviews() { + super.layoutSubviews() + + imageView.frame = bounds + } + + @objc private func removeButtonPressed() { + removeActionHandler?() + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + guard let image = imageView.image else { + return .zero + } + let aspect = image.size.height / image.size.width + let width = size.width + let height = width * aspect + return .init(width: width, height: height) + } + + // MARK: - Private + + private func setup() { + addSubview(imageView) + backgroundColor = .white + } +} diff --git a/Sources/CellUpdateMode.swift b/Sources/CellUpdateMode.swift new file mode 100644 index 0000000..b2ec742 --- /dev/null +++ b/Sources/CellUpdateMode.swift @@ -0,0 +1,8 @@ +// +// Copyright © 2021 Rosberry. All rights reserved. +// + +public enum CellUpdateMode { + case hard + case soft +} diff --git a/Sources/CollectionViewManager.swift b/Sources/CollectionViewManager.swift index b88b2f0..d6e056d 100644 --- a/Sources/CollectionViewManager.swift +++ b/Sources/CollectionViewManager.swift @@ -60,8 +60,13 @@ open class CollectionViewManager: NSObject { } } + /// Previosly `CollectionViewManager` completely replaced cells when only content is updated + /// Mode `soft` allows to configure cells with updates without replacing (default value) + /// Mode `hard` allows to restore previos behavior + public var cellUpdateMode: CellUpdateMode = .soft + /// Provider of `CollectionViewSectionItem` objects, which respond for configuration of specified section in collection view. - /// Setting this property leads collection view to reload data. If you don't need this behaviour use update methods instead. + /// Setting this property leads collection view to reload data. If you don't need this behavior use update methods instead. public var sectionItems: [SectionItem] { get { return sectionItemsProvider.sectionItems @@ -445,65 +450,38 @@ open class CollectionViewManager: NSObject { performUpdates: Bool = true, configureAnimated: Bool = false, completion: Completion? = nil) { - guard indexes.count > 0 else { - return - } - - guard let section = sectionItem.index else { - printContextWarning("It is impossible to replace cell items in sectionItem \(sectionItem)" + - "because there is no index in it") - return - } - - func replace(in collectionView: UICollectionView?) { - for index in 0..) { - sectionItem.cellItems.remove(at: index) - removeIndexPaths.append(.init(row: index, section: section)) - } - - let insertIndexPaths: [IndexPath] = Array(firstIndex.. 0 else { + return + } + + guard let section = sectionItem.index else { + printContextWarning("It is impossible to replace cell items in sectionItem \(sectionItem)" + + "because there is no index in it") + return + } + + func iterateCellItems(in collectionView: UICollectionView?, fallbackHandler: (IndexPath, UICollectionViewCell?, CellItem) -> Void) { + for (cellItem, index) in zip(cellItems, indexes) where index < sectionItem.cellItems.count { + sectionItem.cellItems[index] = cellItem + let indexPath = IndexPath(row: index, section: section) + cellItem.indexPath = indexPath + let optionalCell = collectionView?.cellForItem(at: indexPath) + if !cellItem.isReplacementAnimationEnabled, + let cell = optionalCell { + cellItem.context.shouldConfigureAnimated = true + cellItem.configure(cell) + cellItem.context.shouldConfigureAnimated = false + } + else { + fallbackHandler(indexPath, optionalCell, cellItem) + } + } + } + + func replace(in collectionView: UICollectionView?) { + for index in 0..) { + sectionItem.cellItems.remove(at: index) + removeIndexPaths.append(.init(row: index, section: section)) + } + + let insertIndexPaths: [IndexPath] = Array(firstIndex.. DiffComparator +} /// Your cell items and reusable view items must conform `DiffItem` protocol to work with diffing. /// diffIdentifier: Each item must be uniquely(!!!) identified by `diffIdentifier`. Otherwise diff algorithm can work incorrectly. diff --git a/Sources/Helpers/Factories/ViewCellItemsFactory.swift b/Sources/Helpers/Factories/ViewCellItemsFactory.swift index 0673e8f..708aa8d 100644 --- a/Sources/Helpers/Factories/ViewCellItemsFactory.swift +++ b/Sources/Helpers/Factories/ViewCellItemsFactory.swift @@ -93,6 +93,16 @@ open class ViewCellItemsFactory { factory.makeCellItem(object: object) } + /// Returns an instances of `UniversalCollectionViewCellItem` and associates provided handlers with them + /// + /// - Parameters: + /// - objects: an array of object to create a cell item for it + public func makeCellItems(objects: [Object]) -> [CellItem] { + objects.map { object in + makeCellItem(object: object) + } + } + /// Joins different cell item factories /// /// - Parameters: diff --git a/Sources/Items/UniversalCollectionViewCellItem.swift b/Sources/Items/UniversalCollectionViewCellItem.swift index 61359d9..011bc68 100644 --- a/Sources/Items/UniversalCollectionViewCellItem.swift +++ b/Sources/Items/UniversalCollectionViewCellItem.swift @@ -9,7 +9,7 @@ public class UniversalCollectionViewCellItem else { return false } - return object == cellItem.object && - object == originalObject && - cellItem.object == originalObject + let objectDescriptor = object.makeDiffComparator() + let cellItemObjectDescriptor = cellItem.object.makeDiffComparator() + return comparator == cellItem.comparator && + comparator == objectDescriptor && + objectDescriptor == cellItemObjectDescriptor } }