AutoCat/AutoCat/Utils/RxSectionedDataSource.swift

89 lines
2.9 KiB
Swift

import UIKit
import DifferenceKit
import RxSwift
import RxCocoa
class RxSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource where Item: Dated & Hashable & Differentiable & Decodable, Cell: UITableViewCell & ConfigurableCell, Cell.Item == Item {
private var tv: UITableView
private var cellIdentifier: String
private var sections: [DateSection<Item>] = []
private var items: [Item] = []
private var sortParam: SortParameter = .updatedDate
private(set) var pageToken: String? = nil
private(set) var count: Int? = nil
init(table: UITableView, cellIdentifier: String = String(describing: Cell.self)) {
self.tv = table
self.cellIdentifier = cellIdentifier
super.init()
self.tv.dataSource = self
}
// MARK: - UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.sections[section].elements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: indexPath) as? Cell else {
return UITableViewCell()
}
let item = self.sections[indexPath.section].elements[indexPath.row]
cell.configure(with: item)
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section].header
}
// MARK: - Public
func item(at indexPath: IndexPath) -> Item {
return self.sections[indexPath.section].elements[indexPath.row]
}
func set(item: Item, at indexPath: IndexPath) {
self.sections[indexPath.section].elements[indexPath.row] = item
}
var data: Binder<PagedResponse<Item>> {
return Binder(self) { datasource, data in
if let count = data.count {
self.count = count
self.items = data.items
} else {
self.items.append(contentsOf: data.items)
}
self.pageToken = data.pageToken
let newSections = self.items.groupedByDate(type: self.sortParam)
let changeset = StagedChangeset(source: self.sections, target: newSections)
self.tv.reload(using: changeset, with: .automatic) { newSects in
self.sections = newSects
}
}
}
func needMoreData() -> Bool {
guard let count = self.count else { return true }
return self.items.count < count
}
func reset() {
self.pageToken = nil
self.count = nil
self.items = []
}
func setSortParameter(_ param: SortParameter) {
self.sortParam = param
}
}