Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hlung/8e4aa6439ac29577edf1fbeb580e9f3d to your computer and use it in GitHub Desktop.
Save hlung/8e4aa6439ac29577edf1fbeb580e9f3d to your computer and use it in GitHub Desktop.
import Foundation
import RxSwift
import RxCocoa
class SimplifiedPagedResponseFetcher<LoaderInput, LoaderOutput>
where LoaderInput: Pageable, LoaderOutput: PagedResponse {
/// The main actor here 🤘. Sends all the Elements currently available.
let elementsRelay = BehaviorRelay<[LoaderOutput.Element]>(value: [])
lazy var elements: Driver<[LoaderOutput.Element]> = { return elementsRelay.asDriver() }()
// MARK: - Reload
/// Sends true during reload
let isReloadingRelay = BehaviorRelay<Bool>(value: false)
lazy var isReloading: Driver<Bool> = { return isReloadingRelay.asDriver() }()
/// Sends error from last reload
let reloadErrorRelay = BehaviorRelay<Error?>(value: nil)
lazy var reloadError: Driver<Error?> = { return reloadErrorRelay.asDriver() }()
// MARK: - Load more
/// Sends true during loadMore
let isLoadingMoreRelay = BehaviorRelay<Bool>(value: false)
lazy var isLoadingMore: Driver<Bool> = { return isLoadingMoreRelay.asDriver() }()
/// Sends error from last loadMore
let loadMoreErrorRelay = BehaviorRelay<Error?>(value: nil)
lazy var loadMoreError: Driver<Error?> = { return loadMoreErrorRelay.asDriver() }()
// MARK: - Other
/// Sends true when there is more elements to load
let hasMoreRelay = BehaviorRelay<Bool>(value: false)
lazy var hasMore: Driver<Bool> = { return hasMoreRelay.asDriver() }()
private var lastOutputNextCursor: String?
private let loader: (LoaderInput) -> Single<LoaderOutput>
let disposeBag = DisposeBag()
init(loader: @escaping (LoaderInput) -> Single<LoaderOutput>) {
self.loader = loader
}
func reload(_ input: LoaderInput) {
guard isReloadingRelay.value == false else { return }
isReloadingRelay.accept(true)
loader(input)
.subscribe(
onSuccess: { [weak self] (output) in
guard let weakSelf = self else { return }
weakSelf.lastOutputNextCursor = output.pageInfo.nextCursor
weakSelf.hasMoreRelay.accept(output.pageInfo.hasNextPage)
weakSelf.reloadErrorRelay.accept(nil)
let newElements = output.elements
weakSelf.elementsRelay.accept(newElements)
weakSelf.isReloadingRelay.accept(false)
}, onError: { [weak self] (error) in
guard let weakSelf = self else { return }
weakSelf.reloadErrorRelay.accept(error as Error?)
weakSelf.isReloadingRelay.accept(false)
})
.disposed(by: disposeBag)
}
func loadMore(_ input: LoaderInput) {
guard isLoadingMoreRelay.value == false && hasMoreRelay.value == true else { return }
isLoadingMoreRelay.accept(true)
loader(input)
.subscribe(
onSuccess: { [weak self] (output) in
guard let weakSelf = self else { return }
weakSelf.lastOutputNextCursor = output.pageInfo.nextCursor
weakSelf.hasMoreRelay.accept(output.pageInfo.hasNextPage)
weakSelf.loadMoreErrorRelay.accept(nil)
let newElements = output.elements
let oldElements = weakSelf.elementsRelay.value
weakSelf.elementsRelay.accept(oldElements + newElements)
weakSelf.isLoadingMoreRelay.accept(false)
}, onError: { [weak self] (error) in
guard let weakSelf = self else { return }
weakSelf.loadMoreErrorRelay.accept(error as Error?)
weakSelf.isLoadingMoreRelay.accept(false)
})
.disposed(by: disposeBag)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment