From ef76b64335328e61e4d97d245b65eceded2e106c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tibor=20B=C3=B6decs?= Date: Mon, 11 Feb 2019 14:17:48 +0100 Subject: [PATCH] initial release --- CollectionView.podspec | 20 + CollectionView.xcodeproj/project.pbxproj | 371 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 24136 bytes .../xcschemes/xcschememanagement.plist | 14 + LICENSE | 13 + README.md | 30 ++ Sources/CollectionViewCell+Reuse.swift | 70 ++++ Sources/CollectionViewCell.swift | 46 +++ Sources/CollectionViewController.swift | 90 +++++ Sources/CollectionViewSection.swift | 36 ++ Sources/CollectionViewSource.swift | 248 ++++++++++++ Sources/CollectionViewViewModel.swift | 72 ++++ Sources/Grid.swift | 88 +++++ iOS/CollectionView.h | 17 + iOS/Info.plist | 22 ++ 17 files changed, 1152 insertions(+) create mode 100644 CollectionView.podspec create mode 100644 CollectionView.xcodeproj/project.pbxproj create mode 100644 CollectionView.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 CollectionView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 CollectionView.xcodeproj/project.xcworkspace/xcuserdata/tib.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 CollectionView.xcodeproj/xcuserdata/tib.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 LICENSE create mode 100755 README.md create mode 100755 Sources/CollectionViewCell+Reuse.swift create mode 100755 Sources/CollectionViewCell.swift create mode 100755 Sources/CollectionViewController.swift create mode 100755 Sources/CollectionViewSection.swift create mode 100755 Sources/CollectionViewSource.swift create mode 100755 Sources/CollectionViewViewModel.swift create mode 100755 Sources/Grid.swift create mode 100644 iOS/CollectionView.h create mode 100644 iOS/Info.plist diff --git a/CollectionView.podspec b/CollectionView.podspec new file mode 100644 index 0000000..0306c45 --- /dev/null +++ b/CollectionView.podspec @@ -0,0 +1,20 @@ +Pod::Spec.new do |s| + s.name = 'CollectionView' + s.version = '1.0.0' + s.summary = 'CollectionViews with ease.' + s.description = <<-DESC + A view model framework around collection views. + DESC + + s.homepage = 'https://theswiftdev.com/' + s.license = { :type => 'WTFPL', :file => 'LICENSE' } + s.author = { 'Tibor Bödecs' => 'mail.tib@gmail.com' } + s.source = { :git => 'https://github.com/CoreKit/CollectionView.git', :tag => s.version.to_s } + s.social_media_url = 'https://twitter.com/tiborbodecs' + + s.ios.deployment_target = '11.0' + + s.swift_version = '4.2' + s.source_files = 'Sources/**/*' + s.frameworks = 'UIKit' +end \ No newline at end of file diff --git a/CollectionView.xcodeproj/project.pbxproj b/CollectionView.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9839a46 --- /dev/null +++ b/CollectionView.xcodeproj/project.pbxproj @@ -0,0 +1,371 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 162ED40D2211ACA000D44AEB /* CollectionViewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162ED4032211ACA000D44AEB /* CollectionViewViewModel.swift */; }; + 162ED40E2211ACA000D44AEB /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162ED4042211ACA000D44AEB /* CollectionViewCell.swift */; }; + 162ED40F2211ACA000D44AEB /* CollectionViewSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162ED4052211ACA000D44AEB /* CollectionViewSection.swift */; }; + 162ED4102211ACA000D44AEB /* CollectionViewCell+Reuse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162ED4062211ACA000D44AEB /* CollectionViewCell+Reuse.swift */; }; + 162ED4112211ACA000D44AEB /* Grid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162ED4072211ACA000D44AEB /* Grid.swift */; }; + 162ED4122211ACA000D44AEB /* CollectionViewSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162ED4082211ACA000D44AEB /* CollectionViewSource.swift */; }; + 162ED4132211ACA000D44AEB /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162ED4092211ACA000D44AEB /* CollectionViewController.swift */; }; + 162ED4142211ACA000D44AEB /* CollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 162ED40B2211ACA000D44AEB /* CollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 162ED4032211ACA000D44AEB /* CollectionViewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewViewModel.swift; sourceTree = ""; }; + 162ED4042211ACA000D44AEB /* CollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCell.swift; sourceTree = ""; }; + 162ED4052211ACA000D44AEB /* CollectionViewSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewSection.swift; sourceTree = ""; }; + 162ED4062211ACA000D44AEB /* CollectionViewCell+Reuse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CollectionViewCell+Reuse.swift"; sourceTree = ""; }; + 162ED4072211ACA000D44AEB /* Grid.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Grid.swift; sourceTree = ""; }; + 162ED4082211ACA000D44AEB /* CollectionViewSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewSource.swift; sourceTree = ""; }; + 162ED4092211ACA000D44AEB /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; }; + 162ED40B2211ACA000D44AEB /* CollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionView.h; sourceTree = ""; }; + 162ED40C2211ACA000D44AEB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 16B94D542211AC7400247232 /* CollectionView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CollectionView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 16B94D512211AC7400247232 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 162ED4022211ACA000D44AEB /* Sources */ = { + isa = PBXGroup; + children = ( + 162ED4072211ACA000D44AEB /* Grid.swift */, + 162ED4042211ACA000D44AEB /* CollectionViewCell.swift */, + 162ED4062211ACA000D44AEB /* CollectionViewCell+Reuse.swift */, + 162ED4032211ACA000D44AEB /* CollectionViewViewModel.swift */, + 162ED4052211ACA000D44AEB /* CollectionViewSection.swift */, + 162ED4082211ACA000D44AEB /* CollectionViewSource.swift */, + 162ED4092211ACA000D44AEB /* CollectionViewController.swift */, + ); + path = Sources; + sourceTree = ""; + }; + 162ED40A2211ACA000D44AEB /* iOS */ = { + isa = PBXGroup; + children = ( + 162ED40B2211ACA000D44AEB /* CollectionView.h */, + 162ED40C2211ACA000D44AEB /* Info.plist */, + ); + path = iOS; + sourceTree = ""; + }; + 16B94D4A2211AC7400247232 = { + isa = PBXGroup; + children = ( + 162ED40A2211ACA000D44AEB /* iOS */, + 162ED4022211ACA000D44AEB /* Sources */, + 16B94D552211AC7400247232 /* Products */, + ); + sourceTree = ""; + }; + 16B94D552211AC7400247232 /* Products */ = { + isa = PBXGroup; + children = ( + 16B94D542211AC7400247232 /* CollectionView.framework */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 16B94D4F2211AC7400247232 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 162ED4142211ACA000D44AEB /* CollectionView.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 16B94D532211AC7400247232 /* CollectionView */ = { + isa = PBXNativeTarget; + buildConfigurationList = 16B94D5C2211AC7400247232 /* Build configuration list for PBXNativeTarget "CollectionView" */; + buildPhases = ( + 16B94D4F2211AC7400247232 /* Headers */, + 16B94D502211AC7400247232 /* Sources */, + 16B94D512211AC7400247232 /* Frameworks */, + 16B94D522211AC7400247232 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CollectionView; + productName = CollectionView; + productReference = 16B94D542211AC7400247232 /* CollectionView.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 16B94D4B2211AC7400247232 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1010; + ORGANIZATIONNAME = "Tibor Bödecs"; + TargetAttributes = { + 16B94D532211AC7400247232 = { + CreatedOnToolsVersion = 10.1; + }; + }; + }; + buildConfigurationList = 16B94D4E2211AC7400247232 /* Build configuration list for PBXProject "CollectionView" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 16B94D4A2211AC7400247232; + productRefGroup = 16B94D552211AC7400247232 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 16B94D532211AC7400247232 /* CollectionView */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 16B94D522211AC7400247232 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 16B94D502211AC7400247232 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 162ED40F2211ACA000D44AEB /* CollectionViewSection.swift in Sources */, + 162ED40E2211ACA000D44AEB /* CollectionViewCell.swift in Sources */, + 162ED40D2211ACA000D44AEB /* CollectionViewViewModel.swift in Sources */, + 162ED4122211ACA000D44AEB /* CollectionViewSource.swift in Sources */, + 162ED4132211ACA000D44AEB /* CollectionViewController.swift in Sources */, + 162ED4112211ACA000D44AEB /* Grid.swift in Sources */, + 162ED4102211ACA000D44AEB /* CollectionViewCell+Reuse.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 16B94D5A2211AC7400247232 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 16B94D5B2211AC7400247232 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 16B94D5D2211AC7400247232 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = XL2GSHMUDQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.tiborbodecs.CollectionView; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 16B94D5E2211AC7400247232 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = XL2GSHMUDQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.tiborbodecs.CollectionView; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 16B94D4E2211AC7400247232 /* Build configuration list for PBXProject "CollectionView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 16B94D5A2211AC7400247232 /* Debug */, + 16B94D5B2211AC7400247232 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 16B94D5C2211AC7400247232 /* Build configuration list for PBXNativeTarget "CollectionView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 16B94D5D2211AC7400247232 /* Debug */, + 16B94D5E2211AC7400247232 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 16B94D4B2211AC7400247232 /* Project object */; +} diff --git a/CollectionView.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/CollectionView.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..97156ca --- /dev/null +++ b/CollectionView.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/CollectionView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/CollectionView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/CollectionView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/CollectionView.xcodeproj/project.xcworkspace/xcuserdata/tib.xcuserdatad/UserInterfaceState.xcuserstate b/CollectionView.xcodeproj/project.xcworkspace/xcuserdata/tib.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..3117d3cbd590b8cf5103cf3d7f22aebc387f8a69 GIT binary patch literal 24136 zcmd6P33yXQ*YM0;(!EW(ByAI*d($OplBP>oyO%=gmKMrdLL1sZH>ABEgb{&AL?If9=s)SdO2fvRtu{+tZE0BDs4?bpyKQio$y#1zf!D=h_PTm+ zglDbYF2P5U6LLmA$QSvcNTftjC>q6}SfoN~6o*n#8cIhQC=+F&Y}6NxKxJqoGNDnZ z991AQ8jUJZ9h!n>qFHDzT7)K}=h2I36qVLf?^aJ`4{em*A!N1-uL| z$1md5cr9L!H{fmfHM|q=!n^T4{1)DikKp6@1b!c%$DiWQ@CE!izK(C;oA?&~7T?Bq z@qPR={+*x*nh+6ULV_j|-h@99Ky)EO2_>N;;t4&`o9IKN5dDb$L@qIas3fWg3o(Wm zOH>mzL@iNA)DzuUD_>=gHctnz<6WN9AN_HcI$Y3&r z3?;+Ja593_kXlkl#*+rJ7ulQaOXiUM$o^zLSwtGip=233lB_0c$Xc?FtS85lQ^=X* zEOIvaEIEgqOD-i}AeWKL$yMZ9avj-7ZXvgl+sIeQSIHgZLGlRsF8LmLhCEB2BR?ZA zl3$WPkUx_T$lu9_L~Rtb&5JqeM)^seM4QNu2VOto75fZC+Z>f2lXfILc7v# zv^(uVOK5*OfDWYPw1N(!!|4cGN5|88I)P54yVI$34&9ILPZ!cfw2`i)t7r>7h8{~- z(=~K0T}Ri`<7g{wqwVxl^wTs$v-BK#3B8nlfnG*0r(dL3&`oqRy`J7czec}K@1WnH z56}ncL-Y~)41Jb9M}I<}r$48^q`#ss(O2nP^mp{VlCau_>guz|1-T+O6szBw70gX*kfZS|&db4FcxLyfuC?r2zwx}u1UNQV4T z018BMq(EI5nh`Nhj5FiHxH4`VQ8yHXf>8(*2}8k*JLADDX1<0Zh45QCf`e|Ut*D!j zWi{29%f!9gH&<*Lm0nkCx7Jlxo2_MOS&12m`m8jSL8DCoeA7}@sYz*BDy=3>8?P~> zXQXN~%fu0_5TSOO$vVhn8)&gvMpc^!S?pCtOKoMf8FI?R%JwY@IF#iXi_A8Aoz(=z zjdqjWoMEz?%EaBEXll6~gkdWsI-({HXlu2uu6mTon&W7-Ozhv5$79qkOEzVSCN?P1 zFfBG{iq@cmv{tK0o;J-vUkys;=&MCK6p!>M0VSd&#*^`4#EgXTW_%dmjmQ9W?SXot zUhvz8@dLVUX3jF_;WvUQ9S&`0R#>1*sa7-eL=4Zys=5hzrty|a6TB8)wLZ3$%Bi*0 z!#d!o7|V6S!3G^VpJBFHDr>olMp#|!11;tWZS9oUE%44_wv~ycsWuxdKBii`fRHWM zG^wtkm6dXk5k+i9{ZN0Diw2-Pl#dEfAu3{|jEwPT0+>KX&M25JOxMk*7?p6Hh0kC# z1PukY>c;5!4o5K0GHaQ29BU1!=HVAx&A?XDRyqu*t1y?r*w$8WuYiY0v zh;dWIJkc)X_}5!4H74t%PFakaK}-;%J&)?qIB39%Y{(9cj71aBL^KIaE``;;y25I% z9awLI|LsG|Ik>g<;z{+;Vo*iP)KBHL0&aqI?BdWmtHse>Xi3dz#Fz;d!}2{9O@sEH zLQf+Gv1mGa2F(Blafp)Kx^kXGBXTOBx@EM*Y%MU^tN0Q%CQEJG>oS;SwH4-x`J)|m z+wz!bCX`VzAxu=6IIgrDh@^&r64)A0&9R$nGU_;R>Q*K;+N}-c_6Do@3@<}xqdDu) zvrHJHJd5U``GD~P;ID;4+S(}LTW7*yUPX>b=VTIygt}Ue;m@GOXbD=1UKk=s+**)j zr9zTpeFfmsMmJ~}q!16Rz+|yDqGf3Le<)L$XUyl-GNGXrXeCJdRIAlAsS&L}%YB}H zB>bI4F9G5&qcvzPsvhbXvXY|Q!FEdxNH$YVJrl#kGN?>!7;ULGcaMvUE3pC7#@Q{S z;yU)}u}Aepj;i(6x-kL{&1ij@*e7FPv12eC1KEf+aQ%5wmQZsO+AK)l4#U$%pN@Rh zh_-OxIBET_%6H`NZNT9ZK+UX1lbJYROAUjB;eMSP?i!d7N&%@|Xm^=75*lgcj}Ahv z;{J9qYsabO=SPLkF4ob?7joXG+V&;erGZ z5HI^X!Q=pN486kvIL;)jL+>()Olk1|m@JOm570-*y9u2{AEHxC5|hjrn$X8EJI*lO zVKU6(w27z=&GBoe5!RU6N}`zj(I}SGT~iX z11tyyRVJIcWu++-$3CI7v1I@qopA^P80jY!FR+@&Tk0BY#U^W|xkVR9=hW1eeqs@J z242KYOuu#5h3U^RvjpT!>$=Gaa~sbU*aM3ju_yLoa+zXgkOP1>mIAwCAMA_$m;p>4 zli!48C=3TM1)wApF~;Elu5A>CaZhdPniw8AnLfZ&S!=O3aLa9Q8|gY=(FVgMG{u~P zxIccf;}9G=EYH}=_LCZM2wLvIFC0g8!Y>-|i)Bgxzk!UgAT(tO)ef2#>qg`m2Q=8Z zWtSKGO<2nbexWfvP5^n^TA;1fCaiDYZW2yG5u0!_HsJ2K2kwb`;oi6pGlUt+3}c2f zBbYK~BxBlyQ*jzj#~C;iXW?wzml?&BGZl=PsbVb57-lRtAVGh_Auy%vW@~@*B$z|m z#599GBSELrX|<{8NqUV&r%%$w>)Nt3owHilu@mcMSZw9hbvAPaH{)#3fKIJx0~FsG zkfV8R=d6gae}lcToHI2F>MXVP_Fd3tJr1M5F_gu)1VyY}%al4^l;Xj{3xPq0;SuZb zaAq`9IjFDMQ~@ikFk~h?3izXCM2%*96E@*;w7ewG2oDZeW<0tha0?zIyco!t4H}1; zfNOC*H)HCU>UDS=Q^O5Vq|n8dM%&2QN=IJ*Fx$@I2IPjvV^}2dL^Kgk0`t)^fdRuJ zQ*EU=y{@6w4k}2lxwg_?#ng&Pp%YW^R4B~@0<0VHG_<_kvp|5SL2hG)sb`eu@H3#9 zfPR8!;F)L*o;}#c3l5NojFlM&ddcL_)VH0_Pm5Sv;-J7>{2YpC!t?NaynwMWcBY{T zFT{)R^UQc=0yB{*9Vp1Qfr2pkd%kpZ31pJ&Zw9}UN(YuTUcsTil9|-H?BJL1%Z>pC zoe!_Wjb-940>~C|`?wrz!cDlDThafy*ppSJzsI+oVvRTAO`Kwlw=yge}F$m5zY7{{t%zSA2D;7xy(FfeltFe&)~E89J7E~ z%Dlw9%#@bqnn$-7u704PwaWNb3vY;^MsX(K;37+96<^rFq+j66Tr(H(m-s7uiFuA$ z$Sh)>Zw9AFAAA*sfh`)rECIm|vr;|~R3J`>!*XMuz*&E`BGZI{rs@VxFAD6K+p?@0 z%jlmv$(^L+4Z*XMu2c(44hxZ2Ud`ffE_`m>1UJADLzU zw8%c-7TI6$ugr30W!obA5I=f+5hD-^BM9b2=<5o`*hdCBvs;e1e8;zmvrVe#|2tUA^@MYGl18)a-I6yf71K3tqZ5GxZZj2la1rqWO0+i@V z1UXa-BA97pN_o-{VbDV&oQPnWm<_ExB%%maCp6W7riN(-G}i-~z$*f;ho)FYc0eZcK3u?Ew{XO5)JXTC*G?vU8nQd)Ps}JYoon*h=IR1wP%;qJ$Vo3?fR2!OW}7cIGwab!G?i2D6jd#q4I@WcF+&h7!Y|mm`2mBOwi*8F(7X z>}B49UhfC09f0&+NH2!}0e=}s!HMp>?SwA1cREJ1L<`&oGS)Y2T<u2{>vmWoBNDuPwbxg|0(0ZnjUbjHrRJ=|<-T|>Q~x)L_RzLwc1$hmT2 zd?UB~g9EBfqUn;fu|bAp{j_NUlTO0owag%&7EAxp|6m}WB4(n94aCy~L$Jhj;u&HF zbC`LXIl>%ejxonK5VMHc#IrC^bHS1J4s(k62!`i0d|`k%@2_Kkc)gqRL3J7(j+Grl zAo$yYTS?+r20D|5b1Am+Wrs%6%%kh9E%OL&n_jFA@6m> z3(ULgh~>Bo5ic|EgD<+H|HDzPk=VdZ!zQAcSkHXG zoMb-alJJ2f_bDA@XH_K)Ti)RoFNf%BQZ&EI!OgM1@a}-s!@(`DJDpY z7WMA)FTNZ1`aS;=Y^B@idt=4cx<{uFFWS?f&JY$Ul&QP9Qp)Utx*elNnR;#%}@Lid$m&9Hv zscGpMnOWI=bNcnq9gvq_P*`LvHVzzAI(W#?VZ(f4b8|N#88J=g%vRG{p`moj4!HRALwVrqE2u?C_ zD^!7^Hpn*GCsmsVm~3Nt|Ao+ID_`ei2+d|&>-ly7gPe+qt<=eDs2OFpGMFJ5k+Ta! zxIoa6VqC>u5P9=34R8b z+HbI#Km=O|0>LlR8=M|_cpztyV>7PA7CaVP@dDh4n_&~cCj1eo`d{OF_$LVNONnHn zJJA!u_@xl2A5Y9Ao`nGYO5!C5#~&mv5#JF%lP;t$sellBEZGNw=_AN7Bty=FaCsBC zp4>=o<^$zinEW*elWlY7X0a1YP*@g+BRAYISnbV$pg-6h)z?iXHYWZkTnOKu+ve`M^t=bF#+eD2} zEe)*33cjMnJ_!N_U<$zma0owvkw9Au6jGea4Ez{eRiv8vfqBT{P>vvi=f$C4cZ8)b;P&4L@BZ&? z=rXZNu)bjx;Pn2-+b~y}Yz;O+D@kuNhe$n{2+KN|!2Gz5Ok(bXiqU3_lRbIE`zHvW zjs8!8Ay9MTI1;M)<E6oV47`A^^j|;B{p( z7u;^-0OmKQQg|-l)tioDx5Z(gO>9-p$YOF3ifANDAXe}PGoz6#B?mKqvEVoEK&cTt zrT&Dy3Y{rsvQ>ct|$24)wu6Dk(hz|ar7QPnVwRi73dOD7@IrK`>&SI)X zu_Pye{Y_3JC$X4jv0JNJNlqmh(CEl%ryLSzvjvY5s093mcq+dhb|2f9jUDhRCjBKWV!6)YCF^N5nG$(P8N z@oX0Ru-Kc$5@z!Mn!9*kYL80!0Y@L2NU&oX$!2mri+x$_*9eQxCKgLsEbHt?eFFMV zHjl{dUjv|LyEN@SdqvSEpN6g|bELODh z4V!`-{W(E?2=a#W4U;E1-!O~2Hj$_BBJyJvcVi~7IEb4ne;24|$Haf<5EjPk6Aruc zEDmnr%qL}h$Ff+> zVhxLRo5-8wE%ICPHhG8qj=W2L&tg4`Q(4@f#U(5r$zl)%(9!7~1=4*^Ah9^SOq|tO zB6Tz(;#zFg$Al6e@8bL~YTE?MXnXs0;Wq(zWSKbo{}On*xw<;0$PAWfXXt+k&_VA{ z{a--u1eXHA!I31UOq}o^;d0AaM=GhS+EIXV7GSB$#2Nn))|1I=6n2VqM$<&8n-e0B;m87N}?t3sek?yK@^zATB|v(VS)ot?(c4 zOA8-m=%IW3g5Yp+P>B>ch8w9QDw)N-Slqjj>Q41waUT|^FvgP6(1dM7MaxzzA>Jl{ zPvO1y66dfM$wFmNIUMmasVpj+>dWFZ7N@f~gTTcFS^o<>>Af>J@=X+juIC;Hb2nr&3vGD&glG)pk;QIV$aJm?(D=e;Sq0qShE(+b^DD*9hVTXbs zX}|kN3f-rE5h(P4r;wGS&~H42Y@I3O>QGjxzi5)9&?6erm?l`N1|@Z3GfmMn zEuz7+nZ)90EPjf`Pybhui1q{$(O`Q{ZXprv4J4v{XkYHj;wdbiD*O+VEmQ0snxYlf zJaN|+2BEvqK|IyyZamc(pc);*Q;qFRwQ#~wEs~A}s?kb1ijJmXu?3@V28%(jo7GIK zIKHAmYX%#ER}kj>cM&a#BN{C7&pL?K4$-i#Em%kAv-mk7O2T>(IxaidJtVo52lCEL+N2GUc}<( zSqw|T5*9CI@e3?o#^U9hXo%>dVA@2FqRZ(D6vkpM$PdL1P{F~I1g$3G_r3zszD-x7Ie%lj$im%$#*Bh6Q9B$G#eHZ*}x)ws=5c zla#TchTGUL46D&x$$2w@hFoO4W0m~+mLmt;p@)uHyn~+?bM$m9UQa(m&!A`0vuKz@ zjV#{G;#XMwI*WI;x?t$JG`9nbo=4B87qGaA#my{U-$XB@7tz2d8(6%N#hWVIQvGf8EA*=@hJT<@yvCGFmcMl8=(w# za`qAj$`uijF%X+f4mR}S!$kSUfkTE@)>_9;p4M{2Oo(Gbn5Tu*!l?!bMy1-}9K)yv zyV=GNu#cV`Y-}hmH=7{{cvj-=>LU$!LcFih*N>qXx>4p22fzXuKZsIffpG{W!4|Ev ze$u6Dw;C9(C+B0YEz|+i+;84b%IPz!iABg4GOrBO$C&X=_)+ODMqM$iqD2?b^NP zx*iZWlycbgP7P@6lfoVGYD`P#PI)nYuy+jVH~?}x=Ig9&QCo0CwdQggRoZgINGv+T z1^=ED#qAhU%*_L8w;VI+*T0|;B5fVE92XSj!9elbj{#zF3EzK5V5s zEW|EwqO9wgI@kJf@Tw*3FR4OEQpN4Vhy84*296(Q7o`q{h-r}1MTjWM;H;$@d6~*> z^{E8~xf}!50%8Iqw*UXZdBjKW&Z;{1dQWsvMZrSEqv(-`_lnrNvg0fApgaql-x**u9 z%DIWSBL8pyYN{JJyt%(_@O8J1HTH*JHQ+y^!j!?KlOesM+>~i-Nq;-uGB6L)DF_iE z_4c$PNcV&EsD`m6sgRC^^tRE~tP)7~hV*Au4Sl(^9wAaXxvF>&q`N}8U+t*8d`NeP zbXB=6eF&tLkZ!Cp=Wyc$G$Y@)*mH^@4egP4t#w6Q`Dlcwo)zYdOyNB>dTd>P4u=qU zztc9}$i3%ro?MmA;R$U~=f{}(6+jvU5Ov>Noz0a8ICNmWy?}!W&vZs@bspDl3Z$38 z5elxq@Jye#R~2((rb9>+Vz(A^bpba~@n}m{4y3anJ+aE#mwONW6&?A{Cq?`z>~Oc0#*vq1ElOI0Eh z94$0KN(be2a8Tb2Wz29Q&;q5#@+GWrbjFeIsKM2#hf;NLjNbw$scrXkL#s?TRPxe3n#%$JZ^l?DH)}q;^Eta%7w$_8oo6v zl$eB6{QI8#J4dT+J?Hv%tF_f}fNT5Sx2KnbhHnGC>;SnMdRPk-NB|#=Q z+H}yBlSM%tW>yKbWP$UhoGi6L`_=F~>9I1xyytMM!$bKoe8Nnix>8yy2P9KI3Zhcs z>Wh??G$*Zk!iSSpg7j9wl^7{-F-8WJ%*nC#Jpkwey*P>XWbE6|46~@aC{mOuisWJQ zy%S}K`iinpkVwnD7sZMCLE6BT;!d2ydV|vI>L*#b6A?kF+{wkDoZ51AY>-Z)h1HGI znYc0t{Zz>7LRfmTyumtNct>$RG{jE4;4+y2SXDz|wH9`2^?)@q6Lf%lIO#ta_CA%v zXx0G5Ccy437Osw&2Uo|ufL6jW=Vr7Sy^40gdEEWzZ8*dF0h~+y1TKrY4C~izxGVtYgaB4w_)!Wg6&pPxMD>`CX?xKk;)KqG--wH40GYClt$R|wGXaEISawzJLGSa z2rfPef~!t?P<^Qqs+<}}Jw?rj3rseFS9x#sfFRpJ`y+RL@rb&MgLm} zcQ;G7rQHs7`!>igC^e`$=*6I8LHB|c!F_`pg4YF~3Vs+88B!85J!E^xm!Ynq$)Te| zmxdk*y%*LkY(Uu5u&rUAhr5I)hgXF!4}UlOmx#!SK@qbf-i){z=^vRBIXQA`v4+^%*v8mTRqm=( z)p*rb)z@mNI#)ei{igbETv*(YxaZ^Ejr&WJps9w{?F+59wx4#ocAxe~U9_%Tw@P;| z-XlIM{^|HV@jvKe^k)6b`p*)45(Xs9PB@bAC)_M!O?)-+R#I5f$fVUtpCqeMk52d#HMh?XjiD&7P4x%{`lYUhNgq%hYRKugkrIdXMbA zw)f>e!F^198v9&H2~DX;*^qK0H7a#X>bBIoX__=^+OD);(z~ZmOFx`JW@Kl~%{Z0m zomrB(GV`mfkgUqAty%Z76SAjdAMQ){?cewLzMtlF$tlm-oO7>VQom{aj`er%Z|uLa z|CQY6Tx;&W0mOiQ1C|W9m=~T`oA+iu%FoGPlK*8vWWl(Cw+cmt1%;~$uNP^HrWUT z9I|1^&qFhZzA*IKu!Lc=hMgZCIeg;q6C(mgRF61N=2d1Ydt)R$a?r>vBmXevn;K0& zkIEUfdepu0^z!B9w<}UAmR8&{_cAXw-x%F%^y1MsD|=Ngsk~Lyr)pW%9ZR}prR9e) zeaEaB^UK)$u^Y!esvcCmy~ep_WX;}M@7l4o$LhM)O{_azA5%Z8{_?o)<6and&)VO* z!G>+aZF}s#U|^nXP&UkL_UH z$kgDe?9{KPrA}M-6n<*dQ%9Z-eR{^z*WiHqCf1c5%YHarGkx*&`_Bw|X5Wl1Gng4y zXJ*gbI?HpGb=Ie|d(2+*EcLAA*;8}k=d76X*W8M^@6XfBTQ={H`Q`K9U!Yy^;(|xd zjehRb!o-CyFA^=PU3C8WKF@DjELl8x@zo^*mh4^{v~=#$`!AHeaAKK$*_!39%Nv$o zelhpOJuAXiEL!o$%Bq#0tV&z8eYIlsoYlX)RPoZ8ms4JTbxoHw^Va;n*0T1qb=m87 zH%2rrYZ5h$Z@S(*u=(Bf$?G?72;4Al!=D>#H(uUUwCUL9q|KYRD7GxzN^EV|dTZOT zZ6Cjq@yec8Rj;nwF5N!wHS}7;Yu~;;^7ZpO`tLaMM)Di4?hN0#dY8|xxx4Z1NxSd8 zS@q`SJ%jh0-rH~Qk$pY(?Rrc7*2ew8`&S+CJFxJe>%kcZA03)}=;y=rhwr>y`S#T# zWk@OrJAvpUpV?&bgd(AAFMc$?5YY=Rf;&*r%62tN85Z zh3X4Gd_Mm3hhH$D#LxXw{N=K*6kj!7in_G@a^mF!UuS%M@`~}w7gx)#-u}k+%^%lh zT=%%X>_)d6n{VoF?!T3F>*H^SetYe9{q2W$W_>65ZuMQ|-JRd3e1Gy@>Ah<|Sbuo* z^DRcoekXxXA{0Y0tUEq2;59|dO(}m&`I9i_pm(k_J zC3Hqy0{X{LJRGi}GlBlG7_OFk7f!35!XLu{)eEr8{40DJU&Yt(4SWj@O$NiYap6QX zkpR2R`xAM@AYvF?6jujV!%c;&;Fb}q;QF`MiDSeG;$z}0@fBS9_7mtIez1#M0av{R z!8LC&aKT$5Ts-*$LV+I1@wFL2|jADo5gQJ;DE&t zKi|87UWm`qAJV7b6z*9FA}}wpcpr=R!(rT)xKKjKKl}WJ1AG6W5bzH;2e}(s{vjyA z72=N|{Kt~TaL|u0d4~QJxzV4|7dVF@cl?jvXF0)n4FrMT;|6Kwe=WP6|;v*jgCDZ!>J!V95LkI}W*%(~qAOIZZzj zp%Q+l6wmho;Qfk03E*eyL!KZ%f(!e;A-{*~`W}*h!gYNV=&H_eS)Z2IR4b^_aQ)sG z*kn^n)l*iAh3ofbQnRT!a0%Z6*j(~FwU+uCuF^|@P@|20j@|^?>M`Js_vrWOlk_R@ zE}WsihKud4(Kq07yW4QR-S_klfRDE*T$C)T6ipT_5v>)yA=)K+Q?ys~mgs=!kmzmE zQPFYHXQIzV7e!x*E{m>+z7bs)-4uN*x+D6^#)D(%IrX*15*H&Uu`(&G}j9RiO1AaK7ODh4Yurmz=+L zzUt!V($yu{B@{GZol7s5beBw*Y?mCDQWuj;wM&D`QkNAjdtBajdEe!X%cm}vUA}Yq z&6RYeU7cKATr*wsTq|5Hu1~u@>-vW49@nd`f4KhThTI4@%FV+~?B?y}>(<3B+b!2^ zyxY@m>)p1veeCw7+hw;aZr9vyxZQG>xOa6Ab`N!ra94uv9OvE>^yf_XZ1)`Z0{0^K zV)udWrS3D_SG(_YKLGml5%**6r`<2RUvdA&{kr>2_ix?rxZidE)BTYL_8>iI4<`>7 z4>!=b13~9b^(gTe=dsXZmB%iRBOV`keCY9!$7zqV9v49azwB|v;~S6bo)XVKp0%DY zd2aE1#dEvo4$qySjlb`C*7GyZ&pj`Ce&u=F^GDD7o)0{K^?c-oy+|+G%gM{nE5s|o zYp~Z4uX3+yuSs4{dCl`$?6nm1_7}a@c&+nl@>=h;(QA{}>t6f3PI!Inb;0X?@Xv{l$S|g}AFYNE{*#6DNq1#0GH>aW8QnaVqHgnc{5m81YQ;TJb6IEeR!2N%~51 zBm*UbB&Cuel1fRH#3C6hu}daMCP}79o&h^xg=DQ{gX9g#PRTCGo04Oa6TK&UPxW5lz1(|+_bTs~ zyw`Yd^4{gW-}|8VVecc}C%ixK{?Pj)@6+C&d0+A&d=x%0K6;-dAA?U1pT0ghKK*=h zeM)>9e5U%W_SxZc(&uZRt3KC!Zus2tx$Se`=NF&fd>;Bb`?~tN`+E9z@s03}_f7Ck z@-_JO^_}j!(093Slka-pjlP?GclhoB`TUOW3EvNVKlHus`;+e*o)Z#-Btll`XpJ>|FBZ?E4)zn}dc_&t&$ zDIxWedP{w!GHHNRE{&5WOM6NCNK>Wh(gNuq>0s$l>2PU!eN6_0o;f*QNWU?@Hg7o|JwhJuN*ey&=6X{aN}z`m2nVIm=vS9x^YP zL>4IPCJUB@%EDzjnL*Y=)=Sn$mL=;e>nF>V<;hBACRwelK{i1)Nj60`T{c5DOZKd6 zu57hzy=;eUuk0<^0ofthJF@p=@5@fgPRZ{26aL};I{zI1{{92}^Zg6`js7M6gZu~k z5A`4JU*|n|Ec~@`7{30{b%^k@_!brwE6ze`ET-n)BlYBw*f8z{sFN8DFMX+ z^#L;jo(otAcH7E;H37Q=4h0+zI1=zdz}%N-hD5Pbv?P%jI3`3G5QuB_{a&;FH0h1YZsQHu#6&zd|G-J|TV~vXFof zc}SO#ZXpn(4M_}14(T4!Dh!w!XA3A-J3H|$>6k6{nP{s{XkToxV{9u*!Ft_s(M>%)`6 z4dGegeZ%{O=Y}r`Um4yMzCL_Y_}1`O!`}?w7k(i8aQM;il6*(<(R^*(>`H{~>u8C}nTpzh9a!cgx$oopH6e(Sl z?n;T$S1D5lD1(%d%AU&p%2MTE1qxwhX zMh%F{kFrFKkD47dH)=uDqNpWN%c539t&Um~^;*;$QM;q|M(vL}6m=x(c+`7Q??-(a zbs_4DsIQ_UqxI2=(aF(0qGv`gj$RtQEP6%sm(kxw--*5({XRmob-OuEZ*16JnFVPtY@VR_v14)v;^9U$8!QQ|#-pJ7eFB-5a|< z_F(K6Dy#}uWvB+I3RFf_iE4zZQe{z%Rn@5KRO3{WRkKy|RSQ*%Rm)W?RWGU5sMf1? zst%|Qst&7;syJ92m>MiPR>Q~iosSm48|Oe>7yB@nXcKOIj%XSIjuRTIj^~-xv9Ag-v4`= zA2s(i545D#S?i|t)cR?H@W?=cyCxymh`hsm@;)4jvYjPNPfECF^?Vdg*d?`MO~`v#v@vR#&SV zr<<&srek!|bu)Fdbb$7uNBaIJ;SHyRXkBryE!|~?$#Q5a+?(y02x$*h&Me&2; zhr|z$FN?2@9~b{r{OtI-@eAS?#V?6p9ls{NF@AmgruZ%K@5Xp_PAAPF6 zpWdh+s2{8!rZ3Z*^yT2;snyr(r|GBbXX>BTFVHX2FVVlCZ`N%bvcO(2p1)b{D`OK?uJhhutSUqN0fZ17R+w_W%F@ literal 0 HcmV?d00001 diff --git a/CollectionView.xcodeproj/xcuserdata/tib.xcuserdatad/xcschemes/xcschememanagement.plist b/CollectionView.xcodeproj/xcuserdata/tib.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8d47f01 --- /dev/null +++ b/CollectionView.xcodeproj/xcuserdata/tib.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + CollectionView.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..ae3fbd0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2015-2019 Tibor Bodecs + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md new file mode 100755 index 0000000..7013de8 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# CoreKit CollectionView + +CollectionViews with ease! + + + +## Installation + + + +### CocoaPods + +``` +source 'https://github.com/CoreKit/CollectionView.git' +pod 'CollectionView' +``` + + + +### Carthage + +``` +github "CoreKit/CollectionView" "1.0.0" +``` + + + +## License + +[WTFPL](LICENSE) - Do what the fuck you want to. diff --git a/Sources/CollectionViewCell+Reuse.swift b/Sources/CollectionViewCell+Reuse.swift new file mode 100755 index 0000000..da16a78 --- /dev/null +++ b/Sources/CollectionViewCell+Reuse.swift @@ -0,0 +1,70 @@ +// +// CollectionViewCell+Reuse.swift +// CVVM +// +// Created by Tibor Bödecs on 2018. 04. 11.. +// Copyright © 2018. Tibor Bödecs. All rights reserved. +// + +import UIKit + +public extension UICollectionViewCell { + + public static var uniqueIdentifier: String { + return String(describing: self) + } + + public var uniqueIdentifier: String { + return type(of: self).uniqueIdentifier + } + + public static var hasNib: Bool { + return Bundle.main.path(forResource: self.uniqueIdentifier, ofType: "nib") != nil + } + + public static var nib: UINib { + return UINib(nibName: self.uniqueIdentifier, bundle: nil) + } + + // MARK: - cells + + public static func register(nibFor collectionView: UICollectionView) { + collectionView.register(self.nib, forCellWithReuseIdentifier: self.uniqueIdentifier) + } + + public static func register(classFor collectionView: UICollectionView) { + collectionView.register(self, forCellWithReuseIdentifier: self.uniqueIdentifier) + } + + public static func register(itemFor collectionView: UICollectionView) { + if self.hasNib { + return self.register(nibFor: collectionView) + } + self.register(classFor: collectionView) + } + + public static func reuse(_ collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell { + return collectionView.dequeueReusableCell(withReuseIdentifier: self.uniqueIdentifier, for: indexPath) + } + + // MARK: - supplementary views + + public static func register(nibFor collectionView: UICollectionView, kind: String) { + collectionView.register(self.nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: self.uniqueIdentifier) + } + + public static func register(classFor collectionView: UICollectionView, kind: String) { + collectionView.register(self, forSupplementaryViewOfKind: kind, withReuseIdentifier: self.uniqueIdentifier) + } + + public static func register(itemFor collectionView: UICollectionView, kind: String) { + if self.hasNib { + return self.register(nibFor: collectionView, kind: kind) + } + self.register(classFor: collectionView, kind: kind) + } + + public static func reuse(_ collectionView: UICollectionView, indexPath: IndexPath, kind: String) -> UICollectionReusableView { + return collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: self.uniqueIdentifier, for: indexPath) + } +} diff --git a/Sources/CollectionViewCell.swift b/Sources/CollectionViewCell.swift new file mode 100755 index 0000000..840cda9 --- /dev/null +++ b/Sources/CollectionViewCell.swift @@ -0,0 +1,46 @@ +// +// CollectionViewCell.swift +// CVVM +// +// Created by Tibor Bödecs on 2018. 04. 11.. +// Copyright © 2018. Tibor Bödecs. All rights reserved. +// + +import UIKit + +open class CollectionViewCell: UICollectionViewCell { + + public override init(frame: CGRect) { + super.init(frame: frame) + + self.initialize() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + self.initialize() + } + + open override func awakeFromNib() { + super.awakeFromNib() + + self.reset() + } + + open override func prepareForReuse() { + super.prepareForReuse() + + self.reset() + } + + // MARK: - API + + open func initialize() { + + } + + open func reset() { + + } +} diff --git a/Sources/CollectionViewController.swift b/Sources/CollectionViewController.swift new file mode 100755 index 0000000..87ce310 --- /dev/null +++ b/Sources/CollectionViewController.swift @@ -0,0 +1,90 @@ +// +// CollectionViewController.swift +// CVVM +// +// Created by Tibor Bödecs on 2018. 04. 11.. +// Copyright © 2018. Tibor Bödecs. All rights reserved. +// + +import UIKit + +class CollectionViewController: UIViewController { + + @IBOutlet open weak var collectionView: UICollectionView! + + open var source: CollectionViewSource? = nil { + didSet { + self.source?.register(itemsFor: self.collectionView) + + self.collectionView.dataSource = self.source + self.collectionView.delegate = self.source + } + } + + open override func loadView() { + super.loadView() + + let collectionView = UICollectionView.init(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + collectionView.translatesAutoresizingMaskIntoConstraints = false + self.collectionView = collectionView + self.view.addSubview(self.collectionView) + + NSLayoutConstraint.activate([ + self.collectionView.topAnchor.constraint(equalTo: self.view.topAnchor), + self.collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), + self.collectionView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor), + self.collectionView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor), + ]) + } + + override func viewDidLoad() { + super.viewDidLoad() + + self.view.backgroundColor = .white + self.collectionView.backgroundColor = .clear + self.collectionView.alwaysBounceVertical = true + self.collectionView.showsVerticalScrollIndicator = true + } + + open override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + + if self.isViewLoaded && self.view.window == nil { + self.collectionView = nil + } + } + + // MARK: - handle autorotation + + open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + guard + let previousTraitCollection = previousTraitCollection, + self.traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass || + self.traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass + else { + return + } + + self.collectionView.collectionViewLayout.invalidateLayout() + self.collectionView.reloadData() + } + + open override func viewWillTransition(to size: CGSize, + with coordinator: UIViewControllerTransitionCoordinator) { + + super.viewWillTransition(to: size, with: coordinator) + + self.collectionView.collectionViewLayout.invalidateLayout() + self.collectionView.bounds.size = size + + coordinator.animate(alongsideTransition: { context in + context.viewController(forKey: UITransitionContextViewControllerKey.from) + + }, completion: { [weak self] _ in + self?.collectionView.collectionViewLayout.invalidateLayout() + }) + } +} + diff --git a/Sources/CollectionViewSection.swift b/Sources/CollectionViewSection.swift new file mode 100755 index 0000000..73a2192 --- /dev/null +++ b/Sources/CollectionViewSection.swift @@ -0,0 +1,36 @@ +// +// CollectionViewSection.swift +// CVVM +// +// Created by Tibor Bödecs on 2018. 04. 11.. +// Copyright © 2018. Tibor Bödecs. All rights reserved. +// + +import UIKit + +public typealias CollectionViewCallback = (Any, IndexPath) -> Void + +open class CollectionViewSection { + + public var grid: Grid? + public var header: CollectionViewViewModelProtocol? + public var footer: CollectionViewViewModelProtocol? + public var items: [CollectionViewViewModelProtocol] + public var callback: CollectionViewCallback? + + public init(grid: Grid? = nil, + header: CollectionViewViewModelProtocol? = nil, + footer: CollectionViewViewModelProtocol? = nil, + items: [CollectionViewViewModelProtocol] = [], + callback: CollectionViewCallback? = nil) { + self.grid = grid + self.header = header + self.footer = footer + self.items = items + self.callback = callback + } + + public func add(_ item: CollectionViewViewModelProtocol) { + self.items.append(item) + } +} diff --git a/Sources/CollectionViewSource.swift b/Sources/CollectionViewSource.swift new file mode 100755 index 0000000..d0df2e8 --- /dev/null +++ b/Sources/CollectionViewSource.swift @@ -0,0 +1,248 @@ +// +// CollectionViewSource.swift +// CVVM +// +// Created by Tibor Bödecs on 2018. 04. 11.. +// Copyright © 2018. Tibor Bödecs. All rights reserved. +// + +import UIKit + +public extension Array { + + public func element(at index: Int) -> Element? { + return index < self.count && index >= 0 ? self[index] : nil + } +} + +open class CollectionViewSource: NSObject { + + private var indexPathSelected = false + + open var grid: Grid + open var sections: [CollectionViewSection] + open var callback: CollectionViewCallback? + + public init(grid: Grid = Grid(), + sections: [CollectionViewSection] = [], + callback: CollectionViewCallback? = nil) { + + self.grid = grid + self.sections = sections + self.callback = callback + + super.init() + } + + public func add(_ section: CollectionViewSection) { + self.sections.append(section) + } + + // MARK: - section indexes + + public var sectionIndexes: IndexSet? { + if self.sections.isEmpty { + return nil + } + if self.sections.count == 1 { + return IndexSet(integer: 0) + } + return IndexSet(integersIn: 0.. CollectionViewSection? { + return self.sections.element(at: section) + } + + public func itemAt(_ indexPath: IndexPath) -> CollectionViewViewModelProtocol? { + return self.itemAt(indexPath.section)?.items.element(at: indexPath.item) + } + + // MARK: - view registration + + public func register(itemsFor collectionView: UICollectionView) { + + for section in self.sections { + section.header?.cell.register(itemFor: collectionView, kind: UICollectionView.elementKindSectionHeader) + section.footer?.cell.register(itemFor: collectionView, kind: UICollectionView.elementKindSectionFooter) + + for cell in section.items.map({ $0.cell }) { + cell.register(itemFor: collectionView) + } + } + } +} + +extension CollectionViewSource: UICollectionViewDataSource { + + public func numberOfSections(in collectionView: UICollectionView) -> Int { + return self.sections.count + } + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return self.itemAt(section)?.items.count ?? 0 + } + + private func collectionView(_ collectionView: UICollectionView, + itemForIndexPath indexPath: IndexPath) -> UICollectionViewCell { + guard + let data = self.itemAt(indexPath), + let item = data.cell.reuse(collectionView, indexPath: indexPath) as? CollectionViewCell + else { + return CollectionViewCell.reuse(collectionView, indexPath: indexPath) + } + data.config(cell: item, data: data.value, indexPath: indexPath, grid: self.grid(indexPath.section)) + return item + } + + public func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + return self.collectionView(collectionView, itemForIndexPath: indexPath) + } + + + private func _collectionView(_ collectionView: UICollectionView, + viewForSupplementaryElementOfKind kind: String, + at indexPath: IndexPath) -> UICollectionReusableView + { + let grid = self.grid(indexPath.section) + let section = self.itemAt(indexPath.section) + + if kind == UICollectionView.elementKindSectionHeader { + guard + let section = section, + let data = section.header, + let cell = data.cell.reuse(collectionView, + indexPath: indexPath, + kind: UICollectionView.elementKindSectionHeader) as? CollectionViewCell + else { + return CollectionViewCell.reuse(collectionView, indexPath: indexPath) + } + data.config(cell: cell, data: data.value, indexPath: indexPath, grid: grid) + return cell + } + + if kind == UICollectionView.elementKindSectionFooter { + guard + let section = section, + let data = section.footer, + let cell = data.cell.reuse(collectionView, + indexPath: indexPath, + kind: UICollectionView.elementKindSectionFooter) as? CollectionViewCell + else { + return CollectionViewCell.reuse(collectionView, indexPath: indexPath) + } + data.config(cell: cell, data: data.value, indexPath: indexPath, grid: grid) + return cell + } + + return CollectionViewCell.reuse(collectionView, + indexPath: indexPath, + kind: UICollectionView.elementKindSectionHeader) + } + + public func collectionView(_ collectionView: UICollectionView, + viewForSupplementaryElementOfKind kind: String, + at indexPath: IndexPath) -> UICollectionReusableView { + return self._collectionView(collectionView, viewForSupplementaryElementOfKind: kind, at: indexPath) + } + + public func collectionView(_ collectionView: UICollectionView, + canMoveItemAt indexPath: IndexPath) -> Bool + { + return false + } + + public func collectionView(_ collectionView: UICollectionView, + moveItemAt sourceIndexPath: IndexPath, + to destinationIndexPath: IndexPath) { + + } +} + +extension CollectionViewSource: UICollectionViewDelegate { + + func selectItem(at indexPath: IndexPath) { + guard let data = self.itemAt(indexPath), !self.indexPathSelected else { + return + } + + //source + self.callback?(data.value, indexPath) + //section + self.itemAt(indexPath.section)?.callback?(data.value, indexPath) + //view-model + data.callback(data: data.value, indexPath: indexPath) + } + + public func collectionView(_ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath) { + self.selectItem(at: indexPath) + } + + public func collectionView(_ collectionView: UICollectionView, + willDisplay cell: UICollectionViewCell, + forItemAt indexPath: IndexPath) { + + } +} + +extension CollectionViewSource: UICollectionViewDelegateFlowLayout { + + func grid(_ section: Int) -> Grid { + return self.itemAt(section)?.grid ?? self.grid + } + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + guard let data = self.itemAt(indexPath) else { + return .zero + } + let grid = self.grid(indexPath.section) + + return data.size(data: data.value, indexPath: indexPath, grid: grid, view: collectionView) + } + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + insetForSectionAt section: Int) -> UIEdgeInsets { + return self.grid(section).margin + } + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return self.grid(section).verticalPadding + } + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return self.grid(section).horizontalPadding + } + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + referenceSizeForHeaderInSection section: Int) -> CGSize { + guard let data = self.itemAt(section)?.header else { + return .zero + } + let indexPath = IndexPath(item: -1, section: section) + let grid = self.grid(section) + return data.size(data: data.value, indexPath: indexPath, grid: grid, view: collectionView) + } + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + referenceSizeForFooterInSection section: Int) -> CGSize { + guard let data = self.itemAt(section)?.footer else { + return .zero + } + let indexPath = IndexPath(item: -1, section: section) + let grid = self.grid(section) + return data.size(data: data.value, indexPath: indexPath, grid: grid, view: collectionView) + } +} diff --git a/Sources/CollectionViewViewModel.swift b/Sources/CollectionViewViewModel.swift new file mode 100755 index 0000000..df680e7 --- /dev/null +++ b/Sources/CollectionViewViewModel.swift @@ -0,0 +1,72 @@ +// +// CollectionViewViewModel.swift +// CVVM +// +// Created by Tibor Bödecs on 2018. 04. 11.. +// Copyright © 2018. Tibor Bödecs. All rights reserved. +// + +import UIKit + +public protocol CollectionViewViewModelProtocol { + + var cell: CollectionViewCell.Type { get } + var value: Any { get } + + func config(cell: CollectionViewCell, data: Any, indexPath: IndexPath, grid: Grid) + func size(data: Any, indexPath: IndexPath, grid: Grid, view: UIView) -> CGSize + func callback(data: Any, indexPath: IndexPath) +} + +open class CollectionViewViewModel: CollectionViewViewModelProtocol where Cell: CollectionViewCell, Data: Any { + + public var data: Data + public var cell: CollectionViewCell.Type { return Cell.self } + public var value: Any { return self.data } + + public init(_ data: Data) { + self.data = data + self.initialize() + } + + // MARK: - CollectionViewViewModelProtocol + + public func config(cell: CollectionViewCell, data: Any, indexPath: IndexPath, grid: Grid) { + guard let data = data as? Data, let cell = cell as? Cell else { + return + } + return self.config(cell: cell, data: data, indexPath: indexPath, grid: grid) + } + + public func size(data: Any, indexPath: IndexPath, grid: Grid, view: UIView) -> CGSize { + guard let data = data as? Data else { + return .zero + } + return self.size(data: data, indexPath: indexPath, grid: grid, view: view) + } + + public func callback(data: Any, indexPath: IndexPath) { + guard let data = data as? Data else { + return + } + return self.callback(data: data, indexPath: indexPath) + } + + // MARK: - API + + open func initialize() { + + } + + open func config(cell: Cell, data: Data, indexPath: IndexPath, grid: Grid) { + + } + + open func size(data: Data, indexPath: IndexPath, grid: Grid, view: UIView) -> CGSize { + return .zero + } + + open func callback(data: Data, indexPath: IndexPath) { + + } +} diff --git a/Sources/Grid.swift b/Sources/Grid.swift new file mode 100755 index 0000000..b29031d --- /dev/null +++ b/Sources/Grid.swift @@ -0,0 +1,88 @@ +// +// Grid.swift +// CVVM +// +// Created by Tibor Bödecs on 2018. 04. 11.. +// Copyright © 2018. Tibor Bödecs. All rights reserved. +// + +import UIKit + +extension UIEdgeInsets { + init(all value: CGFloat) { + self.init(top: value, left: value, bottom: value, right: value) + } +} + +extension CGFloat { + + public var evenRounded: CGFloat { + var newValue = self.rounded(.towardZero) + if newValue.truncatingRemainder(dividingBy: 2) == 1 { + newValue -= 1 + } + return newValue + } +} + +open class Grid { + + open var columns: CGFloat + open var margin: UIEdgeInsets + open var padding: UIEdgeInsets + + public var verticalMargin: CGFloat { + return self.margin.top + self.margin.bottom + } + + public var horizontalMargin: CGFloat { + return self.margin.left + self.margin.right + } + + // line spacing + public var verticalPadding: CGFloat { + return self.padding.top + self.padding.bottom + } + + // inter item spacing + public var horizontalPadding: CGFloat { + return self.padding.left + self.padding.right + } + + public init(columns: CGFloat = 1, margin: UIEdgeInsets = .zero, padding: UIEdgeInsets = .zero) { + self.columns = columns + self.margin = margin + self.padding = padding + } + + open func size(for view: UIView, ratio: CGFloat, items: CGFloat = 1, gaps: CGFloat? = nil) -> CGSize { + let size = self.width(for: view, items: items, gaps: gaps) + return CGSize(width: size, height: (size * ratio).evenRounded) + } + + open func size(for view: UIView, height: CGFloat, items: CGFloat = 1, gaps: CGFloat? = nil) -> CGSize { + let size = self.width(for: view, items: items, gaps: gaps) + + var height = height + if height < 0 { + height = view.bounds.size.height - height + } + return CGSize(width: size, height: height.evenRounded) + } + + open func width(for view: UIView, items: CGFloat = 1, gaps: CGFloat? = nil) -> CGFloat { + let gaps = gaps ?? items - 1 + + let width = view.bounds.size.width - self.horizontalMargin - self.horizontalPadding * gaps + + return (width / self.columns * items).evenRounded + } + + open func height(for view: UIView, items: CGFloat = 1, gaps: CGFloat? = nil) -> CGFloat { + let gaps = gaps ?? items - 1 + + let height = view.bounds.size.height - self.verticalMargin - self.verticalPadding * gaps + + return (height / self.columns * items).evenRounded + } +} diff --git a/iOS/CollectionView.h b/iOS/CollectionView.h new file mode 100644 index 0000000..137105e --- /dev/null +++ b/iOS/CollectionView.h @@ -0,0 +1,17 @@ +// +// CollectionView.h +// CollectionView +// +// Created by Tibor Bödecs on 2019. 02. 11.. +// Copyright © 2019. Tibor Bödecs. All rights reserved. +// + +#import + +//! Project version number for CollectionView. +FOUNDATION_EXPORT double CollectionViewVersionNumber; + +//! Project version string for CollectionView. +FOUNDATION_EXPORT const unsigned char CollectionViewVersionString[]; + + diff --git a/iOS/Info.plist b/iOS/Info.plist new file mode 100644 index 0000000..e1fe4cf --- /dev/null +++ b/iOS/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + +