Merge pull request #82 from TouchInstinct/fix/paginationWrapper

Fix/pagination wrapper
This commit is contained in:
Ivan Zinovyev 2017-09-08 12:22:24 +03:00 committed by GitHub
commit 0fb3261f7a
5 changed files with 52 additions and 20 deletions

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "LeadKit"
s.version = "0.5.4"
s.version = "0.5.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

@ -142,6 +142,11 @@ where Delegate.Cursor == Cursor {
paginationViewModel.load(.reload)
}
/// Method acts like reload, but shows initial loading view after being invoked.
public func retry() {
paginationViewModel.load(.retry)
}
/// Method that enables placeholders animation due pull-to-refresh interaction.
///
/// - Parameter scrollObservable: Observable that emits content offset as CGPoint.
@ -204,7 +209,9 @@ where Delegate.Cursor == Cursor {
tableView.support.refreshControl?.endRefreshing()
addInfiniteScroll()
if !(cursor is SingleLoadCursor<Cursor.Element>) {
addInfiniteScroll()
}
} else if case .loadingMore = afterState {
delegate?.paginationWrapper(wrapper: self, didLoad: newItems, usingCursor: cursor)
@ -214,15 +221,15 @@ where Delegate.Cursor == Cursor {
private func onErrorState(error: Error, afterState: PaginationViewModel<Cursor>.State) {
if case .loading = afterState {
enterPlaceholderState()
defer {
tableView.support.refreshControl?.endRefreshing()
}
guard let errorView = delegate?.errorPlaceholder(forPaginationWrapper: self, forError: error) else {
return
}
preparePlaceholderView(errorView)
currentPlaceholderView = errorView
replacePlaceholderViewIfNeeded(with: errorView)
} else if case .loadingMore = afterState {
removeInfiniteScroll()
@ -244,15 +251,23 @@ where Delegate.Cursor == Cursor {
}
private func onEmptyState() {
enterPlaceholderState()
defer {
tableView.support.refreshControl?.endRefreshing()
}
guard let emptyView = delegate?.emptyPlaceholder(forPaginationWrapper: self) else {
return
}
replacePlaceholderViewIfNeeded(with: emptyView)
}
preparePlaceholderView(emptyView)
currentPlaceholderView = emptyView
private func replacePlaceholderViewIfNeeded(with view: UIView) {
// don't update placeholder view if previous placeholder is the same one
if currentPlaceholderView === view {
return
}
enterPlaceholderState()
preparePlaceholderView(view)
currentPlaceholderView = view
}
// MARK: - private stuff
@ -322,7 +337,6 @@ where Delegate.Cursor == Cursor {
}
private func enterPlaceholderState() {
tableView.support.refreshControl?.endRefreshing()
tableView.isUserInteractionEnabled = true
removeCurrentPlaceholderView()

View File

@ -63,7 +63,11 @@ public final class PaginationViewModel<C: ResettableCursorType> {
/// - next: load next batch of items.
public enum LoadType {
/// pull-to-refresh
case reload
/// retry button inside placeholder
case retry
case next
}
@ -94,10 +98,9 @@ public final class PaginationViewModel<C: ResettableCursorType> {
public func load(_ loadType: LoadType) {
switch loadType {
case .reload:
currentRequest?.dispose()
cursor = cursor.reset()
internalState.value = .loading(after: internalState.value)
reload()
case .retry:
reload(isRetry: true)
case .next:
if case .exhausted(_) = internalState.value {
fatalError("You shouldn't call load(.next) after got .exhausted state!")
@ -118,6 +121,11 @@ public final class PaginationViewModel<C: ResettableCursorType> {
}
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 {
@ -138,4 +146,14 @@ public final class PaginationViewModel<C: ResettableCursorType> {
}
}
private func reload(isRetry: Bool = false) {
currentRequest?.dispose()
cursor = cursor.reset()
if isRetry {
internalState.value = .initial
}
internalState.value = .loading(after: internalState.value)
}
}

View File

@ -31,8 +31,8 @@ public struct AnyLoadingIndicator: Animatable {
/// Initializer with indicator that should be wrapped.
///
/// - Parameter _: indicator for wrapping.
public init<Indicator> (_ base: Indicator) where Indicator: LoadingIndicator {
self.internalView = base.view
public init<Indicator> (_ base: Indicator, backgroundView: UIView? = nil) where Indicator: LoadingIndicator {
self.internalView = backgroundView ?? base.view
self.animatableView = base.view
}

View File

@ -94,9 +94,9 @@ class CursorTests: XCTestCase {
XCTAssertEqual(loadedItems.count, 40)
cursorExpectation.fulfill()
}) { error in
}, onError: { error in
XCTFail(error.localizedDescription)
}
})
.addDisposableTo(disposeBag)
waitForExpectations(timeout: 10, handler: nil)