Added app icon (temporary)

added viewer controller for vehicle photos
added logout functionality
This commit is contained in:
Selim Mustafaev 2020-02-25 00:11:46 +03:00
parent 64cb79360f
commit 4df15702b3
18 changed files with 278 additions and 42 deletions

View File

@ -39,6 +39,8 @@
7A7547DD2403180A004E8406 /* SectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DB2403180A004E8406 /* SectionHeader.swift */; };
7A7547DE2403180A004E8406 /* SectionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7A7547DC2403180A004E8406 /* SectionHeader.xib */; };
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */; };
7A92D0AC240425B200EF3B77 /* ATGMediaBrowser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */; };
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFE727240455E200910EB7 /* SettingsController.swift */; };
7AF58D2F24029C5200CE01A0 /* MagazineLayout in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D2E24029C5200CE01A0 /* MagazineLayout */; };
7AF58D3124029E1000CE01A0 /* VehicleHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF58D3024029E1000CE01A0 /* VehicleHeaderCell.swift */; };
7AF58D342402A91C00CE01A0 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D332402A91C00CE01A0 /* Kingfisher */; };
@ -71,6 +73,8 @@
7A7547DB2403180A004E8406 /* SectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeader.swift; sourceTree = "<group>"; };
7A7547DC2403180A004E8406 /* SectionHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SectionHeader.xib; sourceTree = "<group>"; };
7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehiclePhotoCell.swift; sourceTree = "<group>"; };
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; };
7AEFE727240455E200910EB7 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
7AF58D3024029E1000CE01A0 /* VehicleHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleHeaderCell.swift; sourceTree = "<group>"; };
7AF58D57240309CA00CE01A0 /* VehicleTextParamCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleTextParamCell.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -89,6 +93,7 @@
7A11472B23FEA24D00B424AF /* Action in Frameworks */,
7A11471F23FEA18700B424AF /* RxRelay in Frameworks */,
7AF58D2F24029C5200CE01A0 /* MagazineLayout in Frameworks */,
7A92D0AC240425B200EF3B77 /* ATGMediaBrowser.framework in Frameworks */,
7A530B78240010D900CBFE6E /* InputMask in Frameworks */,
7A11471D23FEA18700B424AF /* RxSwift in Frameworks */,
7A11472623FEA1F400B424AF /* Realm in Frameworks */,
@ -140,6 +145,7 @@
7A11471723FDEBFA00B424AF /* ReportController.swift */,
7A11471923FE839000B424AF /* AuthController.swift */,
7A530B7924001D3300CBFE6E /* CheckController.swift */,
7AEFE727240455E200910EB7 /* SettingsController.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -174,6 +180,7 @@
7A11474C23FFEE8700B424AF /* Frameworks */ = {
isa = PBXGroup;
children = (
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */,
7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */,
);
name = Frameworks;
@ -323,6 +330,7 @@
7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */,
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
7A530B86240180CC00CBFE6E /* RealmBindObserver.swift in Sources */,
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */,
7A11474923FF2B2D00B424AF /* Response.swift in Sources */,
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */,
7A11471A23FE839000B424AF /* AuthController.swift in Sources */,

View File

@ -24,21 +24,5 @@
stopOnStyle = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "DFB5CF8A-D7CD-4328-BF19-E491CF2CE141"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Models/Response.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "22"
endingLineNumber = "22"
landmarkName = "init(from:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -18,7 +18,7 @@
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="rG3-ze-Zre">
<rect key="frame" x="0.0" y="44" width="375" height="623"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemGroupedBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" automaticEstimatedItemSize="YES" minimumLineSpacing="10" minimumInteritemSpacing="10" id="w9q-DU-Wac">
<size key="itemSize" width="303" height="85"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
@ -116,38 +116,39 @@
<rect key="frame" x="0.0" y="0.0" width="303" height="264"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="wgf-C8-UOE">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="wgf-C8-UOE">
<rect key="frame" x="0.0" y="0.0" width="303" height="198"/>
<constraints>
<constraint firstAttribute="width" secondItem="wgf-C8-UOE" secondAttribute="height" multiplier="101:66" id="OzD-Ts-mnv"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1HU-6D-JSt">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1HU-6D-JSt">
<rect key="frame" x="8" y="206" width="287" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l3q-fD-P3R">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l3q-fD-P3R">
<rect key="frame" x="8" y="235" width="287" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<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>
</subviews>
<constraints>
<constraint firstItem="1HU-6D-JSt" firstAttribute="top" secondItem="wgf-C8-UOE" secondAttribute="bottom" constant="8" id="2nP-F6-Jr9"/>
<constraint firstItem="1HU-6D-JSt" firstAttribute="top" secondItem="wgf-C8-UOE" secondAttribute="bottom" constant="4" id="2nP-F6-Jr9"/>
<constraint firstAttribute="trailing" secondItem="1HU-6D-JSt" secondAttribute="trailing" constant="8" id="AI8-D3-c49"/>
<constraint firstItem="l3q-fD-P3R" firstAttribute="top" secondItem="1HU-6D-JSt" secondAttribute="bottom" constant="8" id="Gxd-mq-F5c"/>
<constraint firstItem="l3q-fD-P3R" firstAttribute="top" secondItem="1HU-6D-JSt" secondAttribute="bottom" constant="4" id="Gxd-mq-F5c"/>
<constraint firstAttribute="trailing" secondItem="wgf-C8-UOE" secondAttribute="trailing" id="Moc-ou-hry"/>
<constraint firstAttribute="trailing" secondItem="l3q-fD-P3R" secondAttribute="trailing" constant="8" id="QwX-uc-3NV"/>
<constraint firstItem="1HU-6D-JSt" firstAttribute="leading" secondItem="AMu-PZ-gGR" secondAttribute="leading" constant="8" id="SAN-qq-lXm"/>
<constraint firstAttribute="bottom" secondItem="l3q-fD-P3R" secondAttribute="bottom" constant="8" id="TcR-1f-apo"/>
<constraint firstAttribute="bottom" secondItem="l3q-fD-P3R" secondAttribute="bottom" constant="4" id="TcR-1f-apo"/>
<constraint firstItem="wgf-C8-UOE" firstAttribute="leading" secondItem="AMu-PZ-gGR" secondAttribute="leading" id="jVo-O5-SX5"/>
<constraint firstItem="wgf-C8-UOE" firstAttribute="top" secondItem="AMu-PZ-gGR" secondAttribute="top" id="k1d-ot-dij"/>
<constraint firstItem="l3q-fD-P3R" firstAttribute="leading" secondItem="AMu-PZ-gGR" secondAttribute="leading" constant="8" id="u0P-VY-lFV"/>
</constraints>
</collectionViewCellContentView>
<color key="backgroundColor" cocoaTouchSystemColor="tableCellGroupedBackgroundColor"/>
<size key="customSize" width="303" height="264"/>
<connections>
<outlet property="date" destination="l3q-fD-P3R" id="rEm-YK-xrw"/>
@ -199,18 +200,35 @@
<!--Settings-->
<scene sceneID="G47-o0-Caa">
<objects>
<viewController id="4jU-Z3-PF2" sceneMemberID="viewController">
<viewController id="4jU-Z3-PF2" customClass="SettingsController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="NFd-we-MVH">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Te-C0-b8T">
<rect key="frame" x="16" y="20" width="343" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="Xak-Dx-nTf"/>
</constraints>
<state key="normal" title="Logout"/>
<connections>
<action selector="logout:" destination="4jU-Z3-PF2" eventType="touchUpInside" id="RSM-Bp-2sN"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="Uix-8K-fxh" firstAttribute="trailing" secondItem="8Te-C0-b8T" secondAttribute="trailing" constant="16" id="DsI-gO-q9W"/>
<constraint firstItem="8Te-C0-b8T" firstAttribute="top" secondItem="Uix-8K-fxh" secondAttribute="top" constant="20" id="J43-Oo-kme"/>
<constraint firstItem="8Te-C0-b8T" firstAttribute="leading" secondItem="Uix-8K-fxh" secondAttribute="leading" constant="16" id="iSk-SC-T1w"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Uix-8K-fxh"/>
</view>
<tabBarItem key="tabBarItem" title="Settings" image="gear" catalog="system" id="zEL-ph-E2f"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="trD-gZ-yAv" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3262" y="893"/>
<point key="canvasLocation" x="3261.5999999999999" y="892.80359820089961"/>
</scene>
<!--Check Controller-->
<scene sceneID="t7Z-yv-ZLH">
@ -424,6 +442,7 @@
<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="AB1-mO-dFT"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="xYU-vW-bpS" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>

View File

@ -3,10 +3,16 @@ import MagazineLayout
class SectionHeader: MagazineLayoutCollectionReusableView {
@IBOutlet weak var title: UILabel!
@IBOutlet weak var divider: UIView!
@IBOutlet weak var dividerHeightConstraint: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
self.dividerHeightConstraint.constant = 1/UIScreen.main.scale
}
func configure(with section: ReportSection) {
self.title.text = section.description
self.divider.isHidden = section == .photos
}
}

