AutoCat/AutoCat/Controllers/ReportController.swift
2020-06-02 00:24:08 +03:00

336 lines
14 KiB
Swift

import UIKit
import MagazineLayout
import Kingfisher
enum ReportSection: Int, CaseIterable, CustomStringConvertible {
case header = 0
case general = 1
case identifiers = 2
case engine = 3
case photos = 4
var description: String {
switch self {
case .header: return "Header"
case .general: return "General"
case .identifiers: return "Identifiers"
case .engine: return "Engine"
case .photos: return "Photos"
}
}
}
enum ReportGeneralSection: Int, CaseIterable, CustomStringConvertible {
case year = 0
case color = 1
case category = 2
case wheelPosition = 3
case japanese = 4
case owners = 5
var description: String {
switch self {
case .year: return "Year"
case .color: return "Color"
case .category: return "Category"
case .wheelPosition: return "Steering wheel position"
case .japanese: return "Japanese"
case .owners: return "Owners (from PTS)"
}
}
}
enum ReportIdSection: Int, CaseIterable, CustomStringConvertible {
case number = 0
case vin = 1
case sts = 2
case pts = 3
var description: String {
switch self {
case .number: return "Number"
case .vin: return "VIN"
case .pts: return "PTS"
case .sts: return "STS"
}
}
}
enum ReportEngineSection: Int, CaseIterable, CustomStringConvertible {
case number = 0
case fuelType = 1
case volume = 2
case powerHp = 3
case powerKw = 4
var description: String {
switch self {
case .number: return "Number"
case .fuelType: return "Fuel type"
case .volume: return "Volume (cm³)"
case .powerHp: return "Power (HP)"
case .powerKw: return "Power (kw)"
}
}
}
class ReportController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateMagazineLayout, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate {
@IBOutlet weak var collection: UICollectionView!
private let fullWidth = MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), heightMode: .dynamic)
var vehicle: Vehicle? {
didSet {
loadViewIfNeeded()
self.collection.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.collection.collectionViewLayout = MagazineLayout()
let nib = UINib(nibName: "SectionHeader", bundle: nil)
self.collection.register(nib, forSupplementaryViewOfKind: MagazineLayout.SupplementaryViewKind.sectionHeader, withReuseIdentifier: "SectionHeader")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let ad = UIApplication.shared.delegate as? AppDelegate else { return }
self.navigationController?.setNavigationBarHidden(self.traitCollection.horizontalSizeClass != .compact, animated: false)
if ad.quickAction == .check {
self.dismiss(animated: false, completion: nil)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
self.navigationController?.setNavigationBarHidden(self.traitCollection.horizontalSizeClass != .compact, animated: false)
}
// MARK: - UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
guard self.vehicle != nil else { return 0 }
return ReportSection.allCases.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guard let vehicle = self.vehicle else { return 0 }
guard let section = ReportSection(rawValue: section) else { return 0 }
switch section {
case .header: return 1
case .general: return ReportGeneralSection.allCases.count
case .identifiers: return ReportIdSection.allCases.count
case .engine: return ReportEngineSection.allCases.count
case .photos: return vehicle.photos.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let section = ReportSection(rawValue: indexPath.section) else { return UICollectionViewCell() }
guard let vehicle = self.vehicle else { return UICollectionViewCell() }
switch section {
case .header:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleHeaderCell", for: indexPath) as? VehicleHeaderCell
cell?.configure(with: vehicle)
return cell ?? UICollectionViewCell()
case .general:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleTextParamCell", for: indexPath) as? VehicleTextParamCell
if let generalSection = ReportGeneralSection(rawValue: indexPath.item) {
switch generalSection {
case .year:
cell?.configure(param: generalSection.description, value: String(vehicle.year))
break
case .color:
cell?.configure(param: generalSection.description, value: vehicle.color ?? "<unknown>")
break
case .category:
cell?.configure(param: generalSection.description, value: vehicle.category ?? "<unknown>")
break
case .wheelPosition:
cell?.configure(param: generalSection.description, value: vehicle.isRightWheel ? "Right" : "Left")
break
case .japanese:
cell?.configure(param: generalSection.description, value: vehicle.isJapanese ? "Yes" : "No")
break
case .owners:
cell?.configure(param: generalSection.description, value: String(vehicle.ownershipPeriods.count))
break
}
}
return cell ?? UICollectionViewCell()
case .identifiers:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleTextParamCell", for: indexPath) as? VehicleTextParamCell
if let idSection = ReportIdSection(rawValue: indexPath.item) {
switch idSection {
case .number:
cell?.configure(param: idSection.description, value: vehicle.number)
break
case .vin:
cell?.configure(param: idSection.description, value: vehicle.vin1 ?? "<unknown>")
break
case .sts:
cell?.configure(param: idSection.description, value: vehicle.sts ?? "<unknown>")
break
case .pts:
cell?.configure(param: idSection.description, value: vehicle.pts ?? "<unknown>")
break
}
}
return cell ?? UICollectionViewCell()
case .engine:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleTextParamCell", for: indexPath) as? VehicleTextParamCell
if let engineSection = ReportEngineSection(rawValue: indexPath.item), let engine = vehicle.engine {
switch engineSection {
case .number:
cell?.configure(param: engineSection.description, value: engine.number ?? "<unknown>")
break
case .fuelType:
cell?.configure(param: engineSection.description, value: engine.fuelType ?? "<unknown>")
break
case .volume:
cell?.configure(param: engineSection.description, value: String(engine.volume))
break
case .powerHp:
cell?.configure(param: engineSection.description, value: String(engine.powerHp))
break
case .powerKw:
cell?.configure(param: engineSection.description, value: String(engine.powerKw))
break
}
}
return cell ?? UICollectionViewCell()
case .photos:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehiclePhotoCell", for: indexPath) as? VehiclePhotoCell
let photo = vehicle.photos[indexPath.item]
cell?.configure(with: photo)
return cell ?? UICollectionViewCell()
}
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
{
guard let section = ReportSection(rawValue: indexPath.section) else { return UICollectionReusableView() }
if let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionHeader", for: indexPath) as? SectionHeader {
sectionHeader.configure(with: section)
return sectionHeader
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.section == ReportSection.photos.rawValue {
let mediaBrowser = MediaBrowserViewController(index: indexPath.item, dataSource: self, delegate: self)
mediaBrowser.shouldShowTitle = true
mediaBrowser.title = self.vehicle?.photos[indexPath.item].description
present(mediaBrowser, animated: true, completion: nil)
}
if indexPath.section == ReportSection.general.rawValue {
if indexPath.row == ReportGeneralSection.owners.rawValue {
let sb = UIStoryboard(name: "Main", bundle: nil)
let controller = sb.instantiateViewController(identifier: "OwnersController") as OwnersController
controller.owners = self.vehicle?.ownershipPeriods.toArray() ?? []
self.navigationController?.pushViewController(controller, animated: true)
}
}
}
// MARK: - UICollectionViewDelegateMagazineLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeModeForItemAt indexPath: IndexPath) -> MagazineLayoutItemSizeMode
{
guard let section = ReportSection(rawValue: indexPath.section) else { return self.fullWidth }
switch section {
case .header: return self.fullWidth
case .general: return self.fullWidth
case .identifiers: return self.fullWidth
case .engine: return self.fullWidth
case .photos:
let wMode: MagazineLayoutItemWidthMode = self.traitCollection.horizontalSizeClass != .compact ? .thirdWidth : .halfWidth
return .init(widthMode: wMode, heightMode: .dynamic)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForHeaderInSectionAtIndex index: Int) -> MagazineLayoutHeaderVisibilityMode
{
guard let section = ReportSection(rawValue: index) else { return .hidden }
switch section {
case .header: return .hidden
case .general: return .visible(heightMode: .dynamic)
case .identifiers: return .visible(heightMode: .dynamic)
case .engine: return .visible(heightMode: .dynamic)
case .photos: return .visible(heightMode: .dynamic)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForFooterInSectionAtIndex index: Int) -> MagazineLayoutFooterVisibilityMode
{
return .hidden
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForBackgroundInSectionAtIndex index: Int) -> MagazineLayoutBackgroundVisibilityMode
{
return .hidden
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, horizontalSpacingForItemsInSectionAtIndex index: Int) -> CGFloat
{
return 16
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, verticalSpacingForElementsInSectionAtIndex index: Int) -> CGFloat
{
return index == ReportSection.photos.rawValue ? 16 : 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForSectionAtIndex index: Int) -> UIEdgeInsets
{
return index == ReportSection.photos.rawValue ? UIEdgeInsets(top: 0, left: 0, bottom: 16, right: 0) : .zero
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForItemsInSectionAtIndex index: Int) -> UIEdgeInsets
{
return index == ReportSection.photos.rawValue ? UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) : .zero
}
// MARK: - MediaBrowserViewControllerDataSource & MediaBrowserViewControllerDelegate
func numberOfItems(in mediaBrowser: MediaBrowserViewController) -> Int {
guard let images = self.vehicle?.photos else { return 0 }
return images.count
}
func mediaBrowser(_ mediaBrowser: MediaBrowserViewController, imageAt index: Int, completion: @escaping MediaBrowserViewControllerDataSource.CompletionBlock) {
guard let images = self.vehicle?.photos, let url = URL(string: images[index].url) else {
completion(index, nil, ZoomScale.default, NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Image not found"]))
return
}
KingfisherManager.shared.retrieveImage(with: url) { result in
switch result {
case .success(let res):
completion(index, res.image, ZoomScale.default, nil)
break
case .failure(let error):
completion(index, nil, ZoomScale.default, error)
break
}
}
}
func mediaBrowser(_ mediaBrowser: MediaBrowserViewController, didChangeFocusTo index: Int) {
guard let photo = self.vehicle?.photos[index] else { return }
mediaBrowser.title = photo.description
}
}