Search plate numbers

This commit is contained in:
Selim Mustafaev 2020-04-03 21:30:54 +03:00
parent cbace022ab
commit 6bf0ad8d12
10 changed files with 267 additions and 49 deletions

View File

@ -31,6 +31,9 @@
7A11474923FF2B2D00B424AF /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; };
7A11474B23FF368B00B424AF /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474A23FF368B00B424AF /* Settings.swift */; };
7A11474E23FFEE8800B424AF /* SVProgressHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */; };
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3F07AA24360DC800E59687 /* Dated.swift */; };
7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3F07AC2436350B00E59687 /* SearchController.swift */; };
7A3F07AF24366DF900E59687 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3F07AE24366DF900E59687 /* Filter.swift */; };
7A530B78240010D900CBFE6E /* InputMask in Frameworks */ = {isa = PBXBuildFile; productRef = 7A530B77240010D900CBFE6E /* InputMask */; };
7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7924001D3300CBFE6E /* CheckController.swift */; };
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */; };
@ -71,6 +74,9 @@
7A11474823FF2B2D00B424AF /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = "<group>"; };
7A11474A23FF368B00B424AF /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; };
7A3F07AA24360DC800E59687 /* Dated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dated.swift; sourceTree = "<group>"; };
7A3F07AC2436350B00E59687 /* SearchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchController.swift; sourceTree = "<group>"; };
7A3F07AE24366DF900E59687 /* Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filter.swift; sourceTree = "<group>"; };
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>"; };
@ -137,6 +143,7 @@
7A1146FF23FDE7E500B424AF /* AutoCat */ = {
isa = PBXGroup;
children = (
7A3F07A924360D9100E59687 /* Extensions */,
7A6DD90424326788009DE740 /* Fonts */,
7A6DD901242BF48D009DE740 /* Views */,
7A530B7C24017FBE00CBFE6E /* Cells */,
@ -162,6 +169,7 @@
7A11471923FE839000B424AF /* AuthController.swift */,
7A530B7924001D3300CBFE6E /* CheckController.swift */,
7AEFE727240455E200910EB7 /* SettingsController.swift */,
7A3F07AC2436350B00E59687 /* SearchController.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -191,6 +199,7 @@
7A530B7F2401803A00CBFE6E /* Vehicle.swift */,
7A0516192414FF0900FC55AC /* DateSection.swift */,
7A6DD90D24337930009DE740 /* PlateNumber.swift */,
7A3F07AE24366DF900E59687 /* Filter.swift */,
);
path = Models;
sourceTree = "<group>";
@ -204,6 +213,14 @@
name = Frameworks;
sourceTree = "<group>";
};
7A3F07A924360D9100E59687 /* Extensions */ = {
isa = PBXGroup;
children = (
7A3F07AA24360DC800E59687 /* Dated.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
7A530B7C24017FBE00CBFE6E /* Cells */ = {
isa = PBXGroup;
children = (
@ -362,10 +379,12 @@
7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */,
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */,
7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */,
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
7A6DD90E24337930009DE740 /* PlateNumber.swift in Sources */,
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */,
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */,
7A11474923FF2B2D00B424AF /* Response.swift in Sources */,
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */,
7A11471A23FE839000B424AF /* AuthController.swift in Sources */,
@ -382,6 +401,7 @@
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */,
7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */,
7A11474B23FF368B00B424AF /* Settings.swift in Sources */,
7A3F07AF24366DF900E59687 /* Filter.swift in Sources */,
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -181,21 +181,84 @@
</objects>
<point key="canvasLocation" x="844" y="948.57571214392806"/>
</scene>
<!--Search-->
<!--Search Controller-->
<scene sceneID="3Md-yW-a0R">
<objects>
<viewController id="UPf-uT-oOr" sceneMemberID="viewController">
<viewController id="UPf-uT-oOr" customClass="SearchController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="IJP-gV-Ojc">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="dB3-iP-QRo">
<rect key="frame" x="0.0" y="44" width="375" height="574"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VehicleCell" id="VEP-QD-i6y" customClass="VehicleCell" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="85.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VEP-QD-i6y" id="8hH-8I-XLB">
<rect key="frame" x="0.0" y="0.0" width="375" height="85.5"/>
<autoresizingMask key="autoresizingMask"/>
<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="AQY-7N-q8D">
<rect key="frame" x="8" y="8" width="124" height="21.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<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="RPA-NR-0C6">
<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="cvf-vM-QnT" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="8" y="37.5" width="317" height="40"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Xoz-Iw-PCU"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="RPA-NR-0C6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="AQY-7N-q8D" secondAttribute="trailing" constant="8" id="AB5-Fg-dMQ"/>
<constraint firstItem="AQY-7N-q8D" firstAttribute="top" secondItem="8hH-8I-XLB" secondAttribute="top" constant="8" id="FiA-ZH-YN0"/>
<constraint firstItem="RPA-NR-0C6" firstAttribute="top" secondItem="8hH-8I-XLB" secondAttribute="top" constant="8" id="JyS-ht-gyH"/>
<constraint firstAttribute="trailing" secondItem="RPA-NR-0C6" secondAttribute="trailing" constant="8" id="Ki4-ca-I55"/>
<constraint firstAttribute="bottom" secondItem="cvf-vM-QnT" secondAttribute="bottom" constant="8" id="NoD-uC-htT"/>
<constraint firstItem="cvf-vM-QnT" firstAttribute="leading" secondItem="8hH-8I-XLB" secondAttribute="leading" constant="8" id="aO8-6i-9jc"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="cvf-vM-QnT" secondAttribute="trailing" constant="8" id="ipf-aR-tuv"/>
<constraint firstItem="AQY-7N-q8D" firstAttribute="leading" secondItem="8hH-8I-XLB" secondAttribute="leading" constant="8" id="lJ4-uW-IwQ"/>
<constraint firstItem="cvf-vM-QnT" firstAttribute="top" secondItem="AQY-7N-q8D" secondAttribute="bottom" constant="8" id="qh7-O4-4d1"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="date" destination="RPA-NR-0C6" id="ih3-3R-Y8J"/>
<outlet property="name" destination="AQY-7N-q8D" id="hSi-Nh-mc2"/>
<outlet property="plate" destination="cvf-vM-QnT" id="8Bm-gA-bbm"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="6Uh-9i-MKR" firstAttribute="bottom" secondItem="dB3-iP-QRo" secondAttribute="bottom" id="Qq7-Rm-AvA"/>
<constraint firstItem="dB3-iP-QRo" firstAttribute="top" secondItem="6Uh-9i-MKR" secondAttribute="top" id="SUK-IH-xTR"/>
<constraint firstItem="dB3-iP-QRo" firstAttribute="leading" secondItem="6Uh-9i-MKR" secondAttribute="leading" id="XTb-EI-bvm"/>
<constraint firstItem="dB3-iP-QRo" firstAttribute="trailing" secondItem="6Uh-9i-MKR" secondAttribute="trailing" id="w3e-Ir-qlo"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Uh-9i-MKR"/>
</view>
<tabBarItem key="tabBarItem" title="Search" image="magnifyingglass" catalog="system" id="gDG-z8-R0t"/>
<navigationItem key="navigationItem" id="kEp-Rw-7hu"/>
<connections>
<outlet property="tableView" destination="dB3-iP-QRo" id="b3n-R9-6lI"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="xsk-7S-rvc" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3262" y="143"/>
<point key="canvasLocation" x="4200.8000000000002" y="142.57871064467767"/>
</scene>
<!--Settings-->
<scene sceneID="G47-o0-Caa">
@ -354,7 +417,7 @@
</tabBar>
<connections>
<segue destination="TSb-ZG-qfD" kind="relationship" relationship="viewControllers" id="Bwf-98-gjF"/>
<segue destination="UPf-uT-oOr" kind="relationship" relationship="viewControllers" id="FGp-f6-fUh"/>
<segue destination="GCa-Re-j14" kind="relationship" relationship="viewControllers" id="FGp-f6-fUh"/>
<segue destination="4jU-Z3-PF2" kind="relationship" relationship="viewControllers" id="aH2-IT-86l"/>
</connections>
</tabBarController>
@ -485,6 +548,25 @@
</objects>
<point key="canvasLocation" x="844" y="1648"/>
</scene>
<!--Search-->
<scene sceneID="kiS-EQ-VFl">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="GCa-Re-j14" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Search" image="magnifyingglass" catalog="system" id="gDG-z8-R0t"/>
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="vdY-9n-hjX">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="UPf-uT-oOr" kind="relationship" relationship="rootViewController" id="aun-Tj-SJT"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="XQB-kc-hUv" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3261.5999999999999" y="142.57871064467767"/>
</scene>
</scenes>
<resources>
<image name="eye" catalog="system" width="128" height="81"/>

View File

@ -19,6 +19,8 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
override func viewDidLoad() {
super.viewDidLoad()
guard let realm = try? Realm() else { return }
self.maskFieldDelegate.primaryMaskFormat = "[A][000][AA] [009]"
self.maskFieldDelegate.listener = self
self.number.delegate = self.maskFieldDelegate
@ -41,36 +43,11 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
.subscribe(onNext: self.updateDetailController(with:))
.disposed(by: self.bag)
let now = Date()
let monthStart = now.dateAtStartOf(.month)
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]] = [:]
for vehicle in vehicles {
let date = Date(timeIntervalSince1970: vehicle.addedDate/1000)
var key = date.dateAtStartOf(.day).timeIntervalSince1970
if date.isBeforeDate(monthStart, orEqual: false, granularity: .day) {
key = date.dateAtStartOf(.month).timeIntervalSince1970
}
if sections[key] == nil {
sections[key] = [vehicle]
} else {
sections[key]?.append(vehicle)
}
}
var sectionsArray: [DateSection<Vehicle>] = []
for (timestamp, vehicles) in sections {
sectionsArray.append(DateSection<Vehicle>(timestamp: timestamp, items: vehicles))
}
return sectionsArray.sorted { $0.timestamp > $1.timestamp }
}
.bind(to: self.history.rx.items(dataSource: ds))
.disposed(by: self.bag)
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)
}
override func viewWillAppear(_ animated: Bool) {
@ -109,7 +86,6 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
func textField(_ textField: UITextField, didFillMandatoryCharacters complete: Bool, didExtractValue value: String) {
self.check.isEnabled = complete
print(value)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {

View File

@ -0,0 +1,82 @@
import UIKit
import RxDataSources
import RxSwift
import RxCocoa
class SearchController: UIViewController, UISearchResultsUpdating {
@IBOutlet weak var tableView: UITableView!
let bag = DisposeBag()
let searchController = UISearchController(searchResultsController: nil)
var filterRelay = BehaviorRelay<Filter>(value: Filter())
var filter = Filter()
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search plate numbers"
navigationItem.searchController = searchController
definesPresentationContext = true
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
}
self.tableView.rx.modelSelected(Vehicle.self)
.subscribe(onNext: self.updateDetailController(with:))
.disposed(by: self.bag)
self.filterRelay
//.throttle(.seconds(2), scheduler: MainScheduler.instance)
.debounce(.milliseconds(500), scheduler: MainScheduler.instance)
.flatMap(Api.getVehicles)
.observeOn(MainScheduler.instance)
.do(onNext: { self.navigationItem.title = "\($0.count) vehicles found" })
.map { $0.groupedByDate() }
.bind(to: self.tableView.rx.items(dataSource: ds))
.disposed(by: self.bag)
}
// FIXME: Code duplication
func updateDetailController(with vehicle: Vehicle) {
if let splitViewController = self.view.window?.rootViewController as? UISplitViewController
{
var detail: ReportController?
if splitViewController.viewControllers.count == 2 {
detail = splitViewController.viewControllers.last as? ReportController
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
detail = storyboard.instantiateViewController(identifier: "ReportController")
}
if let detail = detail {
detail.vehicle = vehicle
splitViewController.showDetailViewController(detail, sender: self)
//self.performSegue(withIdentifier: "OpenDetailSegue", sender: self)
}
}
}
// MARK: - UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
let newQuery = searchController.searchBar.text?.uppercased() ?? ""
guard self.filter.searchString != newQuery else { return }
self.filter.searchString = newQuery
self.filterRelay.accept(self.filter)
}
}

View File

@ -0,0 +1,40 @@
import Foundation
import RxDataSources
import SwiftDate
protocol Dated {
var date: Date { get }
}
extension Vehicle: Dated {
var date: Date {
Date(timeIntervalSince1970: self.addedDate/1000)
}
}
extension RandomAccessCollection where Element: Dated & IdentifiableType & Equatable {
func groupedByDate() -> [DateSection<Element>] {
let now = Date()
let monthStart = now.dateAtStartOf(.month)
var sections: [TimeInterval: [Element]] = [:]
for vehicle in self {
var key = vehicle.date.dateAtStartOf(.day).timeIntervalSince1970
if vehicle.date.isBeforeDate(monthStart, orEqual: false, granularity: .day) {
key = vehicle.date.dateAtStartOf(.month).timeIntervalSince1970
}
if sections[key] == nil {
sections[key] = [vehicle]
} else {
sections[key]?.append(vehicle)
}
}
var sectionsArray: [DateSection<Element>] = []
for (timestamp, vehicles) in sections {
sectionsArray.append(DateSection<Element>(timestamp: timestamp, items: vehicles))
}
return sectionsArray.sorted { $0.timestamp > $1.timestamp }
}
}

View File

@ -27,7 +27,6 @@ struct DateSection<T>: AnimatableSectionModelType where T: IdentifiableType, T:
let weekStart = now.dateAtStartOf(.weekOfMonth)
let date = Date(timeIntervalSince1970: timestamp)
print("Date: \(date)")
if date.isToday {
self.header = "Today"
}

View File

@ -0,0 +1,5 @@
import Foundation
struct Filter {
var searchString = ""
}

View File

@ -8,23 +8,27 @@ class Api {
return NSError(domain: "", code: code, userInfo: [NSLocalizedDescriptionKey: msg, NSLocalizedRecoverySuggestionErrorKey: suggestion])
}
private static func createRequest(api: String, method: String, body: [String: Any]? = nil) -> URLRequest? {
guard let url = URL(string: baseUrl + api) else { return nil }
private static func createRequest<T>(api: String, method: String, body: [String: T]? = nil) -> URLRequest? where T: LosslessStringConvertible {
guard var urlComponents = URLComponents(string: baseUrl + api) else { return nil }
var request = URLRequest(url: url)
if let body = body, method.uppercased() == "GET" {
urlComponents.queryItems = body.map { URLQueryItem(name: $0, value: String($1)) }
}
var request = URLRequest(url: urlComponents.url!)
request.httpMethod = method
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("Bearer " + Settings.shared.user.token, forHTTPHeaderField: "Authorization")
if let body = body {
if let body = body, method.uppercased() != "GET" {
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
}
return request
}
private static func makeRequest<T>(api: String, method: String, body: [String: Any]? = nil) -> Observable<T> where T: Decodable {
private static func makeRequest<T, U>(api: String, method: String, body: [String: U]? = nil) -> Observable<T> where T: Decodable, U: LosslessStringConvertible {
guard let request = self.createRequest(api: api, method: method, body: body) else {
return Observable.error(self.genError("Error creating request", suggestion: ""))
}
@ -59,8 +63,12 @@ class Api {
return self.makeRequest(api: "user/signup", method: "POST", body: body)
}
public static func getVehicles() -> Observable<[Vehicle]> {
return self.makeRequest(api: "vehicles", method: "GET")
public static func getVehicles(with filter: Filter) -> Observable<[Vehicle]> {
let body = [
"limit": "0", // Unlimited
"query": filter.searchString
]
return self.makeRequest(api: "vehicles", method: "GET", body: body)
}
public static func checkVehicle(by number: String) -> Observable<Vehicle> {

View File

@ -8,7 +8,6 @@ class FlagLayer: CALayer {
let red = CGColor(srgbRed: 213/256.0, green: 43/256.0, blue: 30/256.0, alpha: 1)
override func draw(in ctx: CGContext) {
print("Draw in bounds: \(bounds)")
ctx.saveGState()
super.draw(in: ctx)

View File

@ -14,8 +14,17 @@ class PlateView: UIView {
private var countryLayer = CenterTextLayer()
private var flagLayer = FlagLayer()
var number: PlateNumber?
var unrecognized: Bool = false
var number: PlateNumber? {
didSet {
self.layoutSubviews()
}
}
var unrecognized: Bool = false {
didSet {
self.layoutSubviews()
}
}
required init?(coder: NSCoder) {
super.init(coder: coder)
@ -63,8 +72,6 @@ class PlateView: UIView {
let fgColor = self.unrecognized ? /*fgColorErr*/UIColor.systemRed.cgColor : fgColorMain
print("Layout for number: \(number.asString())")
self.bgLayer.backgroundColor = fgColor
self.bgLayer.frame = self.bounds