diff --git a/AutoCat.xcodeproj/project.pbxproj b/AutoCat.xcodeproj/project.pbxproj index 0746564..f93b6da 100644 --- a/AutoCat.xcodeproj/project.pbxproj +++ b/AutoCat.xcodeproj/project.pbxproj @@ -35,10 +35,6 @@ 7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7924001D3300CBFE6E /* CheckController.swift */; }; 7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */; }; 7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7F2401803A00CBFE6E /* Vehicle.swift */; }; - 7A530B85240180CC00CBFE6E /* RxCollectionViewRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B81240180CC00CBFE6E /* RxCollectionViewRealmDataSource.swift */; }; - 7A530B86240180CC00CBFE6E /* RealmBindObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B82240180CC00CBFE6E /* RealmBindObserver.swift */; }; - 7A530B87240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B83240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift */; }; - 7A530B88240180CC00CBFE6E /* RxTableViewRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B84240180CC00CBFE6E /* RxTableViewRealmDataSource.swift */; }; 7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 7A530B8A240181F500CBFE6E /* RxRealm */; }; 7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD902242BF4A5009DE740 /* PlateView.swift */; }; 7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD90724329144009DE740 /* CenterTextLayer.swift */; }; @@ -76,10 +72,6 @@ 7A530B7924001D3300CBFE6E /* CheckController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckController.swift; sourceTree = ""; }; 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCell.swift; sourceTree = ""; }; 7A530B7F2401803A00CBFE6E /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = ""; }; - 7A530B81240180CC00CBFE6E /* RxCollectionViewRealmDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCollectionViewRealmDataSource.swift; sourceTree = ""; }; - 7A530B82240180CC00CBFE6E /* RealmBindObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealmBindObserver.swift; sourceTree = ""; }; - 7A530B83240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Reactive+RxRealmDataSources.swift"; sourceTree = ""; }; - 7A530B84240180CC00CBFE6E /* RxTableViewRealmDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxTableViewRealmDataSource.swift; sourceTree = ""; }; 7A6DD902242BF4A5009DE740 /* PlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateView.swift; sourceTree = ""; }; 7A6DD90724329144009DE740 /* CenterTextLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterTextLayer.swift; sourceTree = ""; }; 7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = RoadNumbers2.0.otf; sourceTree = ""; }; @@ -173,7 +165,6 @@ 7A11472C23FECA3E00B424AF /* ThirdParty */ = { isa = PBXGroup; children = ( - 7A530B7B24017DED00CBFE6E /* RxRealmDataSources */, 7A6DD90724329144009DE740 /* CenterTextLayer.swift */, ); path = ThirdParty; @@ -209,17 +200,6 @@ name = Frameworks; sourceTree = ""; }; - 7A530B7B24017DED00CBFE6E /* RxRealmDataSources */ = { - isa = PBXGroup; - children = ( - 7A530B83240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift */, - 7A530B82240180CC00CBFE6E /* RealmBindObserver.swift */, - 7A530B81240180CC00CBFE6E /* RxCollectionViewRealmDataSource.swift */, - 7A530B84240180CC00CBFE6E /* RxTableViewRealmDataSource.swift */, - ); - path = RxRealmDataSources; - sourceTree = ""; - }; 7A530B7C24017FBE00CBFE6E /* Cells */ = { isa = PBXGroup; children = ( @@ -375,7 +355,6 @@ files = ( 7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */, 7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */, - 7A530B86240180CC00CBFE6E /* RealmBindObserver.swift in Sources */, 7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */, 7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */, 7A6DD90E24337930009DE740 /* PlateNumber.swift in Sources */, @@ -387,14 +366,11 @@ 7A7547DD2403180A004E8406 /* SectionHeader.swift in Sources */, 7AF58D58240309CA00CE01A0 /* VehicleTextParamCell.swift in Sources */, 7A11474723FF2AA500B424AF /* User.swift in Sources */, - 7A530B88240180CC00CBFE6E /* RxTableViewRealmDataSource.swift in Sources */, 7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */, 7AF58D3124029E1000CE01A0 /* VehicleHeaderCell.swift in Sources */, 7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */, - 7A530B85240180CC00CBFE6E /* RxCollectionViewRealmDataSource.swift in Sources */, 7A11470323FDE7E500B424AF /* SceneDelegate.swift in Sources */, 7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */, - 7A530B87240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift in Sources */, 7A11474423FF06CA00B424AF /* Api.swift in Sources */, 7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */, 7A11474B23FF368B00B424AF /* Settings.swift in Sources */, diff --git a/AutoCat/Base.lproj/Main.storyboard b/AutoCat/Base.lproj/Main.storyboard index f9b2f1b..fe8f6fe 100644 --- a/AutoCat/Base.lproj/Main.storyboard +++ b/AutoCat/Base.lproj/Main.storyboard @@ -281,34 +281,41 @@ - - - - - - - - - - - - - + + + + + + + + + - - - - + + + + + + + + + + diff --git a/AutoCat/Cells/VehicleCell.swift b/AutoCat/Cells/VehicleCell.swift index 2c86064..9cf1799 100644 --- a/AutoCat/Cells/VehicleCell.swift +++ b/AutoCat/Cells/VehicleCell.swift @@ -4,16 +4,22 @@ class VehicleCell: UITableViewCell { @IBOutlet weak var name: UILabel! @IBOutlet weak var plate: PlateView! + @IBOutlet weak var date: UILabel! + + let formatter = DateFormatter() override func awakeFromNib() { super.awakeFromNib() + formatter.dateStyle = .short + formatter.timeStyle = .short } func configure(with vehicle: Vehicle) { self.name.text = vehicle.brand?.name?.original ?? "" self.plate.number = PlateNumber(vehicle.number) self.plate.unrecognized = vehicle.brand == nil + self.date.text = formatter.string(from: Date(timeIntervalSince1970: vehicle.addedDate/1000)) } } diff --git a/AutoCat/Controllers/CheckController.swift b/AutoCat/Controllers/CheckController.swift index c6fd399..af3a4d2 100644 --- a/AutoCat/Controllers/CheckController.swift +++ b/AutoCat/Controllers/CheckController.swift @@ -24,11 +24,6 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener { self.number.delegate = self.maskFieldDelegate self.check.isEnabled = false -// let ds = RxTableViewRealmDataSource(cellIdentifier: "VehicleCell", cellType: VehicleCell.self) { cell, ip, vehicle in -// cell.configure(with: vehicle) -// } -// ds.headerTitle = "History" - let ds = RxTableViewSectionedAnimatedDataSource>(configureCell: { dataSource, tableView, indexPath, item in if let cell = tableView.dequeueReusableCell(withIdentifier: "VehicleCell", for: indexPath) as? VehicleCell { cell.configure(with: item) @@ -42,24 +37,13 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener { return dataSourse.sectionModels[index].header } - let realm = try! Realm() -// Observable.changeset(from: realm.objects(Vehicle.self).sorted(byKeyPath: "addedDate", ascending: false)) -// .bind(to: self.history.rx.realmChanges(ds)) -// .disposed(by: self.bag) - - self.history.rx.realmModelSelected(Vehicle.self) + self.history.rx.modelSelected(Vehicle.self) .subscribe(onNext: self.updateDetailController(with:)) .disposed(by: self.bag) let now = Date() let monthStart = now.dateAtStartOf(.month) - let weekStart = now.dateAtStartOf(.weekOfMonth) - - print("==================================") - print("now: \(now)") - print("week start: \(weekStart)") - print("month start: \(monthStart)") - print("==================================") + let realm = try! Realm() Observable.collection(from: realm.objects(Vehicle.self).sorted(byKeyPath: "addedDate", ascending: false)).map { (vehicles: Results) -> [DateSection] in var sections: [TimeInterval: [Vehicle]] = [:] @@ -94,6 +78,13 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener { self.navigationController?.setNavigationBarHidden(true, animated: false) } + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + if let index = self.history.indexPathForSelectedRow { + self.history.deselectRow(at: index, animated: true) + } + } + @IBAction func checkTapped(_ sender: UIButton) { guard let number = self.number.text else { return } @@ -101,6 +92,7 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener { self.number.resignFirstResponder() self.number.text = nil + self.check.isEnabled = false SVProgressHUD.show() Api.checkVehicle(by: numberNormalized) .observeOn(MainScheduler.instance) diff --git a/AutoCat/ThirdParty/RxRealmDataSources/Reactive+RxRealmDataSources.swift b/AutoCat/ThirdParty/RxRealmDataSources/Reactive+RxRealmDataSources.swift deleted file mode 100644 index c51ca48..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/Reactive+RxRealmDataSources.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -#if os(iOS) -// MARK: - iOS / UIKit - -import UIKit -extension Reactive where Base: UITableView { - - public func realmChanges(_ dataSource: RxTableViewRealmDataSource) - -> RealmBindObserver, RxTableViewRealmDataSource> { - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if ds.tableView == nil { - ds.tableView = self.base - } - ds.tableView?.dataSource = ds - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } - - public func realmModelSelected(_ modelType: E.Type) -> ControlEvent where E: RealmSwift.Object { - - let source: Observable = self.itemSelected.flatMap { [weak view = self.base as UITableView] indexPath -> Observable in - guard let view = view, let ds = view.dataSource as? RxTableViewRealmDataSource else { - return Observable.empty() - } - - return Observable.just(ds.model(at: indexPath)) - } - - return ControlEvent(events: source) - } - -} - -extension Reactive where Base: UICollectionView { - - public func realmChanges(_ dataSource: RxCollectionViewRealmDataSource) - -> RealmBindObserver, RxCollectionViewRealmDataSource> { - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if ds.collectionView == nil { - ds.collectionView = self.base - } - ds.collectionView?.dataSource = ds - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } - - public func realmModelSelected(_ modelType: E.Type) -> ControlEvent where E: RealmSwift.Object { - - let source: Observable = self.itemSelected.flatMap { [weak view = self.base as UICollectionView] indexPath -> Observable in - guard let view = view, let ds = view.dataSource as? RxCollectionViewRealmDataSource else { - return Observable.empty() - } - - return Observable.just(ds.model(at: indexPath)) - } - - return ControlEvent(events: source) - } -} - - -#elseif os(OSX) -// MARK: - macOS / Cocoa - -import Cocoa -extension Reactive where Base: NSTableView { - - public func realmChanges(_ dataSource: RxTableViewRealmDataSource) - -> RealmBindObserver, RxTableViewRealmDataSource> { - - base.delegate = dataSource - base.dataSource = dataSource - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if dataSource.tableView == nil { - dataSource.tableView = self.base - } - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } -} - -extension Reactive where Base: NSCollectionView { - - public func realmChanges(_ dataSource: RxCollectionViewRealmDataSource) - -> RealmBindObserver, RxCollectionViewRealmDataSource> { - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if ds.collectionView == nil { - ds.collectionView = self.base - } - ds.collectionView?.dataSource = ds - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } -} - -#endif diff --git a/AutoCat/ThirdParty/RxRealmDataSources/RealmBindObserver.swift b/AutoCat/ThirdParty/RxRealmDataSources/RealmBindObserver.swift deleted file mode 100644 index a60b378..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/RealmBindObserver.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -public class RealmBindObserver: ObserverType { - typealias BindingType = (DS, C, RealmChangeset?) -> Void - public typealias E = (C, RealmChangeset?) - - let dataSource: DS - let binding: BindingType - - init(dataSource: DS, binding: @escaping BindingType) { - self.dataSource = dataSource - self.binding = binding - } - - public func on(_ event: Event) { - switch event { - case .next(let element): - binding(dataSource, element.0, element.1) - case .error: - return - case .completed: - return - } - } - - func asObserver() -> AnyObserver { - return AnyObserver(eventHandler: on) - } -} diff --git a/AutoCat/ThirdParty/RxRealmDataSources/RxCollectionViewRealmDataSource.swift b/AutoCat/ThirdParty/RxRealmDataSources/RxCollectionViewRealmDataSource.swift deleted file mode 100644 index 8883732..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/RxCollectionViewRealmDataSource.swift +++ /dev/null @@ -1,210 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -#if os(iOS) - // MARK: - iOS / UIKit - - import UIKit - - public typealias CollectionCellFactory = (RxCollectionViewRealmDataSource, UICollectionView, IndexPath, E) -> UICollectionViewCell - public typealias CollectionCellConfig = (CellType, IndexPath, E) -> Void - - open class RxCollectionViewRealmDataSource : NSObject, UICollectionViewDataSource { - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var collectionView: UICollectionView? - public var animated = true - - // MARK: - Init - public let cellIdentifier: String - public let cellFactory: CollectionCellFactory - - public init(cellIdentifier: String, cellFactory: @escaping CollectionCellFactory) { - self.cellIdentifier = cellIdentifier - self.cellFactory = cellFactory - } - - public init(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping CollectionCellConfig) where CellType: UICollectionViewCell { - self.cellIdentifier = cellIdentifier - self.cellFactory = {ds, cv, ip, model in - let cell = cv.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: ip) as! CellType - cellConfig(cell, ip, model) - return cell - } - } - - // MARK: - Data access - public func model(at indexPath: IndexPath) -> E { - return items![indexPath.row] - } - - // MARK: - UICollectionViewDataSource protocol - public func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return items?.count ?? 0 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - return cellFactory(self, collectionView, indexPath, items![indexPath.row]) - } - - // MARK: - Applying changeset to the collection view - private let fromRow = {(row: Int) in return IndexPath(row: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let collectionView = collectionView else { - fatalError("You have to bind a collection view to the data source.") - } - - guard animated else { - collectionView.reloadData() - return - } - - guard let changes = changes else { - collectionView.reloadData() - return - } - - let lastItemCount = collectionView.numberOfItems(inSection: 0) - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - collectionView.reloadData() - return - } - - collectionView.performBatchUpdates({[unowned self] in - collectionView.deleteItems(at: changes.deleted.map(self.fromRow)) - collectionView.reloadItems(at: changes.updated.map(self.fromRow)) - collectionView.insertItems(at: changes.inserted.map(self.fromRow)) - }, completion: nil) - } -} - -#elseif os(OSX) -// MARK: - macOS / Cocoa - -import Cocoa - - public typealias CollectionItemFactory = (RxCollectionViewRealmDataSource, NSCollectionView, IndexPath, E) -> NSCollectionViewItem - public typealias CollectionItemConfig = (ItemType, IndexPath, E) -> Void - - open class RxCollectionViewRealmDataSource : NSObject, NSCollectionViewDataSource { - - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var collectionView: NSCollectionView? - public var animated = true - - // MARK: - Init - public let itemIdentifier: String - public let itemFactory: CollectionItemFactory - - public weak var delegate: NSCollectionViewDelegate? - public weak var dataSource: NSCollectionViewDataSource? - - public init(itemIdentifier: String, itemFactory: @escaping CollectionItemFactory) { - self.itemIdentifier = itemIdentifier - self.itemFactory = itemFactory - } - - public init(itemIdentifier: String, itemType: ItemType.Type, itemConfig: @escaping CollectionItemConfig) where ItemType: NSCollectionViewItem { - self.itemIdentifier = itemIdentifier - self.itemFactory = { ds, cv, ip, model in - let item = cv.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: itemIdentifier), for: ip) as! ItemType - itemConfig(item, ip, model) - return item - } - } - - // MARK: - NSCollectionViewDataSource protocol - public func numberOfSections(in collectionView: NSCollectionView) -> Int { - return 1 - } - - public func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { - return items?.count ?? 0 - } - - @available(OSX 10.11, *) - public func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { - return itemFactory(self, collectionView, indexPath, items![indexPath.item]) - } - - // MARK: - Proxy unimplemented data source and delegate methods - open override func responds(to aSelector: Selector!) -> Bool { - if RxCollectionViewRealmDataSource.instancesRespond(to: aSelector) { - return true - } else if let delegate = delegate { - return delegate.responds(to: aSelector) - } else if let dataSource = dataSource { - return dataSource.responds(to: aSelector) - } else { - return false - } - } - - open override func forwardingTarget(for aSelector: Selector!) -> Any? { - return delegate ?? dataSource - } - - // MARK: - Applying changeset to the collection view - private let fromRow = {(row: Int) in return IndexPath(item: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let collectionView = collectionView else { - fatalError("You have to bind a collection view to the data source.") - } - - guard animated else { - collectionView.reloadData() - return - } - - guard let changes = changes else { - collectionView.reloadData() - return - } - - let lastItemCount = collectionView.numberOfItems(inSection: 0) - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - collectionView.reloadData() - return - } - - collectionView.performBatchUpdates({[unowned self] in - //TODO: this should be animated, but doesn't seem to be? - collectionView.animator().deleteItems(at: Set(changes.deleted.map(self.fromRow))) - collectionView.animator().reloadItems(at: Set(changes.updated.map(self.fromRow))) - collectionView.animator().insertItems(at: Set(changes.inserted.map(self.fromRow))) - }, completionHandler: nil) - } - } - - -#endif diff --git a/AutoCat/ThirdParty/RxRealmDataSources/RxTableViewRealmDataSource.swift b/AutoCat/ThirdParty/RxRealmDataSources/RxTableViewRealmDataSource.swift deleted file mode 100644 index c80bb80..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/RxTableViewRealmDataSource.swift +++ /dev/null @@ -1,223 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -#if os(iOS) - // MARK: - iOS / UIKit - - import UIKit - - public typealias TableCellFactory = (RxTableViewRealmDataSource, UITableView, IndexPath, E) -> UITableViewCell - public typealias TableCellConfig = (CellType, IndexPath, E) -> Void - - open class RxTableViewRealmDataSource: NSObject, UITableViewDataSource { - - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var tableView: UITableView? - public var animated = true - public var rowAnimations = ( - insert: UITableView.RowAnimation.automatic, - update: UITableView.RowAnimation.automatic, - delete: UITableView.RowAnimation.automatic) - - public var headerTitle: String? - public var footerTitle: String? - - // MARK: - Init - public let cellIdentifier: String - public let cellFactory: TableCellFactory - - public init(cellIdentifier: String, cellFactory: @escaping TableCellFactory) { - self.cellIdentifier = cellIdentifier - self.cellFactory = cellFactory - } - - public init(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping TableCellConfig) where CellType: UITableViewCell { - self.cellIdentifier = cellIdentifier - self.cellFactory = {ds, tv, ip, model in - let cell = tv.dequeueReusableCell(withIdentifier: cellIdentifier, for: ip) as! CellType - cellConfig(cell, ip, model) - return cell - } - } - - // MARK: - Data access - public func model(at indexPath: IndexPath) -> E { - return items![indexPath.row] - } - - // MARK: - UITableViewDataSource protocol - public func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return items?.count ?? 0 - } - - public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return cellFactory(self, tableView, indexPath, items![indexPath.row]) - } - - public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return headerTitle - } - - public func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return footerTitle - } - - // MARK: - Applying changeset to the table view - private let fromRow = {(row: Int) in return IndexPath(row: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let tableView = tableView else { - fatalError("You have to bind a table view to the data source.") - } - - guard animated else { - tableView.reloadData() - return - } - - guard let changes = changes else { - tableView.reloadData() - return - } - - let lastItemCount = tableView.numberOfRows(inSection: 0) - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - tableView.reloadData() - return - } - - tableView.beginUpdates() - tableView.deleteRows(at: changes.deleted.map(fromRow), with: rowAnimations.delete) - tableView.insertRows(at: changes.inserted.map(fromRow), with: rowAnimations.insert) - tableView.reloadRows(at: changes.updated.map(fromRow), with: rowAnimations.update) - tableView.endUpdates() - } - } - -#elseif os(OSX) - // MARK: - macOS / Cocoa - - import Cocoa - - public typealias TableCellFactory = (RxTableViewRealmDataSource, NSTableView, Int, E) -> NSTableCellView - public typealias TableCellConfig = (CellType, Int, E) -> Void - - open class RxTableViewRealmDataSource: NSObject, NSTableViewDataSource, NSTableViewDelegate { - - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var tableView: NSTableView? - public var animated = true - public var rowAnimations = ( - insert: NSTableView.AnimationOptions.effectFade, - update: NSTableView.AnimationOptions.effectFade, - delete: NSTableView.AnimationOptions.effectFade) - - public weak var delegate: NSTableViewDelegate? - public weak var dataSource: NSTableViewDataSource? - - // MARK: - Init - public let cellIdentifier: String - public let cellFactory: TableCellFactory - - public init(cellIdentifier: String, cellFactory: @escaping TableCellFactory) { - self.cellIdentifier = cellIdentifier - self.cellFactory = cellFactory - } - - public init(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping TableCellConfig) where CellType: NSTableCellView { - self.cellIdentifier = cellIdentifier - self.cellFactory = { ds, tv, row, model in - let cell = tv.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: tv) as! CellType - cellConfig(cell, row, model) - return cell - } - } - - // MARK: - UITableViewDataSource protocol - public func numberOfRows(in tableView: NSTableView) -> Int { - return items?.count ?? 0 - } - - public func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - return cellFactory(self, tableView, row, items![row]) - } - - // MARK: - Proxy unimplemented data source and delegate methods - open override func responds(to aSelector: Selector!) -> Bool { - if RxTableViewRealmDataSource.instancesRespond(to: aSelector) { - return true - } else if let delegate = delegate { - return delegate.responds(to: aSelector) - } else if let dataSource = dataSource { - return dataSource.responds(to: aSelector) - } else { - return false - } - } - - open override func forwardingTarget(for aSelector: Selector!) -> Any? { - return delegate ?? dataSource - } - - // MARK: - Applying changeset to the table view - private let fromRow = {(row: Int) in return IndexPath(item: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let tableView = tableView else { - fatalError("You have to bind a table view to the data source.") - } - - guard animated else { - tableView.reloadData() - return - } - - guard let changes = changes else { - tableView.reloadData() - return - } - - let lastItemCount = tableView.numberOfRows - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - tableView.reloadData() - return - } - - tableView.beginUpdates() - tableView.removeRows(at: IndexSet(changes.deleted), withAnimation: rowAnimations.delete) - tableView.insertRows(at: IndexSet(changes.inserted), withAnimation: rowAnimations.insert) - tableView.reloadData(forRowIndexes: IndexSet(changes.updated), columnIndexes: IndexSet([0])) - tableView.endUpdates() - } - } - -#endif