Add: replaceDataSource method to RxNetworkOperationModel.
Add: customErrorHandler constructor parameter to RxNetworkOperationModel and it heirs.
This commit is contained in:
parent
14f6a9e6cc
commit
12b4efe6a9
|
|
@ -1,5 +1,10 @@
|
|||
# Changelog
|
||||
|
||||
### 0.8.5
|
||||
|
||||
- **Add**: `replaceDataSource` method to `RxNetworkOperationModel`.
|
||||
- **Add**: `customErrorHandler` constructor parameter to `RxNetworkOperationModel` and it heirs.
|
||||
|
||||
### 0.8.4
|
||||
|
||||
- **Fix**: Add `SeparatorCell` to `Core-iOS-Extension`.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "LeadKit"
|
||||
s.version = "0.8.4"
|
||||
s.version = "0.8.5"
|
||||
s.summary = "iOS framework with a bunch of tools for rapid development"
|
||||
s.homepage = "https://github.com/TouchInstinct/LeadKit"
|
||||
s.license = "Apache License, Version 2.0"
|
||||
|
|
|
|||
|
|
@ -356,6 +356,10 @@
|
|||
673CF4392063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673CF4372063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift */; };
|
||||
673CF43A2063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673CF4372063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift */; };
|
||||
673CF43B2063E80B00C329F6 /* GeneralDataLoadingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673CF4172063D50700C329F6 /* GeneralDataLoadingController.swift */; };
|
||||
6741C40F20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741C40E20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift */; };
|
||||
6741C41020EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741C40E20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift */; };
|
||||
6741C41120EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741C40E20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift */; };
|
||||
6741C41220EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741C40E20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift */; };
|
||||
674AF55C1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */; };
|
||||
674AF55D1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */; };
|
||||
674AF55E1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */; };
|
||||
|
|
@ -737,6 +741,7 @@
|
|||
673CF42B2063DE5900C329F6 /* TextPlaceholderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextPlaceholderView.swift; sourceTree = "<group>"; };
|
||||
673CF4332063E29B00C329F6 /* TextWithButtonPlaceholder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextWithButtonPlaceholder.swift; sourceTree = "<group>"; };
|
||||
673CF4372063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GeneralDataLoadingController+DefaultImplementation.swift"; sourceTree = "<group>"; };
|
||||
6741C40E20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GeneralDataLoadingViewModel+Extensions.swift"; sourceTree = "<group>"; };
|
||||
674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+LoadingIndicator.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>"; };
|
||||
|
|
@ -1426,6 +1431,7 @@
|
|||
children = (
|
||||
673CF4372063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift */,
|
||||
673CF4102063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift */,
|
||||
6741C40E20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift */,
|
||||
);
|
||||
path = GeneralDataLoading;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -2651,6 +2657,7 @@
|
|||
671463A21EB33FF600EAB194 /* Animatable.swift in Sources */,
|
||||
677452A9206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */,
|
||||
671462501EB3396E00EAB194 /* StaticCursor.swift in Sources */,
|
||||
6741C40F20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */,
|
||||
67EB7FC7206148D000BDD9FB /* TotalCountCursorListingResult.swift in Sources */,
|
||||
67745286206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */,
|
||||
67955D52206D216B0021ECD2 /* Singleton.swift in Sources */,
|
||||
|
|
@ -2713,6 +2720,7 @@
|
|||
673CF4132063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */,
|
||||
6713C24320AF189100875921 /* RxNetworkOperationModel.swift in Sources */,
|
||||
671462921EB3396E00EAB194 /* CGImage+Crop.swift in Sources */,
|
||||
6741C41120EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */,
|
||||
671463861EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */,
|
||||
671463921EB3396E00EAB194 /* TemplateDrawingOperation.swift in Sources */,
|
||||
67745282206256A20024EEEF /* RxDataLoadingModel.swift in Sources */,
|
||||
|
|
@ -2800,6 +2808,7 @@
|
|||
67ED2BE120B44DEB00508B3E /* InitializableView.swift in Sources */,
|
||||
67274775206CCF1200725163 /* ViewText.swift in Sources */,
|
||||
6727476B206CCCA500725163 /* ViewBackground.swift in Sources */,
|
||||
6741C41220EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */,
|
||||
671462831EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */,
|
||||
67ED2BE820B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */,
|
||||
677452B820627FE00024EEEF /* PaginationWrappable.swift in Sources */,
|
||||
|
|
@ -3014,6 +3023,7 @@
|
|||
67FD4383206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */,
|
||||
671463811EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */,
|
||||
67EB7FDB20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */,
|
||||
6741C41020EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */,
|
||||
A6F32C0A1F6EBE5B00AC08EE /* String+LocalizedComponent.swift in Sources */,
|
||||
671463291EB3396E00EAB194 /* BaseViewModel.swift in Sources */,
|
||||
671462AD1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -39,11 +39,15 @@ open class GeneralDataLoadingViewModel<ResultType>: BaseViewModel {
|
|||
///
|
||||
/// - Parameters:
|
||||
/// - dataSource: A single element sequence.
|
||||
/// - customErrorHandler: Custom error handler for state update. Pass nil for default error handling.
|
||||
/// - emptyResultChecker: Closure for checking result on empty state.
|
||||
public init(dataSource: DataSourceType,
|
||||
customErrorHandler: LoadingModel.ErrorHandler? = nil,
|
||||
emptyResultChecker: @escaping LoadingModel.EmptyResultChecker = { _ in false }) {
|
||||
|
||||
loadingModel = LoadingModel(dataSource: dataSource, emptyResultChecker: emptyResultChecker)
|
||||
loadingModel = LoadingModel(dataSource: dataSource,
|
||||
customErrorHandler: customErrorHandler,
|
||||
emptyResultChecker: emptyResultChecker)
|
||||
|
||||
loadingModel.stateDriver
|
||||
.drive(loadingStateRelay)
|
||||
|
|
@ -52,7 +56,12 @@ open class GeneralDataLoadingViewModel<ResultType>: BaseViewModel {
|
|||
loadingModel.reload()
|
||||
}
|
||||
|
||||
/// Returns driver that emits current loading state
|
||||
/// Returns observable that emits current loading state.
|
||||
open var loadingStateObservable: Observable<LoadingState> {
|
||||
return loadingStateRelay.asObservable()
|
||||
}
|
||||
|
||||
/// Returns driver that emits current loading state.
|
||||
open var loadingStateDriver: Driver<LoadingState> {
|
||||
return loadingStateRelay.asDriver()
|
||||
}
|
||||
|
|
@ -85,17 +94,16 @@ open class GeneralDataLoadingViewModel<ResultType>: BaseViewModel {
|
|||
currentLoadingState = newState
|
||||
}
|
||||
|
||||
/// Replaces current data source of loading model with new one.
|
||||
///
|
||||
/// - Parameter dataSource: A single element sequence.
|
||||
public func replaceDataSource(with newDataSource: DataSourceType) {
|
||||
loadingModel.replaceDataSource(with: newDataSource)
|
||||
}
|
||||
|
||||
/// Reload data.
|
||||
public func reload() {
|
||||
loadingModel.reload()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension GeneralDataLoadingViewModel where ResultType: Collection {
|
||||
|
||||
convenience init(dataSource: DataSourceType) {
|
||||
self.init(dataSource: dataSource) { $0.isEmpty }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,19 @@ public final class PaginationDataLoadingModel<Cursor: ResettableRxDataSourceCurs
|
|||
|
||||
public typealias PaginationEmptyResultChecker = (Cursor.ResultType) -> Bool
|
||||
|
||||
public override init(dataSource: Cursor, emptyResultChecker: @escaping PaginationEmptyResultChecker) {
|
||||
super.init(dataSource: dataSource, emptyResultChecker: emptyResultChecker)
|
||||
/// Model initializer with cursor, empty result checker and custom error handler.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - dataSource: Data source cursor for paginated data loading.
|
||||
/// - customErrorHandler: Custom error handler for state update. Pass nil for default error handling.
|
||||
/// - emptyResultChecker: Empty result checker closure.
|
||||
public override init(dataSource: Cursor,
|
||||
customErrorHandler: ErrorHandler? = nil,
|
||||
emptyResultChecker: @escaping PaginationEmptyResultChecker) {
|
||||
|
||||
super.init(dataSource: dataSource,
|
||||
customErrorHandler: customErrorHandler,
|
||||
emptyResultChecker: emptyResultChecker)
|
||||
}
|
||||
|
||||
override open func reload() {
|
||||
|
|
@ -61,7 +72,7 @@ public final class PaginationDataLoadingModel<Cursor: ResettableRxDataSourceCurs
|
|||
|
||||
switch loadType {
|
||||
case .reload, .retry:
|
||||
dataSource = dataSource.reset()
|
||||
replaceDataSource(with: dataSource.reset())
|
||||
|
||||
if loadType == .retry {
|
||||
state = .initial
|
||||
|
|
|
|||
|
|
@ -30,10 +30,19 @@ open class RxDataLoadingModel<LoadingStateType: DataLoadingState>: RxNetworkOper
|
|||
|
||||
let emptyResultChecker: EmptyResultChecker
|
||||
|
||||
public init(dataSource: DataSourceType, emptyResultChecker: @escaping EmptyResultChecker) {
|
||||
/// Model initializer with data source, empty result checker and custom error handler.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - dataSource: Data source for data loading.
|
||||
/// - customErrorHandler: Custom error handler for state update. Pass nil for default error handling.
|
||||
/// - emptyResultChecker: Empty result checker closure.
|
||||
public init(dataSource: DataSourceType,
|
||||
customErrorHandler: ErrorHandler? = nil,
|
||||
emptyResultChecker: @escaping EmptyResultChecker) {
|
||||
|
||||
self.emptyResultChecker = emptyResultChecker
|
||||
|
||||
super.init(dataSource: dataSource)
|
||||
super.init(dataSource: dataSource, customErrorHandler: customErrorHandler)
|
||||
}
|
||||
|
||||
open func reload() {
|
||||
|
|
|
|||
|
|
@ -29,16 +29,26 @@ open class RxNetworkOperationModel<LoadingStateType: NetworkOperationState>: Net
|
|||
public typealias DataSourceType = LoadingStateType.DataSourceType
|
||||
public typealias ResultType = DataSourceType.ResultType
|
||||
|
||||
public typealias ErrorHandler = (Error, LoadingStateType) -> LoadingStateType
|
||||
|
||||
private let stateRelay = BehaviorRelay<LoadingStateType>(value: .initialState)
|
||||
var currentRequestDisposable: Disposable?
|
||||
|
||||
var dataSource: DataSourceType
|
||||
private(set) var dataSource: DataSourceType
|
||||
|
||||
private let errorHandler: ErrorHandler
|
||||
|
||||
open var stateDriver: Driver<LoadingStateType> {
|
||||
return stateRelay.asDriver()
|
||||
}
|
||||
|
||||
public init(dataSource: DataSourceType) {
|
||||
/// Model initializer with data source and custom error handler.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - dataSource: Data source for network operation.
|
||||
/// - customErrorHandler: Custom error handler for state update. Pass nil for default error handling.
|
||||
public init(dataSource: DataSourceType, customErrorHandler: ErrorHandler? = nil) {
|
||||
self.errorHandler = customErrorHandler ?? { .errorState(error: $0, after: $1) }
|
||||
self.dataSource = dataSource
|
||||
}
|
||||
|
||||
|
|
@ -51,8 +61,15 @@ open class RxNetworkOperationModel<LoadingStateType: NetworkOperationState>: Net
|
|||
requestResult(from: dataSource)
|
||||
}
|
||||
|
||||
/// Replaces current data source with new one.
|
||||
///
|
||||
/// - Parameter newDataSource: A new data source to use.
|
||||
public func replaceDataSource(with newDataSource: DataSourceType) {
|
||||
dataSource = newDataSource
|
||||
}
|
||||
|
||||
func onGot(error: Error) {
|
||||
state = .errorState(error: error, after: state)
|
||||
state = errorHandler(error, state)
|
||||
}
|
||||
|
||||
func onGot(result: ResultType, from dataSource: DataSourceType) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
public extension GeneralDataLoadingViewModel {
|
||||
|
||||
func updateResultManually(to newResult: ResultType) {
|
||||
updateStateManually(to: .result(newResult: newResult, from: .just(newResult)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension GeneralDataLoadingViewModel where ResultType: Collection {
|
||||
|
||||
convenience init(dataSource: DataSourceType) {
|
||||
self.init(dataSource: dataSource) { $0.isEmpty }
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue