Fixed navigation to detail screen

This commit is contained in:
Selim Mustafaev 2020-04-01 21:29:05 +03:00
parent 9d1efd8d0d
commit 734fbc5bc0
8 changed files with 45 additions and 651 deletions

View File

@ -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 = "<group>"; };
7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCell.swift; sourceTree = "<group>"; };
7A530B7F2401803A00CBFE6E /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = "<group>"; };
7A530B81240180CC00CBFE6E /* RxCollectionViewRealmDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCollectionViewRealmDataSource.swift; sourceTree = "<group>"; };
7A530B82240180CC00CBFE6E /* RealmBindObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealmBindObserver.swift; sourceTree = "<group>"; };
7A530B83240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Reactive+RxRealmDataSources.swift"; sourceTree = "<group>"; };
7A530B84240180CC00CBFE6E /* RxTableViewRealmDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxTableViewRealmDataSource.swift; sourceTree = "<group>"; };
7A6DD902242BF4A5009DE740 /* PlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateView.swift; sourceTree = "<group>"; };
7A6DD90724329144009DE740 /* CenterTextLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterTextLayer.swift; sourceTree = "<group>"; };
7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = RoadNumbers2.0.otf; sourceTree = "<group>"; };
@ -173,7 +165,6 @@
7A11472C23FECA3E00B424AF /* ThirdParty */ = {
isa = PBXGroup;
children = (
7A530B7B24017DED00CBFE6E /* RxRealmDataSources */,
7A6DD90724329144009DE740 /* CenterTextLayer.swift */,
);
path = ThirdParty;
@ -209,17 +200,6 @@
name = Frameworks;
sourceTree = "<group>";
};
7A530B7B24017DED00CBFE6E /* RxRealmDataSources */ = {
isa = PBXGroup;
children = (
7A530B83240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift */,
7A530B82240180CC00CBFE6E /* RealmBindObserver.swift */,
7A530B81240180CC00CBFE6E /* RxCollectionViewRealmDataSource.swift */,
7A530B84240180CC00CBFE6E /* RxTableViewRealmDataSource.swift */,
);
path = RxRealmDataSources;
sourceTree = "<group>";
};
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 */,

View File

@ -280,35 +280,42 @@
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="3ON-lr-UlV" id="IGw-UK-ebp">
<rect key="frame" x="0.0" y="0.0" width="375" height="85"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="prz-7c-HiS">
<rect key="frame" x="8" y="8" width="359" height="69"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Kia (JF) Optima" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h3N-1o-J20">
<rect key="frame" x="0.0" y="0.0" width="124" height="21"/>
<rect key="frame" x="8" y="8" width="124" height="21"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VHX-o0-3BP" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="29" width="359" height="40"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rKr-3e-WYb">
<rect key="frame" x="334" y="8" width="33" height="16"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VHX-o0-3BP" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="8" y="37" width="317" height="40"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="vzo-oF-mWb"/>
</constraints>
</view>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="prz-7c-HiS" secondAttribute="trailing" constant="8" id="42F-cD-DAn"/>
<constraint firstItem="prz-7c-HiS" firstAttribute="top" secondItem="IGw-UK-ebp" secondAttribute="top" constant="8" id="W9V-oe-unX"/>
<constraint firstItem="prz-7c-HiS" firstAttribute="leading" secondItem="IGw-UK-ebp" secondAttribute="leading" constant="8" id="tvA-Ow-u6L"/>
<constraint firstAttribute="bottom" secondItem="prz-7c-HiS" secondAttribute="bottom" constant="8" id="v1W-gU-mvW"/>
<constraint firstAttribute="bottom" secondItem="VHX-o0-3BP" secondAttribute="bottom" constant="8" id="7hb-rB-XFk"/>
<constraint firstItem="rKr-3e-WYb" firstAttribute="top" secondItem="IGw-UK-ebp" secondAttribute="top" constant="8" id="Aae-DJ-RWv"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="VHX-o0-3BP" secondAttribute="trailing" constant="8" id="CNo-ir-xoh"/>
<constraint firstAttribute="trailing" secondItem="rKr-3e-WYb" secondAttribute="trailing" constant="8" id="Efc-w5-0Xo"/>
<constraint firstItem="VHX-o0-3BP" firstAttribute="leading" secondItem="IGw-UK-ebp" secondAttribute="leading" constant="8" id="PgR-8A-drv"/>
<constraint firstItem="VHX-o0-3BP" firstAttribute="top" secondItem="h3N-1o-J20" secondAttribute="bottom" constant="8" id="U0q-5Z-FxE"/>
<constraint firstItem="h3N-1o-J20" firstAttribute="leading" secondItem="IGw-UK-ebp" secondAttribute="leading" constant="8" id="eqF-fX-u0u"/>
<constraint firstItem="rKr-3e-WYb" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="h3N-1o-J20" secondAttribute="trailing" constant="8" id="h98-lu-Lji"/>
<constraint firstItem="h3N-1o-J20" firstAttribute="top" secondItem="IGw-UK-ebp" secondAttribute="top" constant="8" id="yx2-fR-etv"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="date" destination="rKr-3e-WYb" id="TOr-YS-0IE"/>
<outlet property="name" destination="h3N-1o-J20" id="jcM-B4-bEJ"/>
<outlet property="plate" destination="VHX-o0-3BP" id="D8N-L7-O8b"/>
</connections>

