diff --git a/LeadKit.podspec b/LeadKit.podspec index 98ca3fa5..58ac893b 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -34,6 +34,8 @@ Pod::Spec.new do |s| "Sources/Classes/Views/XibView/*", "Sources/Classes/Views/SpinnerView/*", "Sources/Classes/Views/DefaultPlaceholders/*", + "Sources/Classes/Views/CollectionViewWrapperView/*", + "Sources/Classes/Views/TableViewWrapperView/*", "Sources/Extensions/CABasicAnimation/*", "Sources/Extensions/CGFloat/CGFloat+Pixels.swift", "Sources/Extensions/NetworkService/NetworkService+ActivityIndicator-UIApplication.swift", @@ -59,6 +61,7 @@ Pod::Spec.new do |s| "Sources/Structures/DataLoading/PaginationDataLoading/*" ] ss.tvos.exclude_files = [ + "Sources/Classes/Controllers/BaseTableContentController.swift", "Sources/Classes/Views/SeparatorRowBox/*", "Sources/Classes/Views/SeparatorCell/*", "Sources/Classes/Views/EmptyCell/*", diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index f312b50e..035f27b9 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -400,6 +400,9 @@ 675C1FB41F97CA32007D5249 /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; }; 675C1FB51F97CA33007D5249 /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; }; 675C1FB61F97CA33007D5249 /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; }; + 675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; }; + 675E0AAA21072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; }; + 675E0AAB21072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; }; 6762131820A0BBA30034EEF1 /* TableSection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */; }; 676B22A2206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */; }; 676B22A3206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */; }; @@ -500,6 +503,17 @@ 67CAF8C820652E2A00527085 /* TextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CAF8C520652E2A00527085 /* TextFieldViewModel.swift */; }; 67CAF8C920652E2A00527085 /* TextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CAF8C520652E2A00527085 /* TextFieldViewModel.swift */; }; 67CDEE401EB369BF00895905 /* ConfigurableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462241EB3396E00EAB194 /* ConfigurableController.swift */; }; + 67DB7760210869D1001CB56B /* TableViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */; }; + 67DB7761210869D1001CB56B /* TableViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */; }; + 67DB7762210869D1001CB56B /* TableViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */; }; + 67DB776421086A12001CB56B /* BaseTableContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776321086A12001CB56B /* BaseTableContentController.swift */; }; + 67DB776521086A12001CB56B /* BaseTableContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776321086A12001CB56B /* BaseTableContentController.swift */; }; + 67DB776921087154001CB56B /* CollectionViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */; }; + 67DB776A21087154001CB56B /* CollectionViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */; }; + 67DB776B21087154001CB56B /* CollectionViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */; }; + 67DB776D210871E8001CB56B /* BaseCollectionContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */; }; + 67DB776E210871E8001CB56B /* BaseCollectionContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */; }; + 67DB776F210871E8001CB56B /* BaseCollectionContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */; }; 67E6C2351EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; }; 67E6C2361EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; }; 67E6C2371EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; }; @@ -788,6 +802,7 @@ 6741CECC20E243F800FEC4D9 /* BaseCustomViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCustomViewController.swift; sourceTree = ""; }; 6741CECD20E243F800FEC4D9 /* BaseConfigurableController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseConfigurableController.swift; sourceTree = ""; }; 674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+LoadingIndicator.swift"; sourceTree = ""; }; + 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseScrollContentController.swift; sourceTree = ""; }; 6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableSection+Extensions.swift"; sourceTree = ""; }; 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = ""; }; 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+PaginationWrappable.swift"; sourceTree = ""; }; @@ -828,6 +843,10 @@ 67C7B1782068BB1C00C9EDA3 /* NumberFormattingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormattingService.swift; sourceTree = ""; }; 67CAF8AB2065189C00527085 /* NetworkService+ActivityIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkService+ActivityIndicator.swift"; sourceTree = ""; }; 67CAF8C520652E2A00527085 /* TextFieldViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldViewModel.swift; sourceTree = ""; }; + 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewWrapperView.swift; sourceTree = ""; }; + 67DB776321086A12001CB56B /* BaseTableContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableContentController.swift; sourceTree = ""; }; + 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewWrapperView.swift; sourceTree = ""; }; + 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCollectionContentController.swift; sourceTree = ""; }; 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleLoadCursor.swift; sourceTree = ""; }; 67EB7FBF206140E600BDD9FB /* TotalCountCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursor.swift; sourceTree = ""; }; 67EB7FC6206148D000BDD9FB /* TotalCountCursorListingResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursorListingResult.swift; sourceTree = ""; }; @@ -1001,12 +1020,14 @@ 671461D41EB3396E00EAB194 /* Views */ = { isa = PBXGroup; children = ( - 677A4AC9206510FA00753C74 /* TextField */, + 67DB77672108714A001CB56B /* CollectionViewWrapperView */, 673CF42A2063DE3A00C329F6 /* DefaultPlaceholders */, - A6AF3B381F8B957400CDB971 /* SeparatorRowBox */, - A66428A41F8A651700C6308D /* SeparatorCell */, A6C9A4F71F8BBC0F009311CC /* EmptyCell */, + A66428A41F8A651700C6308D /* SeparatorCell */, + A6AF3B381F8B957400CDB971 /* SeparatorRowBox */, A6C9A4F81F8BBC27009311CC /* SpinnerView */, + 67DB775E210869C7001CB56B /* TableViewWrapperView */, + 677A4AC9206510FA00753C74 /* TextField */, A6C9A4F91F8BBCCE009311CC /* XibView */, ); path = Views; @@ -1559,8 +1580,11 @@ 6741CEC520E2434900FEC4D9 /* Controllers */ = { isa = PBXGroup; children = ( + 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */, 6741CECD20E243F800FEC4D9 /* BaseConfigurableController.swift */, 6741CECC20E243F800FEC4D9 /* BaseCustomViewController.swift */, + 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */, + 67DB776321086A12001CB56B /* BaseTableContentController.swift */, ); path = Controllers; sourceTree = ""; @@ -1765,6 +1789,22 @@ path = NumberFormattingService; sourceTree = ""; }; + 67DB775E210869C7001CB56B /* TableViewWrapperView */ = { + isa = PBXGroup; + children = ( + 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */, + ); + path = TableViewWrapperView; + sourceTree = ""; + }; + 67DB77672108714A001CB56B /* CollectionViewWrapperView */ = { + isa = PBXGroup; + children = ( + 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */, + ); + path = CollectionViewWrapperView; + sourceTree = ""; + }; 67EB7FC5206148C400BDD9FB /* DataLoading */ = { isa = PBXGroup; children = ( @@ -2637,6 +2677,7 @@ 673CF42C2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */, 67ED2BDE20B44DEB00508B3E /* InitializableView.swift in Sources */, 671463601EB3396E00EAB194 /* SupportProtocol.swift in Sources */, + 67DB776421086A12001CB56B /* BaseTableContentController.swift in Sources */, 671462841EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */, EFBE57DB1EC361620040E00A /* UIView+Layout.swift in Sources */, 6714639E1EB33AEB00EAB194 /* NetworkService+ActivityIndicator-UIApplication.swift in Sources */, @@ -2650,12 +2691,14 @@ 674AF55C1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift in Sources */, 67A1FF8F1EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */, 673564F62068C68D00F0CBED /* NumberFormat.swift in Sources */, + 67DB776921087154001CB56B /* CollectionViewWrapperView.swift in Sources */, 671462901EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */, 67EB7FC0206140E600BDD9FB /* TotalCountCursor.swift in Sources */, 36DAAF512007CC920090BE0D /* UITableView+Extensions.swift in Sources */, 671463841EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */, 6774528D20625C9E0024EEEF /* GeneralDataLoadingState.swift in Sources */, + 675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */, 671462D01EB3396E00EAB194 /* UIScrollView+Support.swift in Sources */, 671463901EB3396E00EAB194 /* TemplateDrawingOperation.swift in Sources */, A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */, @@ -2728,6 +2771,7 @@ 6774529220625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */, 6714637C1EB3396E00EAB194 /* ImageDrawingOperation.swift in Sources */, 671463341EB3396E00EAB194 /* DrawingOperation.swift in Sources */, + 67DB7760210869D1001CB56B /* TableViewWrapperView.swift in Sources */, 673CF4182063D50700C329F6 /* GeneralDataLoadingController.swift in Sources */, 6741CECE20E243F800FEC4D9 /* BaseCustomViewController.swift in Sources */, 671462701EB3396E00EAB194 /* CursorError.swift in Sources */, @@ -2783,6 +2827,7 @@ 678D267920691D8200B05B93 /* DataModelFieldBinding.swift in Sources */, 673CF4342063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */, 673CF4222063D90600C329F6 /* DisposeBagHolder.swift in Sources */, + 67DB776D210871E8001CB56B /* BaseCollectionContentController.swift in Sources */, 671463681EB3396E00EAB194 /* ConfigurableView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2953,6 +2998,7 @@ 6741CEC020E242FA00FEC4D9 /* UIScrollView+RxBindings.swift in Sources */, 671463A51EB33FF600EAB194 /* Animatable.swift in Sources */, 67CAF8C920652E2A00527085 /* TextFieldViewModel.swift in Sources */, + 675E0AAB21072FF400CDC143 /* BaseScrollContentController.swift in Sources */, 6714629B1EB3396E00EAB194 /* CGSize+Resize.swift in Sources */, 671463331EB3396E00EAB194 /* CursorType.swift in Sources */, 6714624F1EB3396E00EAB194 /* MapCursor.swift in Sources */, @@ -2973,6 +3019,7 @@ 6714632B1EB3396E00EAB194 /* BaseViewModel.swift in Sources */, 673564F42068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */, 677452A220625EEE0024EEEF /* PaginationDataLoadingModel.swift in Sources */, + 67DB776F210871E8001CB56B /* BaseCollectionContentController.swift in Sources */, 673CF4362063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */, A6F32C0C1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */, 6741CEB620E242C100FEC4D9 /* CollectionViewHolder+ScrollViewHolder.swift in Sources */, @@ -2986,6 +3033,7 @@ 67745289206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */, 67386A8F206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */, 671463071EB3396E00EAB194 /* UIView+LoadingIndicator.swift in Sources */, + 67DB7762210869D1001CB56B /* TableViewWrapperView.swift in Sources */, 6774526E206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */, 671463A91EB340C000EAB194 /* UIViewController+ConfigurableController.swift in Sources */, 673564F92068C68D00F0CBED /* NumberFormat.swift in Sources */, @@ -3047,6 +3095,7 @@ 673CF4252063D90600C329F6 /* DisposeBagHolder.swift in Sources */, 6714637B1EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */, 6741CEA720E2418200FEC4D9 /* TableViewHolder.swift in Sources */, + 67DB776B21087154001CB56B /* CollectionViewWrapperView.swift in Sources */, 6774529520625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */, 6713C23A20AF0C4D00875921 /* NetworkOperationState.swift in Sources */, 6774529D20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, @@ -3103,6 +3152,7 @@ 6792623D206EB0EC00308E62 /* CellSeparatorType+Extensions.swift in Sources */, 671462E51EB3396E00EAB194 /* UIColor+Hex.swift in Sources */, 67EB7FFE206176C900BDD9FB /* AnyPaginationWrappable.swift in Sources */, + 67DB776E210871E8001CB56B /* BaseCollectionContentController.swift in Sources */, 67274773206CCF1200725163 /* ViewText.swift in Sources */, 678D26A520692BFF00B05B93 /* TextFieldViewModelEvents.swift in Sources */, 677452B720627FE00024EEEF /* PaginationWrappable.swift in Sources */, @@ -3162,6 +3212,7 @@ 6774526D206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */, 6714627D1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 673CF4352063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */, + 675E0AAA21072FF400CDC143 /* BaseScrollContentController.swift in Sources */, 6727476F206CCDDB00725163 /* ViewBackground+Configuration.swift in Sources */, 673CF4232063D90600C329F6 /* DisposeBagHolder.swift in Sources */, 6741CEBF20E242FA00FEC4D9 /* UIScrollView+RxBindings.swift in Sources */, @@ -3185,11 +3236,13 @@ 677452A020625EEE0024EEEF /* PaginationDataLoadingModel.swift in Sources */, 3622F5E220E25883009DED94 /* SeparatorRowBox.swift in Sources */, 6741CEA620E2418200FEC4D9 /* TableViewHolder.swift in Sources */, + 67DB776A21087154001CB56B /* CollectionViewWrapperView.swift in Sources */, 67FDC2601FA310EA00C76A77 /* RequestError.swift in Sources */, 6774529320625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */, 6741CEC320E2430A00FEC4D9 /* UITableView+TableViewHolder.swift in Sources */, 671462711EB3396E00EAB194 /* CursorError.swift in Sources */, 671463991EB3396E00EAB194 /* AnyLoadingIndicator.swift in Sources */, + 67DB7761210869D1001CB56B /* TableViewWrapperView.swift in Sources */, 673CF4392063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */, 671463A81EB340C000EAB194 /* UIViewController+ConfigurableController.swift in Sources */, 671463151EB3396E00EAB194 /* UIViewController+TopVisibleViewController.swift in Sources */, @@ -3230,6 +3283,7 @@ 6737CFA4207220960063E056 /* SeparatorConfiguration+Extensions.swift in Sources */, 67926237206EB0AE00308E62 /* CellSeparatorType.swift in Sources */, B84CB06E20B8325D0090DB91 /* SessionManager.swift in Sources */, + 67DB776521086A12001CB56B /* BaseTableContentController.swift in Sources */, 6774527A206252020024EEEF /* DataLoadingState.swift in Sources */, 6714628D1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */, 67745269206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */, diff --git a/Sources/Classes/Controllers/BaseCollectionContentController.swift b/Sources/Classes/Controllers/BaseCollectionContentController.swift new file mode 100644 index 00000000..236f124b --- /dev/null +++ b/Sources/Classes/Controllers/BaseCollectionContentController.swift @@ -0,0 +1,49 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit + +/// Base collection controller configurable with view model and CollectionViewWrapperView as custom view. +open class BaseCollectionContentController: BaseScrollContentController { + + /// Initializer with view model, collection view holder and table director parameters. + /// + /// - Parameters: + /// - viewModel: A view model to configure this controller. + /// - collectionViewHolder: A view that contains collection view. + public init(viewModel: ViewModel, + collectionViewHolder: CollectionViewWrapperView = .init(layout: UICollectionViewFlowLayout())) { + + super.init(viewModel: viewModel, + customView: collectionViewHolder) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + /// Contained UICollectionView instance. + public var collectionView: UICollectionView { + return customView.collectionView + } + +} diff --git a/Sources/Classes/Controllers/BaseConfigurableController.swift b/Sources/Classes/Controllers/BaseConfigurableController.swift index 40934789..cf970f04 100644 --- a/Sources/Classes/Controllers/BaseConfigurableController.swift +++ b/Sources/Classes/Controllers/BaseConfigurableController.swift @@ -25,8 +25,12 @@ import UIKit.UIViewController /// Base controller that can should be configured with view model. open class BaseConfigurableController: UIViewController, ConfigurableController { + /// A view model instance used by this controller. public let viewModel: ViewModel + /// Initializer with view model parameter. + /// + /// - Parameter viewModel: A view model to configure this controller. public init(viewModel: ViewModel) { self.viewModel = viewModel diff --git a/Sources/Classes/Controllers/BaseCustomViewController.swift b/Sources/Classes/Controllers/BaseCustomViewController.swift index aea7e746..674c977a 100644 --- a/Sources/Classes/Controllers/BaseCustomViewController.swift +++ b/Sources/Classes/Controllers/BaseCustomViewController.swift @@ -28,6 +28,11 @@ open class BaseCustomViewController: BaseConfigurableCo /// Contained custom view. public let customView: View + /// Initializer with view model and custom view parameters. + /// + /// - Parameters: + /// - viewModel: A view model to configure this controller. + /// - customView: UIView instance to assign in view property. public init(viewModel: ViewModel, customView: View) { self.customView = customView @@ -39,7 +44,7 @@ open class BaseCustomViewController: BaseConfigurableCo } override open func loadView() { - self.view = customView + view = customView } } diff --git a/Sources/Classes/Controllers/BaseScrollContentController.swift b/Sources/Classes/Controllers/BaseScrollContentController.swift new file mode 100644 index 00000000..b8a97ee4 --- /dev/null +++ b/Sources/Classes/Controllers/BaseScrollContentController.swift @@ -0,0 +1,82 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import RxSwift +import RxCocoa + +public typealias ScrollViewHolderView = UIView & ScrollViewHolder + +/// Base controller configurable with view model and ScrollViewHolder custom view. +open class BaseScrollContentController: BaseCustomViewController { + + private let defaultInsetsRelay = BehaviorRelay(value: .zero) + + private var bottomInsetDisposable: Disposable? + + /// Bind given driver to bottom inset of scroll view. Takes into account default bottom insets. + /// + /// - Parameter bottomInsetDriver: Driver that emits CGFloat bottom inset changes. + public func bindBottomInsetBinding(from bottomInsetDriver: Driver) { + bottomInsetDisposable = bottomInsetDriver + .withLatestFrom(defaultInsetsRelay.asDriver()) { + $0 + $1.bottom + } + .drive(customView.scrollView.rx.bottomInsetBinder) + } + + /// Unbind scroll view from previous binding. + public func unbindBottomInsetBinding() { + bottomInsetDisposable?.dispose() + } + + /// Default insets used for contained scroll view. + public var defaultInsets: UIEdgeInsets { + get { + return defaultInsetsRelay.value + } + set { + defaultInsetsRelay.accept(newValue) + customView.scrollView.contentInset = newValue + customView.scrollView.scrollIndicatorInsets = newValue + } + } + + /// Contained UIScrollView instance. + public var scrollView: UIScrollView { + return customView.scrollView + } + +} + +public extension BaseScrollContentController { + + /// On iOS, tvOS 11+ sets contentInsetAdjustmentBehavior to .never. + /// On earlier versions sets automaticallyAdjustsScrollViewInsets to false. + func disableAdjustsScrollViewInsets() { + if #available(iOS 11.0, tvOS 11.0, *) { + customView.scrollView.contentInsetAdjustmentBehavior = .never + } else { + automaticallyAdjustsScrollViewInsets = false + } + } + +} diff --git a/Sources/Classes/Controllers/BaseTableContentController.swift b/Sources/Classes/Controllers/BaseTableContentController.swift new file mode 100644 index 00000000..72729e49 --- /dev/null +++ b/Sources/Classes/Controllers/BaseTableContentController.swift @@ -0,0 +1,62 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TableKit + +/// Base table controller configurable with view model and TableViewWrapperView as custom view. +open class BaseTableContentController: BaseScrollContentController { + + /// TableDirector binded to table view. + public let tableDirector: TableDirector + + /// Initializer with view model, table view holder and table director parameters. + /// + /// - Parameters: + /// - viewModel: A view model to configure this controller. + /// - tableViewHolder: A view that contains table view. + /// - tableDirector: Custom TableDirector instance or nil to use the default one. + public init(viewModel: ViewModel, + tableViewHolder: TableViewWrapperView = .init(tableViewStyle: .plain), + tableDirector: TableDirector? = nil) { + + self.tableDirector = tableDirector ?? TableDirector(tableView: tableViewHolder.tableView) + + super.init(viewModel: viewModel, + customView: tableViewHolder) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func configureAppearance() { + super.configureAppearance() + + tableView.separatorStyle = .none + } + + /// Contained UITableView instance. + public var tableView: UITableView { + return customView.tableView + } + +} diff --git a/Sources/Classes/Views/CollectionViewWrapperView/CollectionViewWrapperView.swift b/Sources/Classes/Views/CollectionViewWrapperView/CollectionViewWrapperView.swift new file mode 100644 index 00000000..87aaeca2 --- /dev/null +++ b/Sources/Classes/Views/CollectionViewWrapperView/CollectionViewWrapperView.swift @@ -0,0 +1,48 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit + +/// The main purpose of this class is to fix empty space on top of the screen +/// when view controller view is UICollectionView. +open class CollectionViewWrapperView: ScrollViewHolderView, CollectionViewHolder { + + /// Contained collection view. + public let collectionView: UICollectionView + + /// Initializer with collection view layout parameter. + /// + /// - Parameter layout: UICollectionViewLayout to pass in UICollectionView init. + public init(layout: UICollectionViewLayout) { + self.collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + self.collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + super.init(frame: .zero) + + addSubview(collectionView) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/Sources/Classes/Views/TableViewWrapperView/TableViewWrapperView.swift b/Sources/Classes/Views/TableViewWrapperView/TableViewWrapperView.swift new file mode 100644 index 00000000..970ff539 --- /dev/null +++ b/Sources/Classes/Views/TableViewWrapperView/TableViewWrapperView.swift @@ -0,0 +1,48 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit.UITableView + +/// The main purpose of this class is to fix empty space on top of the screen +/// when view controller view is UITableView. +open class TableViewWrapperView: ScrollViewHolderView, TableViewHolder { + + /// Contained table view. + public let tableView: UITableView + + /// Initializer with tableViewStyle parameter. + /// + /// - Parameter tableViewStyle: UITableViewStyle to pass in UITableView init. + public init(tableViewStyle: UITableViewStyle) { + self.tableView = UITableView(frame: .zero, style: tableViewStyle) + self.tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + super.init(frame: .zero) + + addSubview(tableView) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +}