Filtering search results

This commit is contained in:
Selim Mustafaev 2020-06-20 14:34:01 +03:00
parent 9733495593
commit 579495053c
9 changed files with 426 additions and 20 deletions

View File

@ -30,9 +30,11 @@
7A11474723FF2AA500B424AF /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474623FF2AA500B424AF /* User.swift */; };
7A11474923FF2B2D00B424AF /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; };
7A11474B23FF368B00B424AF /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474A23FF368B00B424AF /* Settings.swift */; };
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADC6249D43210035F39E /* RegionsController.swift */; };
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A33381024990DAE00D878F1 /* FiltersController.swift */; };
7A333814249A532400D878F1 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A333813249A532400D878F1 /* Filter.swift */; };
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 */; };
7A43F9F8246C8A6200BA5B49 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A43F9F7246C8A6200BA5B49 /* JWT.swift */; };
7A530B78240010D900CBFE6E /* InputMask in Frameworks */ = {isa = PBXBuildFile; productRef = 7A530B77240010D900CBFE6E /* InputMask */; };
7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7924001D3300CBFE6E /* CheckController.swift */; };
@ -66,6 +68,7 @@
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A96AE2E246B2BCD00297C33 /* WebKit.framework */; };
7A96AE31246B2FE400297C33 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE30246B2FE400297C33 /* Constants.swift */; };
7A96AE33246C095700297C33 /* Base64FS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE32246C095700297C33 /* Base64FS.swift */; };
7AB562BA249C9E9B00473D53 /* Region.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB562B9249C9E9B00473D53 /* Region.swift */; };
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; };
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFE727240455E200910EB7 /* SettingsController.swift */; };
@ -92,9 +95,11 @@
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>"; };
7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = "<group>"; };
7A33381024990DAE00D878F1 /* FiltersController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersController.swift; sourceTree = "<group>"; };
7A333813249A532400D878F1 /* Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filter.swift; 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>"; };
7A43F9F7246C8A6200BA5B49 /* JWT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWT.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>"; };
@ -126,6 +131,7 @@
7A96AE2E246B2BCD00297C33 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
7A96AE30246B2FE400297C33 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
7A96AE32246C095700297C33 /* Base64FS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base64FS.swift; sourceTree = "<group>"; };
7AB562B9249C9E9B00473D53 /* Region.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Region.swift; sourceTree = "<group>"; };
7AB67E8B2435C38700258F61 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
7AEFE727240455E200910EB7 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
@ -211,6 +217,8 @@
7A3F07AC2436350B00E59687 /* SearchController.swift */,
7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */,
7A6E03272485951700DB22ED /* OwnersController.swift */,
7A33381024990DAE00D878F1 /* FiltersController.swift */,
7A27ADC6249D43210035F39E /* RegionsController.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -245,7 +253,8 @@
7A530B7F2401803A00CBFE6E /* Vehicle.swift */,
7A0516192414FF0900FC55AC /* DateSection.swift */,
7A6DD90D24337930009DE740 /* PlateNumber.swift */,
7A3F07AE24366DF900E59687 /* Filter.swift */,
7A333813249A532400D878F1 /* Filter.swift */,
7AB562B9249C9E9B00473D53 /* Region.swift */,
);
path = Models;
sourceTree = "<group>";
@ -439,12 +448,14 @@
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */,
7AB562BA249C9E9B00473D53 /* Region.swift in Sources */,
7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */,
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */,
7A6DD90E24337930009DE740 /* PlateNumber.swift in Sources */,
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */,
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */,
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */,
7A11474923FF2B2D00B424AF /* Response.swift in Sources */,
7A64AE762469DFB600ABE48E /* ContentTransformers.swift in Sources */,
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */,
@ -467,10 +478,11 @@
7A11474423FF06CA00B424AF /* Api.swift in Sources */,
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */,
7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */,
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */,
7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */,
7A333814249A532400D878F1 /* Filter.swift in Sources */,
7A11474B23FF368B00B424AF /* Settings.swift in Sources */,
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
7A3F07AF24366DF900E59687 /* Filter.swift in Sources */,
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
7A64AE812469E16100ABE48E /* ProgressAnimatedView.swift in Sources */,
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
@ -619,7 +631,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 15;
CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@ -641,7 +653,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 15;
CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;

View File