View File

@ -14,7 +14,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FPf-35-HkN">
<rect key="frame" x="16" y="8" width="288" height="34"/>
<rect key="frame" x="16" y="24" width="288" height="18"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -34,11 +34,12 @@
<constraint firstItem="VXr-Tz-HHm" firstAttribute="trailing" secondItem="co2-Tz-MXm" secondAttribute="trailing" id="GTl-lK-7Be"/>
<constraint firstItem="co2-Tz-MXm" firstAttribute="leading" secondItem="VXr-Tz-HHm" secondAttribute="leading" id="Hzk-ur-lNg"/>
<constraint firstItem="FPf-35-HkN" firstAttribute="leading" secondItem="U6b-Vx-4bR" secondAttribute="leading" constant="16" id="MeA-dL-PeZ"/>
<constraint firstItem="FPf-35-HkN" firstAttribute="top" secondItem="U6b-Vx-4bR" secondAttribute="top" constant="8" id="P1f-gG-3TZ"/>
<constraint firstItem="FPf-35-HkN" firstAttribute="top" secondItem="U6b-Vx-4bR" secondAttribute="top" constant="24" id="P1f-gG-3TZ"/>
<constraint firstItem="VXr-Tz-HHm" firstAttribute="bottom" secondItem="FPf-35-HkN" secondAttribute="bottom" constant="8" id="han-2D-OPQ"/>
</constraints>
<viewLayoutGuide key="safeArea" id="VXr-Tz-HHm"/>
<connections>
<outlet property="divider" destination="co2-Tz-MXm" id="0C5-OK-vyS"/>
<outlet property="dividerHeightConstraint" destination="6Y8-H1-th4" id="fQS-Xf-i5n"/>
<outlet property="title" destination="FPf-35-HkN" id="yr1-mY-pnu"/>
</connections>

