add base table & collection view controllers

This commit is contained in:
Ivan Smolin 2018-07-25 12:10:04 +03:00
parent a20aa5affa
commit e11b129a75
9 changed files with 359 additions and 4 deletions

View File

@ -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/*",

View File

@ -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 = "<group>"; };
6741CECD20E243F800FEC4D9 /* BaseConfigurableController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseConfigurableController.swift; sourceTree = "<group>"; };
674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+LoadingIndicator.swift"; sourceTree = "<group>"; };
675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseScrollContentController.swift; sourceTree = "<group>"; };
6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableSection+Extensions.swift"; sourceTree = "<group>"; };
676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = "<group>"; };
67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+PaginationWrappable.swift"; sourceTree = "<group>"; };
@ -828,6 +843,10 @@
67C7B1782068BB1C00C9EDA3 /* NumberFormattingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormattingService.swift; sourceTree = "<group>"; };
67CAF8AB2065189C00527085 /* NetworkService+ActivityIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkService+ActivityIndicator.swift"; sourceTree = "<group>"; };
67CAF8C520652E2A00527085 /* TextFieldViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldViewModel.swift; sourceTree = "<group>"; };
67DB775F210869D1001CB56B /* TableViewWrapperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewWrapperView.swift; sourceTree = "<group>"; };
67DB776321086A12001CB56B /* BaseTableContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableContentController.swift; sourceTree = "<group>"; };
67DB776821087154001CB56B /* CollectionViewWrapperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewWrapperView.swift; sourceTree = "<group>"; };
67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCollectionContentController.swift; sourceTree = "<group>"; };
67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleLoadCursor.swift; sourceTree = "<group>"; };
67EB7FBF206140E600BDD9FB /* TotalCountCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursor.swift; sourceTree = "<group>"; };
67EB7FC6206148D000BDD9FB /* TotalCountCursorListingResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursorListingResult.swift; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -1765,6 +1789,22 @@
path = NumberFormattingService;
sourceTree = "<group>";
};
67DB775E210869C7001CB56B /* TableViewWrapperView */ = {
isa = PBXGroup;
children = (
67DB775F210869D1001CB56B /* TableViewWrapperView.swift */,
);
path = TableViewWrapperView;
sourceTree = "<group>";
};
67DB77672108714A001CB56B /* CollectionViewWrapperView */ = {
isa = PBXGroup;
children = (
67DB776821087154001CB56B /* CollectionViewWrapperView.swift */,
);
path = CollectionViewWrapperView;
sourceTree = "<group>";
};
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 */,

View File

@ -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<ViewModel>: BaseScrollContentController<ViewModel, CollectionViewWrapperView> {
/// 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
}
}

View File

@ -25,8 +25,12 @@ import UIKit.UIViewController
/// Base controller that can should be configured with view model.
open class BaseConfigurableController<ViewModel>: 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

View File

@ -28,6 +28,11 @@ open class BaseCustomViewController<ViewModel, View: UIView>: 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<ViewModel, View: UIView>: BaseConfigurableCo
}
override open func loadView() {
self.view = customView
view = customView
}
}

View File

@ -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<ViewModel, View: ScrollViewHolderView>: BaseCustomViewController<ViewModel, View> {
private let defaultInsetsRelay = BehaviorRelay<UIEdgeInsets>(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<CGFloat>) {
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
}
}
}

View File

@ -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<ViewModel>: BaseScrollContentController<ViewModel, TableViewWrapperView> {
/// 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
}
}

View File

@ -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")
}
}

View File

@ -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")
}
}