//
|
// RefreshModel.swift
|
// WanPai
|
//
|
// Created by 无故事王国 on 2023/7/11.
|
//
|
|
import UIKit
|
import MJRefresh
|
import RxSwift
|
import HandyJSON
|
import RxRelay
|
|
|
enum RefreshState {
|
case refreshing
|
case completedRefresh
|
case moreLoading
|
case completedLoad
|
case completedLoadWithNoMoreData
|
}
|
|
protocol RefreshModelProctol {
|
associatedtype T:HandyJSON
|
func api()->(Observable<BaseResponse<[T]>>)?
|
}
|
protocol RefreshModelInnerProctol {
|
associatedtype T:HandyJSON
|
func api()->(Observable<BaseResponse<BaseResponseList<T>>>)?
|
}
|
|
|
class RefreshModel<T:HandyJSON>:RefreshModelProctol{
|
func api() -> (RxSwift.Observable<BaseResponse<[T]>>)? {return nil}
|
let disposeBag = DisposeBag()
|
enum RefreshType {case refresh,load}
|
|
private var handle:UIScrollView!
|
|
lazy var refreshSubject = PublishSubject<RefreshState>()
|
var page:Int = 1
|
var pageSize:Int = 20
|
private var needRefreshData:Bool = true
|
lazy var dataSource = BehaviorRelay<[T]>(value: [])
|
|
func configure(_ scrollView:UITableView,needMore:Bool = true){
|
scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData())
|
if needMore{
|
scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData())
|
}
|
refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag)
|
handle = scrollView
|
}
|
|
func configure(_ scrollView:UICollectionView,needMore:Bool = true,needRefreshData:Bool = true){
|
self.needRefreshData = needRefreshData
|
scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData())
|
if needMore{
|
scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData())
|
}
|
refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag)
|
handle = scrollView
|
}
|
|
func beginRefresh(){
|
guard handle != nil else {return}
|
page = 1
|
api()?.subscribe(onNext: { data in
|
if let datas = data.data{
|
self.dataSource.accept(datas)
|
self.refreshSubject.onNext(.completedRefresh)
|
}
|
}).disposed(by: disposeBag)
|
}
|
|
func refreshData() ->(()->Void) {
|
return {self.request(status: .refresh)}
|
}
|
|
func loadMoreData() ->(()->Void) {
|
return {self.request(status: .load)}
|
}
|
|
func request(status:RefreshType){
|
switch status {
|
case .refresh:
|
self.page = 1
|
self.refreshSubject.onNext(.refreshing)
|
case .load:
|
self.page += 1
|
self.refreshSubject.onNext(.moreLoading)
|
}
|
|
api()?.subscribe(onNext: { data in
|
if let datas = data.data{
|
switch status{
|
case .refresh:
|
self.dataSource.accept(datas)
|
self.refreshSubject.onNext(.completedRefresh)
|
case .load:
|
self.dataSource.accept(self.dataSource.value + datas)
|
if datas.count == 0{
|
self.refreshSubject.onNext(.completedLoadWithNoMoreData)
|
}else{
|
self.refreshSubject.onNext(.completedLoad)
|
}
|
}
|
}else{
|
self.refreshSubject.onNext(.completedLoadWithNoMoreData)
|
}
|
}, onError: { error in
|
self.refreshSubject.onNext(.completedLoad)
|
|
}).disposed(by: disposeBag)
|
}
|
}
|
|
|
class RefreshInnerModel<T:HandyJSON>:RefreshModelInnerProctol{
|
func api() -> (RxSwift.Observable<BaseResponse<BaseResponseList<T>>>)? {
|
return nil
|
}
|
|
let disposeBag = DisposeBag()
|
enum RefreshType {case refresh,load}
|
|
private var handle:UIScrollView!
|
|
lazy var refreshSubject = PublishSubject<RefreshState>()
|
var page:Int = 0
|
var pageSize:Int = 20
|
private var needRefreshData:Bool = true
|
lazy var dataSource = BehaviorRelay<BaseResponseList<T>?>(value: nil)
|
|
func configure(_ scrollView:UITableView,needMore:Bool = true){
|
scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData())
|
if needMore{
|
scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData())
|
}
|
refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag)
|
handle = scrollView
|
}
|
|
func configure(_ scrollView:UICollectionView,needMore:Bool = true,needRefreshData:Bool = true){
|
self.needRefreshData = needRefreshData
|
scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData())
|
if needMore{
|
scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData())
|
}
|
refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag)
|
handle = scrollView
|
}
|
|
func beginRefresh(){
|
handle.mj_header?.beginRefreshing()
|
}
|
|
func refreshData() ->(()->Void) {
|
return {self.request(status: .refresh)}
|
}
|
|
func loadMoreData() ->(()->Void) {
|
return {self.request(status: .load)}
|
}
|
|
func request(status:RefreshType){
|
switch status {
|
case .refresh:
|
self.page = 1
|
self.refreshSubject.onNext(.refreshing)
|
case .load:
|
self.page += 1
|
self.refreshSubject.onNext(.moreLoading)
|
}
|
|
api()?.subscribe(onNext: { data in
|
switch status{
|
case .refresh:
|
self.dataSource.accept(data.data)
|
self.refreshSubject.onNext(.completedRefresh)
|
case .load:
|
var new = self.dataSource.value?.list ?? []
|
new.append(contentsOf: data.data?.list ?? [])
|
var model = self.dataSource.value
|
model!.list = new
|
self.dataSource.accept(model)
|
if data.data?.list.count == 0{
|
self.refreshSubject.onNext(.completedLoadWithNoMoreData)
|
}else{
|
self.refreshSubject.onNext(.completedLoad)
|
}
|
}
|
}, onError: { error in
|
self.refreshSubject.onNext(.completedLoad)
|
|
}).disposed(by: disposeBag)
|
}
|
|
|
}
|
|
class CustomRefreshHeaer:MJRefreshNormalHeader{
|
static func refreshing(with refreshingBlock: @escaping MJRefreshComponentAction) -> MJRefreshNormalHeader? {
|
let refreshHeader = MJRefreshNormalHeader(refreshingBlock: refreshingBlock)
|
return refreshHeader
|
}
|
}
|
|
class CustomRefreshFooter:MJRefreshAutoNormalFooter{
|
static func refreshing(with refreshingBlock: @escaping MJRefreshComponentAction) -> MJRefreshAutoNormalFooter? {
|
let refrehFooter = MJRefreshAutoNormalFooter(refreshingBlock: refreshingBlock)
|
refrehFooter.isRefreshingTitleHidden = true
|
refrehFooter.stateLabel?.isHidden = true
|
return refrehFooter
|
}
|
}
|
|
extension Reactive where Base : UITableView {
|
|
func handlestatus() -> Binder<RefreshState> {
|
return Binder(self.base) { (tableView, status) in
|
switch status {
|
case .moreLoading:
|
self.base.mj_footer?.beginRefreshing()
|
case .refreshing:
|
self.base.reloadData()
|
self.base.mj_footer?.resetNoMoreData()
|
self.base.mj_header?.beginRefreshing()
|
|
case .completedLoadWithNoMoreData:
|
DispatchQueue.main.async {
|
self.base.reloadData()
|
}
|
(self.base.mj_footer as? MJRefreshAutoNormalFooter)?.stateLabel?.isHidden = false
|
self.base.mj_footer?.endRefreshingWithNoMoreData()
|
self.base.mj_header?.endRefreshing()
|
case .completedLoad:
|
DispatchQueue.main.async {
|
self.base.reloadData()
|
}
|
self.base.mj_footer?.endRefreshing()
|
self.base.mj_header?.endRefreshing()
|
default:
|
DispatchQueue.main.async {
|
self.base.reloadData()
|
}
|
self.base.mj_header?.endRefreshing()
|
self.base.mj_footer?.endRefreshing()
|
}
|
}
|
}
|
}
|
|
extension Reactive where Base : UICollectionView {
|
|
func handlestatus() -> Binder<RefreshState> {
|
return Binder(self.base) { (tableView, status) in
|
switch status {
|
case .moreLoading:
|
self.base.mj_footer?.beginRefreshing()
|
case .refreshing:
|
self.base.reloadData()
|
self.base.mj_footer?.resetNoMoreData()
|
self.base.mj_header?.endRefreshing()
|
|
case .completedLoadWithNoMoreData:
|
DispatchQueue.main.async {
|
self.base.reloadData()
|
}
|
self.base.mj_footer?.endRefreshingWithNoMoreData()
|
case .completedLoad:
|
DispatchQueue.main.async {
|
self.base.reloadData()
|
}
|
self.base.mj_footer?.endRefreshing()
|
default:
|
DispatchQueue.main.async {
|
self.base.reloadData()
|
}
|
self.base.mj_header?.endRefreshing()
|
self.base.mj_footer?.endRefreshing()
|
}
|
}
|
}
|
}
|