View File

@ -7,6 +7,15 @@ class VehiclePhotoCell: MagazineLayoutCollectionViewCell {
@IBOutlet weak var model: UILabel!
@IBOutlet weak var date: UILabel!
let formatter = DateFormatter()
override func awakeFromNib() {
super.awakeFromNib()
self.layer.cornerRadius = 8
formatter.timeStyle = .none
formatter.dateStyle = .medium
}
override func prepareForReuse() {
super.prepareForReuse()
self.photo.kf.cancelDownloadTask()
@ -18,5 +27,8 @@ class VehiclePhotoCell: MagazineLayoutCollectionViewCell {
}
self.model.text = "\(photoModel.brand ?? "") \(photoModel.model ?? "")"
let date = Date(timeIntervalSince1970: photoModel.date/1000)
self.date.text = formatter.string(from: date)
}
}

View File

@ -2,6 +2,7 @@ import UIKit
import RxSwift
import RxCocoa
import SVProgressHUD
import RealmSwift
class AuthController: UIViewController {
@ -22,6 +23,10 @@ class AuthController: UIViewController {
authValid.bind(to: self.login.rx.isEnabled).disposed(by: self.bag)
authValid.bind(to: self.signup.rx.isEnabled).disposed(by: self.bag)
if Settings.shared.user.login.count > 0 {
self.username.text = Settings.shared.user.login
}
}
@IBAction func loginTapped(_ sender: UIButton) {
@ -45,7 +50,19 @@ class AuthController: UIViewController {
}
func goToMainScreen(user: User) {
guard let realm = try? Realm() else {
SVProgressHUD.showError(withStatus: "Database error")
return
}
SVProgressHUD.dismiss()
if user.login != Settings.shared.user.login {
try? realm.write {
realm.deleteAll()
}
}
Settings.shared.user = user
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.view.window?.rootViewController = storyboard.instantiateViewController(identifier: "MainSplitController")

View File

@ -27,7 +27,7 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener {
ds.headerTitle = "History"
let realm = try! Realm()
Observable.changeset(from: realm.objects(Vehicle.self))
Observable.changeset(from: realm.objects(Vehicle.self).sorted(byKeyPath: "addedDate", ascending: false))
.bind(to: self.history.rx.realmChanges(ds))
.disposed(by: self.bag)

View File

@ -1,17 +1,21 @@
import UIKit
import MagazineLayout
import ATGMediaBrowser
import Kingfisher
enum ReportSection: Int, CaseIterable, CustomStringConvertible {
case header = 0
case general = 1
case identifiers = 2
case photos = 3
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"
}
}
@ -49,7 +53,25 @@ enum ReportIdSection: Int, CaseIterable, CustomStringConvertible {
}
}
class ReportController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateMagazineLayout {
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!
@ -81,6 +103,7 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
// MARK: - UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
guard self.vehicle != nil else { return 0 }
return ReportSection.allCases.count
}
@ -92,6 +115,7 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
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
}
}
@ -142,6 +166,28 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
}
}
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]
@ -155,12 +201,21 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
guard let section = ReportSection(rawValue: indexPath.section) else { return UICollectionReusableView() }
if let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionHeader", for: indexPath) as? SectionHeader {
sectionHeader.title.text = section.description
sectionHeader.configure(with: section)
return sectionHeader
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard indexPath.section == ReportSection.photos.rawValue else { return }
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)
}
// MARK: - UICollectionViewDelegateMagazineLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeModeForItemAt indexPath: IndexPath) -> MagazineLayoutItemSizeMode
@ -170,7 +225,10 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
case .header: return self.fullWidth
case .general: return self.fullWidth
case .identifiers: return self.fullWidth
case .photos: return .init(widthMode: .thirdWidth, heightMode: .dynamic)
case .engine: return self.fullWidth
case .photos:
let wMode: MagazineLayoutItemWidthMode = self.traitCollection.horizontalSizeClass != .compact ? .thirdWidth : .halfWidth
return .init(widthMode: wMode, heightMode: .dynamic)
}
}
@ -181,6 +239,7 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
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)
}
}
@ -202,16 +261,46 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, verticalSpacingForElementsInSectionAtIndex index: Int) -> CGFloat
{
return 0
return index == ReportSection.photos.rawValue ? 16 : 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForSectionAtIndex index: Int) -> UIEdgeInsets
{
return .zero
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 .zero
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: ATGMediaBrowser.MediaBrowserViewController, didChangeFocusTo index: Int) {
guard let photo = self.vehicle?.photos[index] else { return }
mediaBrowser.title = photo.description
}
}