@ -223,14 +223,14 @@
<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"/>
<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"/>
<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"/>
<rect key="frame" x="8" y="8" width="124" height="21.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -242,7 +242,7 @@
<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" width="317" height="40"/>
<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"/>
@ -280,15 +280,92 @@
</constraints>
<viewLayoutGuide key="safeArea" id="6Uh-9i-MKR"/>
</view>
<navigationItem key="navigationItem" id="kEp-Rw-7hu"/>
<navigationItem key="navigationItem" id="kEp-Rw-7hu">
<barButtonItem key="backBarButtonItem" title="Back" id="7QQ-Qi-qEw"/>
<barButtonItem key="rightBarButtonItem" image="line.horizontal.3.decrease" catalog="system" id="mvq-Q5-tVc">
<connections>
<action selector="onFilter:" destination="UPf-uT-oOr" id="z2g-n9-tJ0"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="tableView" destination="dB3-iP-QRo" id="b3n-R9-6lI"/>
<segue destination="xtc-Md-WHl" kind="show" id="XGo-Dt-MEf"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="xsk-7S-rvc" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4200.8000000000002" y="142.57871064467767"/>
</scene>
<!--Filters-->
<scene sceneID="guf-tR-b25">
<objects>
<viewController storyboardIdentifier="FiltersController" id="xtc-Md-WHl" customClass="FiltersController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="ACq-OO-MJ9">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="tol-Qd-fB2"/>
</view>
<toolbarItems/>
<navigationItem key="navigationItem" title="Filters" id="U4X-4i-ZJm">
<barButtonItem key="rightBarButtonItem" systemItem="done" id="z1q-3D-LSC">
<connections>
<action selector="onDone:" destination="xtc-Md-WHl" id="SaN-2o-frs"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
<connections>
<segue destination="mwd-dq-ihi" kind="show" id="n3A-4T-cFK"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bdg-V0-dfn" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4940" y="144"/>
</scene>
<!--Regions Controller-->
<scene sceneID="Aej-R9-1fN">
<objects>
<viewController storyboardIdentifier="RegionsController" hidesBottomBarWhenPushed="YES" id="mwd-dq-ihi" customClass="RegionsController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="d0c-Nb-ZHe">
<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="grouped" separatorStyle="default" allowsMultipleSelection="YES" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="zEt-R6-oSY">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<connections>
<outlet property="delegate" destination="mwd-dq-ihi" id="q6l-kV-3Og"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="zEt-R6-oSY" firstAttribute="leading" secondItem="d0c-Nb-ZHe" secondAttribute="leading" id="muf-Z6-ce5"/>
<constraint firstItem="zEt-R6-oSY" firstAttribute="top" secondItem="d0c-Nb-ZHe" secondAttribute="top" id="qkW-ZF-ZjV"/>
<constraint firstAttribute="bottom" secondItem="zEt-R6-oSY" secondAttribute="bottom" id="vHZ-rp-tcD"/>
<constraint firstAttribute="trailing" secondItem="zEt-R6-oSY" secondAttribute="trailing" id="x0p-bT-D5f"/>
</constraints>
<viewLayoutGuide key="safeArea" id="TQH-W9-FD9"/>
</view>
<toolbarItems/>
<navigationItem key="navigationItem" id="bUY-8e-NfY">
<barButtonItem key="rightBarButtonItem" systemItem="done" id="w1V-C0-NZn">
<connections>
<action selector="onDone:" destination="mwd-dq-ihi" id="DbN-Ih-WZH"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
<connections>
<outlet property="tableView" destination="zEt-R6-oSY" id="UPW-kx-wwM"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="p1i-aS-QZU" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5688.8000000000002" y="142.57871064467767"/>
</scene>
<!--Settings-->
<scene sceneID="G47-o0-Caa">
<objects>
@ -634,6 +711,7 @@
<image name="eye" catalog="system" width="128" height="81"/>
<image name="eye.fill" catalog="system" width="128" height="78"/>
<image name="gear" catalog="system" width="128" height="119"/>
<image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/>
<image name="magnifyingglass" catalog="system" width="128" height="115"/>
</resources>
</document>

View File

