diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index b6379277..294ab30d 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -41,10 +41,6 @@ 6714625D1EB3396E00EAB194 /* LogFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461CE1EB3396E00EAB194 /* LogFormatter.swift */; }; 6714625E1EB3396E00EAB194 /* LogFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461CE1EB3396E00EAB194 /* LogFormatter.swift */; }; 6714625F1EB3396E00EAB194 /* LogFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461CE1EB3396E00EAB194 /* LogFormatter.swift */; }; - 671462641EB3396E00EAB194 /* PaginationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D11EB3396E00EAB194 /* PaginationViewModel.swift */; }; - 671462651EB3396E00EAB194 /* PaginationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D11EB3396E00EAB194 /* PaginationViewModel.swift */; }; - 671462661EB3396E00EAB194 /* PaginationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D11EB3396E00EAB194 /* PaginationViewModel.swift */; }; - 671462671EB3396E00EAB194 /* PaginationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D11EB3396E00EAB194 /* PaginationViewModel.swift */; }; 671462681EB3396E00EAB194 /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D31EB3396E00EAB194 /* NetworkService.swift */; }; 671462691EB3396E00EAB194 /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D31EB3396E00EAB194 /* NetworkService.swift */; }; 6714626A1EB3396E00EAB194 /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D31EB3396E00EAB194 /* NetworkService.swift */; }; @@ -512,7 +508,6 @@ 671461CC1EB3396E00EAB194 /* App.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; 671461CD1EB3396E00EAB194 /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; 671461CE1EB3396E00EAB194 /* LogFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogFormatter.swift; sourceTree = ""; }; - 671461D11EB3396E00EAB194 /* PaginationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaginationViewModel.swift; sourceTree = ""; }; 671461D31EB3396E00EAB194 /* NetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; 671461D51EB3396E00EAB194 /* XibView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XibView.swift; sourceTree = ""; }; 671461D71EB3396E00EAB194 /* CursorError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CursorError.swift; sourceTree = ""; }; @@ -771,7 +766,6 @@ isa = PBXGroup; children = ( 6774529E20625EEE0024EEEF /* PaginationDataLoadingModel.swift */, - 671461D11EB3396E00EAB194 /* PaginationViewModel.swift */, 677452AD206274630024EEEF /* PaginationWrapper.swift */, ); path = PaginationDataLoading; @@ -2258,7 +2252,6 @@ 671463101EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, 674AF55C1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift in Sources */, 671463401EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, - 671462641EB3396E00EAB194 /* PaginationViewModel.swift in Sources */, 67A1FF8F1EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */, 671462901EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */, @@ -2403,7 +2396,6 @@ 6714634E1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */, 6714626A1EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463421EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, - 671462661EB3396E00EAB194 /* PaginationViewModel.swift in Sources */, 671462921EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 671463861EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */, 671463921EB3396E00EAB194 /* TemplateDrawingOperation.swift in Sources */, @@ -2485,7 +2477,6 @@ 6714626B1EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463131EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, 671463431EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, - 671462671EB3396E00EAB194 /* PaginationViewModel.swift in Sources */, 671462931EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 67EB7FE720615DE000BDD9FB /* DataSource.swift in Sources */, 671462FF1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */, @@ -2616,7 +2607,6 @@ 671462691EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463111EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, 671463411EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, - 671462651EB3396E00EAB194 /* PaginationViewModel.swift in Sources */, 671462911EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 67051ADC1EBC7C36008EADC0 /* SpinnerView.swift in Sources */, 671462FD1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */, diff --git a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationViewModel.swift b/Sources/Classes/DataLoading/PaginationDataLoading/PaginationViewModel.swift deleted file mode 100644 index 888ccfec..00000000 --- a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationViewModel.swift +++ /dev/null @@ -1,154 +0,0 @@ -// -// Copyright (c) 2017 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 - -/// Class that encapsulate all pagination logic -public final class PaginationViewModel { - - /// Enum contains all possible states for PaginationViewModel class. - /// - /// - initial: initial state of view model. - /// Can occur only once after initial binding. - /// - loading: loading state of view model. Contains previous state of view model. - /// Can occur after any state. - /// - loadingMore: loading more items state of view model. Contains previous state of view model. - /// Can occur after error or results state. - /// - results: results state of view model. Contains loaded items, cursor and previous state of view model. - /// Can occur after loading or loadingMore state. - /// - error: error state of view model. Contains received error and previous state of view model. - /// Can occur after loading or loadingMore state. - /// - empty: empty state of view model. - /// Can occur after loading or loadingMore state when we got empty result (zero items). - /// - exhausted: exhausted state of view model. - /// Can occur after results state or after initial->loading state when cursor reports that it's exhausted. - public indirect enum State { - - case initial - case loading(after: State) - case loadingMore(after: State) - case results(newItems: [C.Element], inCursor: C, after: State) - case error(error: Error, after: State) - case empty - case exhausted - - } - - /// Enum represents possible load types for PaginationViewModel class - /// - /// - reload: reload all items and reset cursor to initial state. - /// - next: load next batch of items. - /// - retry: reload to initial loading state - public enum LoadType { - - case reload - case retry - case next - - } - - private var cursor: C - - private let internalState = Variable(.initial) - - private var currentRequest: Disposable? - - private let internalScheduler = SerialDispatchQueueScheduler(qos: .default) - - /// Current PaginationViewModel state Driver - public var state: Driver { - return internalState.asDriver() - } - - /// Initializer with enclosed cursor - /// - /// - Parameter cursor: cursor to use for pagination - public init(cursor: C) { - self.cursor = cursor - } - - /// Mathod which triggers loading of items. - /// - /// - Parameter loadType: type of loading. See LoadType enum. - public func load(_ loadType: LoadType) { - switch loadType { - case .reload: - reload() - case .retry: - reload(isRetry: true) - case .next: - if case .exhausted = internalState.value { - fatalError("You shouldn't call load(.next) after got .exhausted state!") - } - - internalState.value = .loadingMore(after: internalState.value) - } - - let currentCursor = cursor - - currentRequest = currentCursor.loadNextBatch() - .subscribeOn(internalScheduler) - .subscribe(onSuccess: { [weak self] newItems in - self?.onGot(newItems: newItems, using: currentCursor) - }, onError: { [weak self] error in - self?.onGot(error: error) - }) - } - - private func onGot(newItems: [C.Element], using cursor: C) { - if newItems.isEmpty { - internalState.value = .empty - return - } - - internalState.value = .results(newItems: newItems, inCursor: cursor, after: internalState.value) - - if cursor.exhausted { - internalState.value = .exhausted - } - } - - private func onGot(error: Error) { - if case .exhausted? = error as? CursorError, case .loading(let after) = internalState.value { - switch after { - case .initial, .empty: // cursor exhausted after creation - internalState.value = .empty - default: - internalState.value = .error(error: error, after: internalState.value) - } - } else { - internalState.value = .error(error: error, after: internalState.value) - } - } - - private func reload(isRetry: Bool = false) { - currentRequest?.dispose() - cursor = cursor.reset() - - if isRetry { - internalState.value = .initial - } - internalState.value = .loading(after: internalState.value) - } - -} diff --git a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift b/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift index cf96f09e..8ad40b57 100644 --- a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift +++ b/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift @@ -24,7 +24,7 @@ import RxSwift import RxCocoa import UIScrollView_InfiniteScroll -/// Class that connects PaginationViewModel with UIScrollView. It handles all non-visual and visual states. +/// Class that connects PaginationDataLoadingModel with UIScrollView. It handles all non-visual and visual states. final public class PaginationWrapper // "Segmentation fault: 11" in Xcode 9.2 without redundant same-type constraint :( where Cursor == Delegate.DataSourceType, Cursor.ResultType == [Cursor.Element] {