Diffable datasource in check history list
This commit is contained in:
parent
9959fbc854
commit
6d0fb32fa7
@ -25,7 +25,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
|
||||
let config = Realm.Configuration(
|
||||
schemaVersion: 27,
|
||||
schemaVersion: 28,
|
||||
migrationBlock: { migration, oldSchemaVersion in
|
||||
if oldSchemaVersion <= 3 {
|
||||
var numbers: [String] = []
|
||||
|
||||
@ -18,7 +18,7 @@ extension AudioRecord: Dated {
|
||||
}
|
||||
}
|
||||
|
||||
extension RandomAccessCollection where Element: Dated & Equatable & Differentiable {
|
||||
extension RandomAccessCollection where Element: Dated & Hashable & Differentiable {
|
||||
func groupedByDate() -> [DateSection<Element>] {
|
||||
let now = Date()
|
||||
let monthStart = now.dateAtStartOf(.month)
|
||||
|
||||
@ -2,7 +2,7 @@ import Foundation
|
||||
import SwiftDate
|
||||
import DifferenceKit
|
||||
|
||||
struct DateSection<T>: Differentiable, DifferentiableSection where T: Differentiable {
|
||||
struct DateSection<T>: Differentiable, DifferentiableSection, Hashable where T: Differentiable & Hashable {
|
||||
|
||||
var timestamp: Double = 0
|
||||
var header: String
|
||||
@ -59,4 +59,15 @@ struct DateSection<T>: Differentiable, DifferentiableSection where T: Differenti
|
||||
func isContentEqual(to source: DateSection<T>) -> Bool {
|
||||
return self.differenceIdentifier == source.differenceIdentifier
|
||||
}
|
||||
|
||||
// MARK: - Hasable
|
||||
|
||||
static func == (lhs: DateSection<T>, rhs: DateSection<T>) -> Bool {
|
||||
return lhs.timestamp == rhs.timestamp && lhs.elements == rhs.elements
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(self.timestamp)
|
||||
hasher.combine(self.elements)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import RealmSwift
|
||||
|
||||
class VehicleAd: Object, Decodable {
|
||||
@objc dynamic var id: Int = 0
|
||||
@objc dynamic var url: String = ""
|
||||
@objc dynamic var url: String?
|
||||
@objc dynamic var price: String?
|
||||
@objc dynamic var date: TimeInterval = Date().timeIntervalSince1970
|
||||
@objc dynamic var mileage: String?
|
||||
|
||||
@ -3,7 +3,13 @@ import RealmSwift
|
||||
import DifferenceKit
|
||||
import ExceptionCatcher
|
||||
|
||||
class RealmSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource where Item: Object & Identifiable & Dated & Differentiable, Cell: UITableViewCell & ConfigurableCell, Cell.Item == Item {
|
||||
class RealmDiffableDataSourse<Item>: UITableViewDiffableDataSource<DateSection<Item>, Item> where Item: Hashable & ContentEquatable & ContentIdentifiable {
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return snapshot().sectionIdentifiers[section].header
|
||||
}
|
||||
}
|
||||
|
||||
class RealmSectionedDataSource<Item,Cell> where Item: Object & Identifiable & Dated & Differentiable, Cell: UITableViewCell & ConfigurableCell, Cell.Item == Item {
|
||||
|
||||
private var tv: UITableView
|
||||
private var data: Results<Item>
|
||||
@ -11,97 +17,31 @@ class RealmSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource where
|
||||
private var sections: [DateSection<Item>] = []
|
||||
private var cellIdentifier: String
|
||||
private var lastUpdateTime = Date()
|
||||
private var dataSource: RealmDiffableDataSourse<Item>!
|
||||
|
||||
init(table: UITableView, data: Results<Item>, cellIdentifier: String = String(describing: Cell.self)) {
|
||||
self.tv = table
|
||||
self.data = data
|
||||
self.cellIdentifier = cellIdentifier
|
||||
super.init()
|
||||
self.tv.dataSource = self
|
||||
|
||||
self.dataSource = RealmDiffableDataSourse<Item>(tableView: table) { tv, ip, model -> UITableViewCell? in
|
||||
let cell = tv.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: ip) as? Cell
|
||||
cell?.configure(with: model)
|
||||
return cell
|
||||
}
|
||||
self.tv.dataSource = self.dataSource
|
||||
|
||||
self.notificationToken = self.data.observe { changes in
|
||||
switch changes {
|
||||
case .initial:
|
||||
self.sections = self.data.groupedByDate()
|
||||
self.tv.reloadData()
|
||||
case .update(_, let deletions, let insertions, let modifications):
|
||||
if !Calendar.current.isDateInToday(self.lastUpdateTime) {
|
||||
self.sections = self.data.groupedByDate()
|
||||
self.tv.reloadData()
|
||||
return
|
||||
}
|
||||
|
||||
var actions = "Deletions: \(deletions), Insertions: \(insertions), Modifications: \(modifications)"
|
||||
let newSections = self.data.groupedByDate()
|
||||
let changeset = StagedChangeset(source: self.sections, target: newSections, section: 0)
|
||||
|
||||
do {
|
||||
try ExceptionCatcher.catch {
|
||||
self.tv.beginUpdates()
|
||||
self.tv.deleteRows(at: deletions.map(self.indexPath), with: .automatic)
|
||||
self.sections = self.data.groupedByDate()
|
||||
self.tv.insertRows(at: insertions.map(self.indexPath), with: .automatic)
|
||||
self.tv.reloadRows(at: modifications.map(self.indexPath), with: .automatic)
|
||||
|
||||
actions += "\n" + "Changesets count: \(changeset.count)"
|
||||
if let firstChangeset = changeset.first {
|
||||
actions += "\n" + "Deletions: \(firstChangeset.elementDeleted.map { $0.element })"
|
||||
actions += "\n" + "Insertions: \(firstChangeset.elementInserted.map { $0.element })"
|
||||
self.tv.deleteSections(IndexSet(firstChangeset.elementDeleted.map { $0.element }), with: .automatic)
|
||||
self.tv.insertSections(IndexSet(firstChangeset.elementInserted.map { $0.element }), with: .automatic)
|
||||
}
|
||||
self.tv.endUpdates()
|
||||
}
|
||||
} catch {
|
||||
let msg = error.localizedDescription + "\n\n" + actions
|
||||
let alert = UIAlertController(title: "Error", message: msg, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
||||
self.tv.window?.rootViewController?.present(alert, animated: true)
|
||||
}
|
||||
self.reload(animated: false)
|
||||
case .update(_, _, _, _):
|
||||
self.reload(animated: true)
|
||||
case .error(let err):
|
||||
print("Realm observer error: \(err)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Here I assume that sections keep order of elements the same as in initial flat collection
|
||||
// Otherwise it will not work properly
|
||||
func indexPath(by index: Int) -> IndexPath {
|
||||
var sectionStartIndex = 0
|
||||
for (i, section) in self.sections.enumerated() {
|
||||
if index < sectionStartIndex + section.elements.count {
|
||||
return IndexPath(row: index - sectionStartIndex, section: i)
|
||||
}
|
||||
|
||||
sectionStartIndex += section.elements.count
|
||||
}
|
||||
|
||||
return IndexPath(row: 0, section: 0)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@ -109,8 +49,13 @@ class RealmSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource where
|
||||
return self.sections[indexPath.section].elements[indexPath.row]
|
||||
}
|
||||
|
||||
func reload() {
|
||||
func reload(animated: Bool = true) {
|
||||
self.sections = self.data.groupedByDate()
|
||||
self.tv.reloadData()
|
||||
var snapshot = NSDiffableDataSourceSnapshot<DateSection<Item>, Item>()
|
||||
snapshot.appendSections(self.sections)
|
||||
for section in self.sections {
|
||||
snapshot.appendItems(section.elements, toSection: section)
|
||||
}
|
||||
self.dataSource.apply(snapshot, animatingDifferences: animated, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import DifferenceKit
|
||||
import RxSwift
|
||||
import RxCocoa
|
||||
|
||||
class RxSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource where Item: Dated & Equatable & Differentiable, Cell: UITableViewCell & ConfigurableCell, Cell.Item == Item {
|
||||
class RxSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource where Item: Dated & Hashable & Differentiable, Cell: UITableViewCell & ConfigurableCell, Cell.Item == Item {
|
||||
private var tv: UITableView
|
||||
private var cellIdentifier: String
|
||||
private var sections: [DateSection<Item>] = []
|
||||
|
||||
Loading…
Reference in New Issue
Block a user