Grouping history by dates

This commit is contained in:
Selim Mustafaev 2020-03-18 01:29:39 +03:00
parent 8e04a446d2
commit efafeb6cb0
6 changed files with 149 additions and 10 deletions

View File

@ -7,6 +7,10 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
7A051611241412CA00FC55AC /* SwiftDate in Frameworks */ = {isa = PBXBuildFile; productRef = 7A051610241412CA00FC55AC /* SwiftDate */; };
7A0516162414EC1200FC55AC /* Differentiator in Frameworks */ = {isa = PBXBuildFile; productRef = 7A0516152414EC1200FC55AC /* Differentiator */; };
7A0516182414EC1200FC55AC /* RxDataSources in Frameworks */ = {isa = PBXBuildFile; productRef = 7A0516172414EC1200FC55AC /* RxDataSources */; };
7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0516192414FF0900FC55AC /* DateSection.swift */; };
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11470023FDE7E500B424AF /* AppDelegate.swift */; }; 7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11470023FDE7E500B424AF /* AppDelegate.swift */; };
7A11470323FDE7E500B424AF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11470223FDE7E500B424AF /* SceneDelegate.swift */; }; 7A11470323FDE7E500B424AF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11470223FDE7E500B424AF /* SceneDelegate.swift */; };
7A11470823FDE7E500B424AF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470623FDE7E500B424AF /* Main.storyboard */; }; 7A11470823FDE7E500B424AF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470623FDE7E500B424AF /* Main.storyboard */; };
@ -48,6 +52,7 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
7A0516192414FF0900FC55AC /* DateSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSection.swift; sourceTree = "<group>"; };
7A1146FD23FDE7E500B424AF /* AutoCat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoCat.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7A1146FD23FDE7E500B424AF /* AutoCat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoCat.app; sourceTree = BUILT_PRODUCTS_DIR; };
7A11470023FDE7E500B424AF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 7A11470023FDE7E500B424AF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7A11470223FDE7E500B424AF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; }; 7A11470223FDE7E500B424AF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
@ -85,9 +90,12 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
7AF58D342402A91C00CE01A0 /* Kingfisher in Frameworks */, 7AF58D342402A91C00CE01A0 /* Kingfisher in Frameworks */,
7A0516162414EC1200FC55AC /* Differentiator in Frameworks */,
7A11472823FEA1F400B424AF /* RealmSwift in Frameworks */, 7A11472823FEA1F400B424AF /* RealmSwift in Frameworks */,
7A11472123FEA18700B424AF /* RxCocoa in Frameworks */, 7A11472123FEA18700B424AF /* RxCocoa in Frameworks */,
7A11474E23FFEE8800B424AF /* SVProgressHUD.framework in Frameworks */, 7A11474E23FFEE8800B424AF /* SVProgressHUD.framework in Frameworks */,
7A0516182414EC1200FC55AC /* RxDataSources in Frameworks */,
7A051611241412CA00FC55AC /* SwiftDate in Frameworks */,
7A11472323FEA18700B424AF /* RxBlocking in Frameworks */, 7A11472323FEA18700B424AF /* RxBlocking in Frameworks */,
7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */, 7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */,
7A11472B23FEA24D00B424AF /* Action in Frameworks */, 7A11472B23FEA24D00B424AF /* Action in Frameworks */,
@ -173,6 +181,7 @@
7A11474823FF2B2D00B424AF /* Response.swift */, 7A11474823FF2B2D00B424AF /* Response.swift */,
7A11474A23FF368B00B424AF /* Settings.swift */, 7A11474A23FF368B00B424AF /* Settings.swift */,
7A530B7F2401803A00CBFE6E /* Vehicle.swift */, 7A530B7F2401803A00CBFE6E /* Vehicle.swift */,
7A0516192414FF0900FC55AC /* DateSection.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -239,6 +248,9 @@
7A530B8A240181F500CBFE6E /* RxRealm */, 7A530B8A240181F500CBFE6E /* RxRealm */,
7AF58D2E24029C5200CE01A0 /* MagazineLayout */, 7AF58D2E24029C5200CE01A0 /* MagazineLayout */,
7AF58D332402A91C00CE01A0 /* Kingfisher */, 7AF58D332402A91C00CE01A0 /* Kingfisher */,
7A051610241412CA00FC55AC /* SwiftDate */,
7A0516152414EC1200FC55AC /* Differentiator */,
7A0516172414EC1200FC55AC /* RxDataSources */,
); );
productName = AutoCat; productName = AutoCat;
productReference = 7A1146FD23FDE7E500B424AF /* AutoCat.app */; productReference = 7A1146FD23FDE7E500B424AF /* AutoCat.app */;
@ -276,6 +288,8 @@
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */, 7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */,
7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */, 7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */,
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */, 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */,
7A0516142414EC1200FC55AC /* XCRemoteSwiftPackageReference "RxDataSources" */,
); );
productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */; productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -346,6 +360,7 @@
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */, 7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */,
7A530B87240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift in Sources */, 7A530B87240180CC00CBFE6E /* Reactive+RxRealmDataSources.swift in Sources */,
7A11474423FF06CA00B424AF /* Api.swift in Sources */, 7A11474423FF06CA00B424AF /* Api.swift in Sources */,
7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */,
7A11474B23FF368B00B424AF /* Settings.swift in Sources */, 7A11474B23FF368B00B424AF /* Settings.swift in Sources */,
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */, 7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
); );
@ -559,6 +574,22 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/malcommac/SwiftDate.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 6.1.0;
};
};
7A0516142414EC1200FC55AC /* XCRemoteSwiftPackageReference "RxDataSources" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/RxSwiftCommunity/RxDataSources";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.0.1;
};
};
7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */ = { 7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ReactiveX/RxSwift.git"; repositoryURL = "https://github.com/ReactiveX/RxSwift.git";
@ -618,6 +649,21 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
7A051610241412CA00FC55AC /* SwiftDate */ = {
isa = XCSwiftPackageProductDependency;
package = 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */;
productName = SwiftDate;
};
7A0516152414EC1200FC55AC /* Differentiator */ = {
isa = XCSwiftPackageProductDependency;
package = 7A0516142414EC1200FC55AC /* XCRemoteSwiftPackageReference "RxDataSources" */;
productName = Differentiator;
};
7A0516172414EC1200FC55AC /* RxDataSources */ = {
isa = XCSwiftPackageProductDependency;
package = 7A0516142414EC1200FC55AC /* XCRemoteSwiftPackageReference "RxDataSources" */;
productName = RxDataSources;
};
7A11471C23FEA18700B424AF /* RxSwift */ = { 7A11471C23FEA18700B424AF /* RxSwift */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */; package = 7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */;

View File

@ -55,6 +55,15 @@
"version": "5.23.8" "version": "5.23.8"
} }
}, },
{
"package": "RxDataSources",
"repositoryURL": "https://github.com/RxSwiftCommunity/RxDataSources",
"state": {
"branch": null,
"revision": "a18cee01c9ee55f04d0c7eb15c77a96c3648c88e",
"version": "4.0.1"
}
},
{ {
"package": "RxRealm", "package": "RxRealm",
"repositoryURL": "https://github.com/RxSwiftCommunity/RxRealm", "repositoryURL": "https://github.com/RxSwiftCommunity/RxRealm",
@ -72,6 +81,15 @@
"revision": "b3e888b4972d9bc76495dd74d30a8c7fad4b9395", "revision": "b3e888b4972d9bc76495dd74d30a8c7fad4b9395",
"version": "5.0.1" "version": "5.0.1"
} }
},
{
"package": "SwiftDate",
"repositoryURL": "https://github.com/malcommac/SwiftDate.git",
"state": {
"branch": null,
"revision": "700dde1b3417fd4a7fd2bec9f5bc8ab2de1b96b4",
"version": "6.1.0"
}
} }
] ]
}, },