View File

@ -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 ?? "<unknown>"
self.plate.number = PlateNumber(vehicle.number)
self.plate.unrecognized = vehicle.brand == nil
self.date.text = formatter.string(from: Date(timeIntervalSince1970: vehicle.addedDate/1000))
}
}

View File

@ -24,11 +24,6 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
self.number.delegate = self.maskFieldDelegate
self.check.isEnabled = false
// let ds = RxTableViewRealmDataSource<Vehicle>(cellIdentifier: "VehicleCell", cellType: VehicleCell.self) { cell, ip, vehicle in
// cell.configure(with: vehicle)
// }
// ds.headerTitle = "History"
let ds = RxTableViewSectionedAnimatedDataSource<DateSection<Vehicle>>(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<Vehicle>) -> [DateSection<Vehicle>] 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)

View File

@ -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<E>(_ dataSource: RxTableViewRealmDataSource<E>)
-> RealmBindObserver<E, AnyRealmCollection<E>, RxTableViewRealmDataSource<E>> {
return RealmBindObserver(dataSource: dataSource) {ds, results, changes in
if ds.tableView == nil {
ds.tableView = self.base
}
ds.tableView?.dataSource = ds
ds.applyChanges(items: AnyRealmCollection<E>(results), changes: changes)
}
}
public func realmModelSelected<E>(_ modelType: E.Type) -> ControlEvent<E> where E: RealmSwift.Object {
let source: Observable<E> = self.itemSelected.flatMap { [weak view = self.base as UITableView] indexPath -> Observable<E> in
guard let view = view, let ds = view.dataSource as? RxTableViewRealmDataSource<E> else {
return Observable.empty()
}
return Observable.just(ds.model(at: indexPath))
}
return ControlEvent(events: source)
}
}
extension Reactive where Base: UICollectionView {
public func realmChanges<E>(_ dataSource: RxCollectionViewRealmDataSource<E>)
-> RealmBindObserver<E, AnyRealmCollection<E>, RxCollectionViewRealmDataSource<E>> {
return RealmBindObserver(dataSource: dataSource) {ds, results, changes in
if ds.collectionView == nil {
ds.collectionView = self.base
}
ds.collectionView?.dataSource = ds
ds.applyChanges(items: AnyRealmCollection<E>(results), changes: changes)
}
}
public func realmModelSelected<E>(_ modelType: E.Type) -> ControlEvent<E> where E: RealmSwift.Object {
let source: Observable<E> = self.itemSelected.flatMap { [weak view = self.base as UICollectionView] indexPath -> Observable<E> in
guard let view = view, let ds = view.dataSource as? RxCollectionViewRealmDataSource<E> 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<E>(_ dataSource: RxTableViewRealmDataSource<E>)
-> RealmBindObserver<E, AnyRealmCollection<E>, RxTableViewRealmDataSource<E>> {
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<E>(results), changes: changes)
}
}
}
extension Reactive where Base: NSCollectionView {
public func realmChanges<E>(_ dataSource: RxCollectionViewRealmDataSource<E>)
-> RealmBindObserver<E, AnyRealmCollection<E>, RxCollectionViewRealmDataSource<E>> {
return RealmBindObserver(dataSource: dataSource) {ds, results, changes in
if ds.collectionView == nil {
ds.collectionView = self.base
}
ds.collectionView?.dataSource = ds
ds.applyChanges(items: AnyRealmCollection<E>(results), changes: changes)
}
}
}
#endif

