diff --git a/AutoCat2.xcodeproj/project.pbxproj b/AutoCat2.xcodeproj/project.pbxproj index 1831d20..015b462 100644 --- a/AutoCat2.xcodeproj/project.pbxproj +++ b/AutoCat2.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 7A28283327E7263B0049BDBF /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A28283227E7263B0049BDBF /* UIStackView.swift */; }; 7A28283627E74C110049BDBF /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7A28283527E74C110049BDBF /* SwiftEntryKit */; }; 7A28283827E74D930049BDBF /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A28283727E74D930049BDBF /* CheckController.swift */; }; + 7A2977212857595700060A2A /* ReportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2977202857595700060A2A /* ReportController.swift */; }; 7A2B6CD427FCE93C00519F1E /* TestSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2B6CD327FCE93C00519F1E /* TestSettings.swift */; }; 7A2B6CD727FCED0500519F1E /* XCUIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2B6CD527FCEC8600519F1E /* XCUIApplication.swift */; }; 7A36E55C27FB55570025AACB /* Testing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A36E55B27FB55570025AACB /* Testing.swift */; }; @@ -163,6 +164,7 @@ 7A28283027E721A70049BDBF /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; 7A28283227E7263B0049BDBF /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = ""; }; 7A28283727E74D930049BDBF /* CheckController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckController.swift; sourceTree = ""; }; + 7A2977202857595700060A2A /* ReportController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportController.swift; sourceTree = ""; }; 7A2B6CD327FCE93C00519F1E /* TestSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSettings.swift; sourceTree = ""; }; 7A2B6CD527FCEC8600519F1E /* XCUIApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIApplication.swift; sourceTree = ""; }; 7A36E55B27FB55570025AACB /* Testing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Testing.swift; sourceTree = ""; }; @@ -298,6 +300,7 @@ 6841A0A6580C6E9FF26DC6E2 /* HistoryController.swift */, 6841A5A586BC03AA21D73DF4 /* SettingsController.swift */, 7A28283727E74D930049BDBF /* CheckController.swift */, + 7A2977202857595700060A2A /* ReportController.swift */, ); path = Controllers; sourceTree = ""; @@ -815,6 +818,7 @@ 7A28283827E74D930049BDBF /* CheckController.swift in Sources */, 6841A7D2375D35B0102D7DEC /* SwiftMaskTextfield.swift in Sources */, 6841ABD5E4B126DEF3612BBD /* PNKeyboard.swift in Sources */, + 7A2977212857595700060A2A /* ReportController.swift in Sources */, 7A24C19C27EE25B400049E7F /* PlateView.swift in Sources */, 7A24C19D27EE25B400049E7F /* FlagLayer.swift in Sources */, ); diff --git a/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist b/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist index 7c5d819..b84da60 100644 --- a/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,6 +9,18 @@ orderHint 0 + AutoCat2.xcscheme_^#shared#^_ + + orderHint + 0 + + AutoCat2UITests.testExample.xcscheme + + isShown + + orderHint + 8 + AutoCatCore.xcscheme_^#shared#^_ orderHint @@ -17,59 +29,52 @@ DifferenceKit (Playground) 1.xcscheme isShown - + orderHint 3 DifferenceKit (Playground) 2.xcscheme isShown - + orderHint 4 DifferenceKit (Playground).xcscheme isShown - + orderHint 2 SwiftDate (Playground) 1.xcscheme isShown - + orderHint 6 SwiftDate (Playground) 2.xcscheme isShown - + orderHint 7 SwiftDate (Playground).xcscheme isShown - + orderHint 5 - AutoCat2UITests.testExample.xcscheme - - isShown - - orderHint - 8 - SuppressBuildableAutocreation 7A49F4D627D4064500AEAAE0 primary - + diff --git a/AutoCat2/Components/TableView/CoreDataSource.swift b/AutoCat2/Components/TableView/CoreDataSource.swift index 0781f1c..c405d03 100644 --- a/AutoCat2/Components/TableView/CoreDataSource.swift +++ b/AutoCat2/Components/TableView/CoreDataSource.swift @@ -66,6 +66,10 @@ class CoreDataSource Item { + sections[indexPath.section].elements[indexPath.row] + } + // MARK: - NSFetchedResultsControllerDelegate diff --git a/AutoCat2/Controllers/HistoryController.swift b/AutoCat2/Controllers/HistoryController.swift index d478303..17a3b46 100644 --- a/AutoCat2/Controllers/HistoryController.swift +++ b/AutoCat2/Controllers/HistoryController.swift @@ -6,8 +6,7 @@ import UIKit import PKHUD import AutoCatCore -class HistoryController: UIViewController { - +class HistoryController: UIViewController, UITableViewDelegate { private lazy var tableView: UITableView = { let table = UITableView() @@ -15,6 +14,7 @@ class HistoryController: UIViewController { table.register(VehicleCell.self, forCellReuseIdentifier: cellIdentifier) table.translatesAutoresizingMaskIntoConstraints = false table.accessibilityIdentifier = "historyTable" + table.delegate = self return table }() @@ -52,4 +52,18 @@ class HistoryController: UIViewController { show(error: error) } } + + // MARK: - UITableViewDelegate + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + guard let vehicle = dataSource?.item(at: indexPath) else { + return + } + + let controller = ReportController(vehicle: vehicle) + controller.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(controller, animated: true) + } } diff --git a/AutoCat2/Controllers/ReportController.swift b/AutoCat2/Controllers/ReportController.swift new file mode 100644 index 0000000..435a542 --- /dev/null +++ b/AutoCat2/Controllers/ReportController.swift @@ -0,0 +1,278 @@ +// +// ReportController.swift +// AutoCat2 +// +// Created by Selim Mustafaev on 13.06.2022. +// + +import UIKit +import AutoCatCore + +enum ReportSection: Int, CaseIterable { + + case title + case general + case identifiers + case engine +// case history = 3 +// case debug = 4 + + var name: String { + switch self { + case .title: return "" + case .general: return "General" + case .identifiers: return "Identifiers" + case .engine: return "Engine" + } + } +} + +enum ReportGeneralItem: Int, CaseIterable { + + case year + case color + case category + case steeringWheelPosition + case isJapanese + + var name: String { + switch self { + case .year: return "Year" + case .color: return "Color" + case .category: return "Category" + case .steeringWheelPosition: return "Steering wheel position" + case .isJapanese: return "Japanese vehicle" + } + } +} + +enum ReportIdentifiersItem: Int, CaseIterable { + + case number + case vin + case sts + case pts + + var name: String { + switch self { + case .number: return "Plate number" + case .vin: return "VIN" + case .sts: return "STS" + case .pts: return "PTS" + } + } +} + +enum ReportEngineItem: Int, CaseIterable { + + case number + case fuelType + case volume + case powerHp + case powerKw + + var name: String { + switch self { + case .number: return "Number" + case .fuelType: return "Fuel type" + case .volume: return "Volume" + case .powerHp: return "Power (HP)" + case .powerKw: return "Power (kw)" + } + } +} + +struct ReportItem { + let name: String + let value: String? + let image: UIImage? + + init(name: String, value: String?) { + self.name = name + self.value = value + self.image = nil + } + + init(name: String, image: UIImage?) { + self.name = name + self.value = nil + self.image = image + } +} + +class ReportController: UIViewController, UICollectionViewDataSource { + + private let reportTextItemId = String(describing: ReportTextItemCell.self) + + private lazy var collectionView: UICollectionView = { + let collection = UICollectionView(frame: .zero, collectionViewLayout: createLayout()) + collection.translatesAutoresizingMaskIntoConstraints = false + collection.register(ReportTextItemCell.self, + forCellWithReuseIdentifier: reportTextItemId) + collection.dataSource = self + return collection + }() + + private let textCellRegistration = UICollectionView.CellRegistration { cell, indexPath, item in + var config = UIListContentConfiguration.valueCell() + config.text = item.name + config.secondaryText = item.value + cell.contentConfiguration = config + } + + private let titleCellRegistration = UICollectionView.CellRegistration { cell, indexPath, item in + var config = UIListContentConfiguration.cell() + config.text = item.name + cell.contentConfiguration = config + } + + private let supplementaryRegistration = UICollectionView.SupplementaryRegistration(elementKind: UICollectionView.elementKindSectionHeader) { supplementaryView, elementKind, indexPath in + + guard let section = ReportSection(rawValue: indexPath.section) else { + return + } + + var configutation = UIListContentConfiguration.groupedHeader() + configutation.text = section.name + supplementaryView.contentConfiguration = configutation + } + + let vehicle: CDVehicle + + // MARK: - Lifecycle + + init(vehicle: CDVehicle) { + self.vehicle = vehicle + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemBackground + title = vehicle.number + + view.addSubview(collectionView) + collectionView.pin(to: view) + } + + func createLayout() -> UICollectionViewLayout { + + UICollectionViewCompositionalLayout { section, env in + var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped) + config.headerMode = section == 0 ? .none : .supplementary + + return NSCollectionLayoutSection.list(using: config, layoutEnvironment: env) + } + } + + // MARK: - Getting data + + func getTextData(for indexPath: IndexPath) -> ReportItem { + guard let section = ReportSection(rawValue: indexPath.section) else { + return ReportItem(name: "", value: nil) + } + + switch section { + case .title: return ReportItem(name: vehicle.brand?.name?.original ?? "", image: nil) + case .general: return getGeneralValue(index: indexPath.row) + case .identifiers: return getIdentifiersValue(index: indexPath.row) + case .engine: return getEngineValue(index: indexPath.row) + } + } + + func getGeneralValue(index: Int) -> ReportItem { + guard let item = ReportGeneralItem(rawValue: index) else { + return ReportItem(name: "", value: nil) + } + + let value: String? + + switch item { + case .year: value = String(vehicle.year) + case .color: value = vehicle.color + case .category: value = vehicle.category + case .steeringWheelPosition: value = vehicle.isRightWheel ? "Right" : "Left" + case .isJapanese: value = vehicle.isJapanese ? "Yes" : "No" + } + + return ReportItem(name: item.name, value: value) + } + + func getIdentifiersValue(index: Int) -> ReportItem { + guard let item = ReportIdentifiersItem(rawValue: index) else { + return ReportItem(name: "", value: nil) + } + + let value: String? + + switch item { + case .number: value = vehicle.number + case .vin: value = vehicle.vin1 + case .sts: value = vehicle.sts + case .pts: value = vehicle.pts + } + + return ReportItem(name: item.name, value: value) + } + + func getEngineValue(index: Int) -> ReportItem { + guard let item = ReportEngineItem(rawValue: index) else { + return ReportItem(name: "", value: nil) + } + + let value: String? + + switch item { + case .number: value = vehicle.engine?.number + case .fuelType: value = vehicle.engine?.fuelType + case .volume: value = String(vehicle.engine?.volume ?? 0) + case .powerHp: value = String(vehicle.engine?.powerHp ?? 0) + case .powerKw: value = String(vehicle.engine?.powerKw ?? 0) + } + + return ReportItem(name: item.name, value: value) + } + + // MARK: - UICollectionViewDataSource + + func numberOfSections(in collectionView: UICollectionView) -> Int { + ReportSection.allCases.count + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + guard let sectionEnum = ReportSection(rawValue: section) else { + return 0 + } + + switch sectionEnum { + case .title: + return 1 + case .general: + return ReportGeneralItem.allCases.count + case .identifiers: + return ReportIdentifiersItem.allCases.count + case .engine: + return ReportEngineItem.allCases.count + } + } + + func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + + let item = getTextData(for: indexPath) + return collectionView.dequeueConfiguredReusableCell(using: textCellRegistration, for: indexPath, item: item) + } + + func collectionView(_ collectionView: UICollectionView, + viewForSupplementaryElementOfKind kind: String, + at indexPath: IndexPath) -> UICollectionReusableView { + + collectionView.dequeueConfiguredReusableSupplementary(using: supplementaryRegistration, + for: indexPath) + } +}