View File

@ -8,7 +8,7 @@
BreakpointExtensionID = "Xcode.Breakpoint.SwiftErrorBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.SwiftErrorBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "C14D0996-5708-44D2-A6BA-4A4B50B522EE" uuid = "C14D0996-5708-44D2-A6BA-4A4B50B522EE"
shouldBeEnabled = "No" shouldBeEnabled = "Yes"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No"> continueAfterRunningActions = "No">
</BreakpointContent> </BreakpointContent>
@ -17,7 +17,7 @@
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "CF01B44D-372B-4C78-A197-7FDEC607CE0E" uuid = "CF01B44D-372B-4C78-A197-7FDEC607CE0E"
shouldBeEnabled = "No" shouldBeEnabled = "Yes"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
scope = "1" scope = "1"

View File

@ -3,6 +3,9 @@ import InputMask
import RealmSwift import RealmSwift
import RxSwift import RxSwift
import SVProgressHUD import SVProgressHUD
import SwiftDate
import RxRealm
import RxDataSources
class CheckController: UIViewController, MaskedTextFieldDelegateListener { class CheckController: UIViewController, MaskedTextFieldDelegateListener {
@ -21,19 +24,64 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
self.number.delegate = self.maskFieldDelegate self.number.delegate = self.maskFieldDelegate
self.check.isEnabled = false self.check.isEnabled = false
let ds = RxTableViewRealmDataSource<Vehicle>(cellIdentifier: "VehicleCell", cellType: VehicleCell.self) { cell, ip, vehicle in // let ds = RxTableViewRealmDataSource<Vehicle>(cellIdentifier: "VehicleCell", cellType: VehicleCell.self) { cell, ip, vehicle in
cell.configure(with: vehicle) // 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)
return cell
} else {
return UITableViewCell()
}
})
ds.titleForHeaderInSection = { dataSourse, index in
return dataSourse.sectionModels[index].header
} }
ds.headerTitle = "History"
let realm = try! Realm() let realm = try! Realm()
Observable.changeset(from: realm.objects(Vehicle.self).sorted(byKeyPath: "addedDate", ascending: false)) // Observable.changeset(from: realm.objects(Vehicle.self).sorted(byKeyPath: "addedDate", ascending: false))
.bind(to: self.history.rx.realmChanges(ds)) // .bind(to: self.history.rx.realmChanges(ds))
.disposed(by: self.bag) // .disposed(by: self.bag)
self.history.rx.realmModelSelected(Vehicle.self) self.history.rx.realmModelSelected(Vehicle.self)
.subscribe(onNext: self.updateDetailController(with:)) .subscribe(onNext: self.updateDetailController(with:))
.disposed(by: self.bag) .disposed(by: self.bag)
Observable.collection(from: realm.objects(Vehicle.self).sorted(byKeyPath: "addedDate", ascending: false)).map { (vehicles: Results<Vehicle>) -> [DateSection<Vehicle>] in
var sections: [TimeInterval: [Vehicle]] = [:]
for vehicle in vehicles {
let date = Date(timeIntervalSince1970: vehicle.addedDate)
let key = date.dateAtStartOf(.weekday).timeIntervalSince1970
print("==== Key: \(key)")
if sections[key] == nil {
sections[key] = [vehicle]
} else {
sections[key]?.append(vehicle)
}
}
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .medium
var sectionsArray: [DateSection<Vehicle>] = []
for (timestamp, vehicles) in sections {
let dateStr = formatter.string(from: Date(timeIntervalSince1970: timestamp/1000))
sectionsArray.append(DateSection<Vehicle>(header: dateStr, items: vehicles))
}
print("==========================")
for s in sectionsArray {
print(s.header)
}
return sectionsArray
}
.bind(to: self.history.rx.items(dataSource: ds))
.disposed(by: self.bag)
} }
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
@ -44,6 +92,7 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
@IBAction func checkTapped(_ sender: UIButton) { @IBAction func checkTapped(_ sender: UIButton) {
guard let number = self.number.text else { return } guard let number = self.number.text else { return }
self.number.resignFirstResponder()
self.number.text = nil self.number.text = nil
SVProgressHUD.show() SVProgressHUD.show()
Api.checkVehicle(by: number) Api.checkVehicle(by: number)
@ -60,7 +109,6 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
} }
func textFieldShouldReturn(_ textField: UITextField) -> Bool { func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
if self.check.isEnabled { if self.check.isEnabled {
self.checkTapped(self.check) self.checkTapped(self.check)
} }
@ -96,4 +144,6 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
} }
} }
} }
} }