View File

@ -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<O: Object, C: RealmCollection, DS>: 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<E>) {
switch event {
case .next(let element):
binding(dataSource, element.0, element.1)
case .error:
return
case .completed:
return
}
}
func asObserver() -> AnyObserver<E> {
return AnyObserver(eventHandler: on)
}
}

View File

@ -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<E: Object> = (RxCollectionViewRealmDataSource<E>, UICollectionView, IndexPath, E) -> UICollectionViewCell
public typealias CollectionCellConfig<E: Object, CellType: UICollectionViewCell> = (CellType, IndexPath, E) -> Void
open class RxCollectionViewRealmDataSource <E: Object>: NSObject, UICollectionViewDataSource {
private var items: AnyRealmCollection<E>?
// MARK: - Configuration
public var collectionView: UICollectionView?
public var animated = true
// MARK: - Init
public let cellIdentifier: String
public let cellFactory: CollectionCellFactory<E>
public init(cellIdentifier: String, cellFactory: @escaping CollectionCellFactory<E>) {
self.cellIdentifier = cellIdentifier
self.cellFactory = cellFactory
}
public init<CellType>(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping CollectionCellConfig<E, CellType>) 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<E>, 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<E: Object> = (RxCollectionViewRealmDataSource<E>, NSCollectionView, IndexPath, E) -> NSCollectionViewItem
public typealias CollectionItemConfig<E: Object, ItemType: NSCollectionViewItem> = (ItemType, IndexPath, E) -> Void
open class RxCollectionViewRealmDataSource <E: Object>: NSObject, NSCollectionViewDataSource {
private var items: AnyRealmCollection<E>?
// MARK: - Configuration
public var collectionView: NSCollectionView?
public var animated = true
// MARK: - Init
public let itemIdentifier: String
public let itemFactory: CollectionItemFactory<E>
public weak var delegate: NSCollectionViewDelegate?
public weak var dataSource: NSCollectionViewDataSource?
public init(itemIdentifier: String, itemFactory: @escaping CollectionItemFactory<E>) {
self.itemIdentifier = itemIdentifier
self.itemFactory = itemFactory
}
public init<ItemType>(itemIdentifier: String, itemType: ItemType.Type, itemConfig: @escaping CollectionItemConfig<E, ItemType>) 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<E>, 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

View File

@ -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<E: Object> = (RxTableViewRealmDataSource<E>, UITableView, IndexPath, E) -> UITableViewCell
public typealias TableCellConfig<E: Object, CellType: UITableViewCell> = (CellType, IndexPath, E) -> Void
open class RxTableViewRealmDataSource<E: Object>: NSObject, UITableViewDataSource {
private var items: AnyRealmCollection<E>?
// 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<E>
public init(cellIdentifier: String, cellFactory: @escaping TableCellFactory<E>) {
self.cellIdentifier = cellIdentifier
self.cellFactory = cellFactory
}
public init<CellType>(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping TableCellConfig<E, CellType>) 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<E>, 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<E: Object> = (RxTableViewRealmDataSource<E>, NSTableView, Int, E) -> NSTableCellView
public typealias TableCellConfig<E: Object, CellType: NSTableCellView> = (CellType, Int, E) -> Void
open class RxTableViewRealmDataSource<E: Object>: NSObject, NSTableViewDataSource, NSTableViewDelegate {
private var items: AnyRealmCollection<E>?
// 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<E>
public init(cellIdentifier: String, cellFactory: @escaping TableCellFactory<E>) {
self.cellIdentifier = cellIdentifier
self.cellFactory = cellFactory
}
public init<CellType>(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping TableCellConfig<E, CellType>) 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<E>, 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