AutoCat/AutoCat/Controllers/CheckController.swift

259 lines
9.5 KiB
Swift

import UIKit
import InputMask
import RealmSwift
import RxSwift
import SwiftDate
import RxRealm
import RxDataSources
enum EventAction {
case doNotSend
case receiveAndSend
case sendSpecific(VehicleEvent)
}
class CheckController: UIViewController, MaskedTextFieldDelegateListener, UITableViewDelegate {
@IBOutlet weak var number: UITextField!
@IBOutlet weak var check: UIButton!
@IBOutlet weak var history: UITableView!
let bag = DisposeBag()
let maskFieldDelegate = MaskedTextFieldDelegate()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
guard let realm = try? Realm() else { return }
self.hideKeyboardWhenTappedAround()
self.maskFieldDelegate.primaryMaskFormat = "[A][000][AA] [009]"
self.maskFieldDelegate.listener = self
self.number.delegate = self.maskFieldDelegate
self.check.isEnabled = false
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()
}
}, canEditRowAtIndexPath: { _, _ in true })
ds.titleForHeaderInSection = { dataSourse, index in
return dataSourse.sectionModels[index].header
}
self.history.rx.modelSelected(Vehicle.self)
.subscribe(onNext: self.updateDetailController(with:))
.disposed(by: self.bag)
DispatchQueue.main.async {
Observable.collection(from: realm.objects(Vehicle.self)
.sorted(byKeyPath: "addedDate", ascending: false))
.map { $0.groupedByDate() }
.bind(to: self.history.rx.items(dataSource: ds))
.disposed(by: self.bag)
}
self.history.rx.setDelegate(self).disposed(by: self.bag)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
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)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.handleQuickActions()
}
// MARK: -
func handleQuickActions() {
guard let ad = UIApplication.shared.delegate as? AppDelegate else { return }
switch ad.quickAction {
case .check:
ad.quickAction = .none
self.number.becomeFirstResponder()
break
case .checkNumber(let number, let event):
ad.quickAction = .none
var action: EventAction = .receiveAndSend
if let event = event {
action = .sendSpecific(event)
}
self.check(number: number, action: action)
break
case .addVoiceRecord:
self.tabBarController?.selectedIndex = 1
break
default:
break
}
}
// MARK: - Checking new number
@IBAction func checkTapped(_ sender: UIButton) {
guard let number = self.number.text else { return }
let numberNormalized = number.filter { !$0.isWhitespace }.uppercased()
self.check(number: numberNormalized, action: .receiveAndSend)
}
func check(number: String, action: EventAction) {
self.number.resignFirstResponder()
self.number.text = nil
self.check.isEnabled = false
IHProgressHUD.show()
Api.checkVehicle(by: number)
.observeOn(MainScheduler.instance)
.subscribe(onSuccess: { vehicle in
self.onReceivedVehicle(vehicle, action: action)
}, onError: { err in
if let realm = try? Realm() {
let vehicle = Vehicle(number)
try? realm.write {
realm.add(vehicle, update: .all)
}
var eventSingle = self.getEvent()
if case .sendSpecific(let event) = action {
eventSingle = Single.just(event)
}
eventSingle
.flatMap { event in event.findAddress().map{ [event] }.catchErrorJustReturn([event]) }
.catchErrorJustReturn([])
.subscribe(onSuccess: { events in
try? realm.write {
vehicle.events.append(objectsIn: events)
}
})
.disposed(by: self.bag)
}
IHProgressHUD.showError(withStatus: err.localizedDescription)
print(err.localizedDescription)
}).disposed(by: self.bag)
}
func save(vehicle: Vehicle) {
if let realm = try? Realm() {
try? realm.write {
realm.add(vehicle, update: .all)
}
}
}
func getEvent() -> Single<VehicleEvent> {
if let event = LocationManager.lastEvent, (Date().timeIntervalSince1970 - event.date) < 30 {
print("Using last event")
return Single<VehicleEvent>.just(event)
} else {
print("requesting new event")
return LocationManager.requestCurrentLocation()
}
}
func onReceivedVehicle(_ vehicle: Vehicle, action: EventAction = .receiveAndSend) {
self.save(vehicle: vehicle)
if case .doNotSend = action {
// Just do nothing
} else {
var eventSingle = self.getEvent()
if case .sendSpecific(let event) = action {
eventSingle = Single.just(event)
}
eventSingle
.flatMap { event in event.findAddress().map{ event }.catchErrorJustReturn(event) }
.flatMap { Api.add(event: $0, to: vehicle.number) }
.subscribe(onSuccess: self.save(vehicle:), onError: { print("Error adding event: \($0)") })
.disposed(by: self.bag)
}
self.updateDetailController(with: vehicle)
IHProgressHUD.dismiss()
}
func updateDetailController(with vehicle: Vehicle) {
if let splitViewController = self.view.window?.rootViewController as? UISplitViewController
{
var detail: UINavigationController?
if splitViewController.viewControllers.count == 2 {
detail = splitViewController.viewControllers.last as? UINavigationController
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
detail = storyboard.instantiateViewController(identifier: "ReportNavController")
}
if let detail = detail {
detail.popToRootViewController(animated: true)
let report = detail.viewControllers.first as? ReportController
report?.number = vehicle.number
splitViewController.showDetailViewController(detail, sender: self)
//self.performSegue(withIdentifier: "OpenDetailSegue", sender: self)
}
}
}
// MARK: - UITextFieldDelegate
func textField(_ textField: UITextField, didFillMandatoryCharacters complete: Bool, didExtractValue value: String) {
self.check.isEnabled = complete
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if self.check.isEnabled {
self.checkTapped(self.check)
}
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
LocationManager.requestCurrentLocation().subscribe().disposed(by: self.bag)
}
// MARK: -
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard let vehicle: Vehicle = try? self.history.rx.model(at: indexPath) else { return nil }
let updateAction = UIContextualAction(style: .normal, title: "Update") { action, view, completion in
IHProgressHUD.show()
var eventAction: EventAction = .doNotSend
if vehicle.unrecognized, let savedEvent = vehicle.events.first {
eventAction = .sendSpecific(savedEvent.freeze())
}
Api.checkVehicle(by: vehicle.number, force: true)
.observeOn(MainScheduler.instance)
.subscribe(onSuccess: { vehicle in
self.onReceivedVehicle(vehicle, action: eventAction)
}, onError: { err in
IHProgressHUD.showError(withStatus: err.localizedDescription)
print(err.localizedDescription)
}).disposed(by: self.bag)
completion(true)
}
updateAction.image = UIImage(systemName: "arrow.2.circlepath")
updateAction.backgroundColor = .systemBlue
let configuration = UISwipeActionsConfiguration(actions: [updateAction])
configuration.performsFirstActionWithFullSwipe = false
return configuration
}
}