@ -0,0 +1,123 @@
import UIKit
import Eureka
import RxSwift
class FiltersController: FormViewController {
var done = false
var filter: Filter!
var onDone: (() -> Void)?
var regions: [Region] = []
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
form +++ Section("Main filters") { $0.tag = "MainFilters" }
<<< PushRow<String>("Brand") { row in
row.title = "Brand"
row.value = self.filter.brand ?? "Any"
row.selectorTitle = "Brands"
row.optionsProvider = .lazy({ form, completion in
Api.getBrands().observeOn(MainScheduler.instance).subscribe(onNext: { brands in
completion(["Any"] + brands)
}, onError: { error in
print("Get brands error: ", error)
}).disposed(by: self.bag)
})
}.onPresent(removeSectionName(from:to:))
.onChange { self.filter.brand = $0.value == "Any" ? nil : $0.value }
.cellUpdate { $1.value = self.filter.brand ?? "Any" }
<<< PushRow<String>("Model") { row in
row.title = "Model"
row.value = self.filter.model ?? "Any"
row.disabled = "$Brand == 'Any'"
row.optionsProvider = .lazy({ form, completion in
guard let brand = self.filter.brand else {
completion(["Any"])
return
}
Api.getModels(of: brand).observeOn(MainScheduler.instance).subscribe(onNext: { models in
completion(["Any"] + models)
}, onError: { error in
print("Get models error: ", error)
}).disposed(by: self.bag)
})
}.onPresent(removeSectionName(from:to:))
.onChange { self.filter.model = $0.value == "Any" ? nil : $0.value }
.cellUpdate { $1.value = self.filter.model ?? "Any" }
<<< PushRow<String>("Color") { row in
row.title = "Color"
row.value = self.filter.color ?? "Any"
row.optionsProvider = .lazy({ form, completion in
Api.getColors().observeOn(MainScheduler.instance).subscribe(onNext: { colors in
completion(["Any"] + colors)
}, onError: { error in
print("Get colors error: ", error)
}).disposed(by: self.bag)
})
}.onPresent(removeSectionName(from:to:))
.onChange { self.filter.color = $0.value == "Any" ? nil : $0.value }
.cellUpdate { $1.value = self.filter.color ?? "Any" }
form +++ Section() { $0.tag = "Regions" }
<<< LabelRow("RegionsRow") { row in
row.title = "Regions"
row.value = self.filter.regions?.map(String.init).joined(separator: ",") ?? "Any"
row.cellUpdate { cell, _ in
cell.accessoryType = .disclosureIndicator
}
}
.onCellSelection { cell, row in
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(identifier: "RegionsController") as RegionsController
vc.regionCodes = self.filter.regions ?? []
vc.onDone = { regions in
row.value = regions?.map(String.init).joined(separator: ",") ?? "Any"
self.filter.regions = regions
}
self.navigationController?.pushViewController(vc, animated: true)
}
form +++ Section()
<<< ButtonRow("ClearAll") { $0.title = "Clear all filters" }.onCellSelection { cell, row in
self.filter.clear()
if let section = self.form.sectionBy(tag: "MainFilters") {
// For some reason certain cells do not redraw after first reload
section.reload()
section.reload()
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.done = false
}
// override func viewDidDisappear(_ animated: Bool) {
// super.viewDidDisappear(animated)
// if self.done {
// self.onDone?()
// }
// }
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.done {
self.onDone?()
}
}
@IBAction func onDone(_ sender: UIBarButtonItem) {
self.done = true
self.navigationController?.popViewController(animated: true)
}
func removeSectionName(from: FormViewController, to: SelectorViewController<SelectorRow<PushSelectorCell<String>>>) {
to.sectionKeyForValue = { _ in "" }
}
}

View File

@ -0,0 +1,128 @@
import UIKit
import RxSwift
class RegionsDataSourse: UITableViewDiffableDataSource<Region, Int> {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return snapshot().sectionIdentifiers[section].name
}
}
class RegionsController: UIViewController, UISearchResultsUpdating, UITableViewDelegate {
@IBOutlet weak var tableView: UITableView!
var regions: [Region] = []
var regionsFiltered: [Region] = []
var done = false
var onDone: (([Int]?) -> Void)?
var regionCodes: [Int] = []
var datasource: RegionsDataSourse!
let searchController = UISearchController(searchResultsController: nil)
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search regions"
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
definesPresentationContext = true
self.datasource = RegionsDataSourse(tableView: self.tableView) { tableView, indexPath, code -> UITableViewCell? in
var cell = tableView.dequeueReusableCell(withIdentifier: "RegionCell")
if cell == nil {
cell = UITableViewCell(style: .value1, reuseIdentifier: "RegionCell")
}
let selectedIndexPaths = tableView.indexPathsForSelectedRows
let rowIsSelected = selectedIndexPaths != nil && selectedIndexPaths!.contains(indexPath)
cell?.accessoryType = rowIsSelected ? .checkmark : .none
cell?.selectionStyle = .none
cell?.textLabel?.text = String(code)
return cell
}
Api.getRegions().observeOn(MainScheduler.instance).subscribe(onNext: { regions in
self.regions = regions
self.regionsFiltered = regions
self.updateTableView()
self.applySelection()
}, onError: { error in
print("Get regions error: ", error)
}).disposed(by: self.bag)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.done {
self.onDone?(self.regionCodes)
}
}
@IBAction func onDone(_ sender: UIBarButtonItem) {
self.done = true
self.navigationController?.popViewController(animated: true)
}
func updateTableView() {
var snapshot = NSDiffableDataSourceSnapshot<Region, Int>()
snapshot.appendSections(self.regionsFiltered)
for region in self.regionsFiltered {
snapshot.appendItems(region.codes, toSection: region)
}
self.datasource.apply(snapshot);
}
func applySelection() {
self.regionCodes.forEach { code in
if let section = self.regionsFiltered.firstIndex(where: { $0.codes.contains(code) }) {
if let row = self.regionsFiltered[section].codes.firstIndex(of: code) {
let indexPath = IndexPath(row: row, section: section)
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .middle)
let cell = tableView.cellForRow(at: indexPath)!
cell.accessoryType = .checkmark
}
}
}
}
// MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)!
cell.accessoryType = .checkmark
if let codeStr = cell.textLabel?.text, let code = Int(codeStr) {
if !self.regionCodes.contains(code) {
self.regionCodes.append(code)
}
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)!
cell.accessoryType = .none
if let codeStr = cell.textLabel?.text, let code = Int(codeStr) {
self.regionCodes.removeAll(where: { $0 == code })
}
}
// MARK: - UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
let newQuery = searchController.searchBar.text?.uppercased() ?? ""
if newQuery.isEmpty {
self.regionsFiltered = self.regions
} else {
self.regionsFiltered = self.regions.filter { $0.name.lowercased().contains(newQuery.lowercased()) }
}
self.updateTableView()
self.applySelection()
}
}

