Merge pull request #154 from TouchInstinct/feature/RxNetworkOperationModel_update

small changes in RxNetworkOperationModel
This commit is contained in:
Ivan Smolin 2018-07-03 16:27:48 +03:00 committed by GitHub
commit d31ec29152
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 116 additions and 19 deletions

View File

@ -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`.

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -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() {

View File

@ -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) {

View File

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