View File

@ -0,0 +1,22 @@
import Foundation
import RxDataSources
struct DateSection<T>: AnimatableSectionModelType where T: IdentifiableType, T: Equatable {
var header: String
var items: [T]
var identity: String {
return header
}
init(original: DateSection, items: [T]) {
self = original
self.items = items
}
init(header: String, items: [T]) {
self.header = header
self.items = items
}
}

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import RealmSwift import RealmSwift
import RxDataSources
class VehicleName: Object, Decodable { class VehicleName: Object, Decodable {
@objc dynamic var original: String? @objc dynamic var original: String?
@ -39,7 +40,7 @@ class VehiclePhoto: Object, Decodable {
} }
} }
class Vehicle: Object, Decodable { class Vehicle: Object, Decodable, IdentifiableType {
@objc dynamic var _id: String = "" @objc dynamic var _id: String = ""
@objc dynamic var brand: VehicleBrand? @objc dynamic var brand: VehicleBrand?
@objc dynamic var model: VehicleModel? @objc dynamic var model: VehicleModel?
@ -58,6 +59,8 @@ class Vehicle: Object, Decodable {
@objc dynamic var addedBy: String = "" @objc dynamic var addedBy: String = ""
let photos = List<VehiclePhoto>() let photos = List<VehiclePhoto>()
var identity: String { _id }
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case _id case _id
case brand case brand