View File

@ -81,4 +81,17 @@ class SearchController: UIViewController, UISearchResultsUpdating {
self.filter.searchString = newQuery
self.filterRelay.accept(self.filter)
}
// MARK: -
@IBAction func onFilter(_ sender: UIBarButtonItem) {
let sb = UIStoryboard(name: "Main", bundle: nil)
let controller = sb.instantiateViewController(identifier: "FiltersController") as FiltersController
controller.filter = self.filter
controller.onDone = {
self.filter = controller.filter
self.filterRelay.accept(self.filter)
}
self.navigationController?.pushViewController(controller, animated: true)
}
}

View File

@ -2,4 +2,34 @@ import Foundation
struct Filter {
var searchString = ""
var brand: String?
var model: String?
var color: String?
var regions: [Int]?
mutating func clear() {
self.brand = nil
self.model = nil
self.color = nil
self.regions = nil
}
func queryDictionary() -> [String: String] {
var dict: [String: String] = ["query": self.searchString]
if let brand = self.brand {
dict["brand"] = brand
}
if let model = self.model {
dict["model"] = model
}
if let color = self.color {
dict["color"] = color
}
if let regions = self.regions {
dict["regions"] = regions.map(String.init).joined(separator: ",")
}
return dict
}
}

View File

@ -0,0 +1,10 @@
import Foundation
struct Region: Codable, Hashable {
var name: String
var codes: [Int]
static func == (lhs: Region, rhs: Region) -> Bool {
return lhs.name == rhs.name
}
}

View File

@ -6,7 +6,7 @@ class Api {
return NSError(domain: "", code: code, userInfo: [NSLocalizedDescriptionKey: msg, NSLocalizedRecoverySuggestionErrorKey: suggestion])
}
private static func createRequest<T>(api: String, method: String, body: [String: T]? = nil) -> URLRequest? where T: LosslessStringConvertible {
private static func createRequest(api: String, method: String, body: [String: String]? = nil) -> URLRequest? {
guard var urlComponents = URLComponents(string: Constants.baseUrl + api) else { return nil }
if let body = body, method.uppercased() == "GET" {
@ -26,7 +26,7 @@ class Api {
return request
}
private static func makeRequest<T, U>(api: String, method: String, body: [String: U]? = nil) -> Observable<T> where T: Decodable, U: LosslessStringConvertible {
private static func makeRequest<T>(api: String, method: String = "GET", body: [String: String]? = nil) -> Observable<T> where T: Decodable {
guard let request = self.createRequest(api: api, method: method, body: body) else {
return Observable.error(self.genError("Error creating request", suggestion: ""))
}
@ -100,11 +100,7 @@ class Api {
}
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)
return self.makeRequest(api: "vehicles", method: "GET", body: filter.queryDictionary())
}
public static func checkVehicle(by number: String, force: Bool = false) -> Observable<Vehicle> {
@ -122,4 +118,20 @@ class Api {
}
}
}
public static func getBrands() -> Observable<[String]> {
return self.makeRequest(api: "vehicles/brands")
}
public static func getModels(of brand: String) -> Observable<[String]> {
return self.makeRequest(api: "vehicles/models", body: ["brand": brand])
}
public static func getColors() -> Observable<[String]> {
return self.makeRequest(api: "vehicles/colors")
}
public static func getRegions() -> Observable<[Region]> {
return self.makeRequest(api: "vehicles/regions")
}
}

View File

@ -3,8 +3,8 @@ import Foundation
enum Constants {
static var baseUrl: String {
#if DEBUG
//return "http://127.0.0.1:3000/"
return "https://vps.aliencat.pro:8443/"
return "http://127.0.0.1:3000/"
//return "https://vps.aliencat.pro:8443/"
#else
return "https://vps.aliencat.pro:8443/"
#endif