View File

@ -0,0 +1,16 @@
import UIKit
class SettingsController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func logout(_ sender: UIButton) {
Settings.shared.user.token = ""
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.view.window?.rootViewController = storyboard.instantiateViewController(identifier: "AuthController")
}
}

View File

@ -2,6 +2,26 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>platesmania.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>avto-nomer.ru</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>

View File

@ -2,7 +2,7 @@ import Foundation
class User: Codable {
let login: String
let token: String
var token: String
init() {
self.login = ""

View File

@ -26,8 +26,17 @@ class VehicleEngine: Object, Decodable {
class VehiclePhoto: Object, Decodable {
@objc dynamic var brand: String?
@objc dynamic var model: String?
@objc dynamic var date: Int64 = 0
@objc dynamic var date: TimeInterval = 0
@objc dynamic var url: String = ""
override var description: String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
let date = Date(timeIntervalSince1970: self.date/1000)
let dateStr = formatter.string(from: date)
return "\(self.brand ?? "") \(self.model ?? "") (\(dateStr))"
}
}
class Vehicle: Object, Decodable {
@ -45,7 +54,55 @@ class Vehicle: Object, Decodable {
@objc dynamic var pts: String?
@objc dynamic var isRightWheel: Bool = false
@objc dynamic var isJapanese: Bool = false
@objc dynamic var addedDate: Int64 = 0
@objc dynamic var addedDate: TimeInterval = 0
@objc dynamic var addedBy: String = ""
let photos = List<VehiclePhoto>()
enum CodingKeys: String, CodingKey {
case _id
case brand
case model
case color
case year
case category
case engine
case number
case vin1
case vin2
case sts
case pts
case isRightWheel
case isJapanese
case addedDate
case addedBy
case photos
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self._id = try container.decode(String.self, forKey: ._id)
self.brand = try container.decodeIfPresent(VehicleBrand.self, forKey: .brand)
self.model = try container.decodeIfPresent(VehicleModel.self, forKey: .model)
self.color = try container.decodeIfPresent(String.self, forKey: .color)
self.year = try container.decode(Int.self, forKey: .year)
self.category = try container.decodeIfPresent(String.self, forKey: .category)
self.engine = try container.decodeIfPresent(VehicleEngine.self, forKey: .engine)
self.number = try container.decode(String.self, forKey: .number)
self.vin1 = try container.decodeIfPresent(String.self, forKey: .vin1)
self.vin2 = try container.decodeIfPresent(String.self, forKey: .vin2)
self.sts = try container.decodeIfPresent(String.self, forKey: .sts)
self.pts = try container.decodeIfPresent(String.self, forKey: .pts)
self.isRightWheel = try container.decode(Bool.self, forKey: .isRightWheel)
self.isJapanese = try container.decode(Bool.self, forKey: .isJapanese)
self.addedDate = try container.decode(TimeInterval.self, forKey: .addedDate)
self.addedBy = try container.decode(String.self, forKey: .addedBy)
if let photosArray = try container.decodeIfPresent([VehiclePhoto].self, forKey: .photos) {
self.photos.append(objectsIn: photosArray)
}
}
required init() {
}
}

View File

@ -64,6 +64,9 @@ class Api {
}
public static func checkVehicle(by number: String) -> Observable<Vehicle> {
return self.makeRequest(api: "vehicles/check", method: "POST", body: ["number": number])
return self.makeRequest(api: "vehicles/check", method: "POST", body: ["number": number]).map { (vehicle: Vehicle) -> Vehicle in
vehicle.addedDate = Date().timeIntervalSince1970*1000
return vehicle
}
}
}

View File

@ -1 +1,2 @@
github "selim-mustafaev/SVProgressHUD" "ios13-support"
github "altayer-digital/ATGMediaBrowser" "master"

View File

@ -1 +1,2 @@
github "altayer-digital/ATGMediaBrowser" "8afc2957ab218ab650fcb538256f118b79ae92bd"
github "selim-mustafaev/SVProgressHUD" "17b1eacb2800ffa91eb5fb12e1a5983dba29f9dc"

View File

@ -1 +1,2 @@
$(SRCROOT)/Carthage/Build/iOS/SVProgressHUD.framework
$(SRCROOT)/Carthage/Build/iOS/ATGMediaBrowser.framework

View File

@ -1 +1,2 @@
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SVProgressHUD.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ATGMediaBrowser.framework