Replacing report screen with swiftui version

This commit is contained in:
Selim Mustafaev 2024-12-08 13:29:31 +03:00
parent 37b94aca62
commit 49b3f90f4c
12 changed files with 54 additions and 1147 deletions

View File

@ -29,7 +29,6 @@
7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470923FDE7E600B424AF /* Assets.xcassets */; };
7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470B23FDE7E600B424AF /* LaunchScreen.storyboard */; };
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471523FDEB2A00B424AF /* MainSplitController.swift */; };
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471723FDEBFA00B424AF /* ReportController.swift */; };
7A11471A23FE839000B424AF /* AuthController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471923FE839000B424AF /* AuthController.swift */; };
7A1441662C297EDE00E79018 /* NotesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1441652C297EDE00E79018 /* NotesScreen.swift */; };
7A1441682C297EFD00E79018 /* NotesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1441672C297EFD00E79018 /* NotesViewModel.swift */; };
@ -47,14 +46,12 @@
7A1E78FF2CE91A740004B740 /* Vehicle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78FE2CE91A740004B740 /* Vehicle.swift */; };
7A22B6ED2C67FDEA00E60173 /* SwiftLocationMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A22B6EB2C67FDEA00E60173 /* SwiftLocationMock.swift */; };
7A22B6EE2C67FDEA00E60173 /* GeocoderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A22B6EA2C67FDEA00E60173 /* GeocoderMock.swift */; };
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADC6249D43210035F39E /* RegionsController.swift */; };
7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF2249F8B650035F39E /* RecordsController.swift */; };
7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */; };
7A27ADF7249FEF690035F39E /* Recorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF6249FEF690035F39E /* Recorder.swift */; };
7A2C96122C3B155B00AE46B5 /* NoteAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2C96112C3B155B00AE46B5 /* NoteAlertModifier.swift */; };
7A2E11292CCE395300E5CA17 /* OptionalDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */; };
7A2E6FA72C42B3AD00C40DA7 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; };
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A33381024990DAE00D878F1 /* FiltersController.swift */; };
7A3399AB299063370087DF98 /* SearchControllerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3399AA299063370087DF98 /* SearchControllerExt.swift */; };
7A35177B27E23F8800DC538C /* Eureka in Frameworks */ = {isa = PBXBuildFile; productRef = 7A35177A27E23F8800DC538C /* Eureka */; };
7A3E12D72C7B42B700EE710D /* UserDefaults+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3E12D62C7B42B700EE710D /* UserDefaults+Settings.swift */; };
@ -66,7 +63,6 @@
7A4322952CB2CD0F00085CF6 /* FiltersCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4322942CB2CD0F00085CF6 /* FiltersCoordinator.swift */; };
7A45FB382C27073700618694 /* StorageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A45FB372C27073700618694 /* StorageService.swift */; };
7A4927D52CCE438600851C01 /* OptionalBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4927D42CCE438600851C01 /* OptionalBinding.swift */; };
7A4927D72CCEA6DC00851C01 /* VMResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4927D62CCEA6DC00851C01 /* VMResult.swift */; };
7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7924001D3300CBFE6E /* CheckController.swift */; };
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */; };
7A599C362C18AC7F00D47C18 /* ApiError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A599C352C18AC7F00D47C18 /* ApiError.swift */; };
@ -288,7 +284,6 @@
7A11470C23FDE7E600B424AF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
7A11470E23FDE7E600B424AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7A11471523FDEB2A00B424AF /* MainSplitController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitController.swift; sourceTree = "<group>"; };
7A11471723FDEBFA00B424AF /* ReportController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportController.swift; sourceTree = "<group>"; };
7A11471923FE839000B424AF /* AuthController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthController.swift; sourceTree = "<group>"; };
7A11474323FF06CA00B424AF /* ApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiService.swift; sourceTree = "<group>"; };
7A11474623FF2AA500B424AF /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
@ -311,7 +306,6 @@
7A1E78FE2CE91A740004B740 /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = "<group>"; };
7A22B6EA2C67FDEA00E60173 /* GeocoderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeocoderMock.swift; sourceTree = "<group>"; };
7A22B6EB2C67FDEA00E60173 /* SwiftLocationMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftLocationMock.swift; sourceTree = "<group>"; };
7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = "<group>"; };
7A27ADF2249F8B650035F39E /* RecordsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsController.swift; sourceTree = "<group>"; };
7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExt.swift; sourceTree = "<group>"; };
7A27ADF6249FEF690035F39E /* Recorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recorder.swift; sourceTree = "<group>"; };
@ -320,7 +314,6 @@
7A2DE69725868AC800A113FC /* VehicleAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleAd.swift; sourceTree = "<group>"; };
7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalDatePicker.swift; sourceTree = "<group>"; };
7A2E6FA32C42B3AD00C40DA7 /* AutoCatCoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutoCatCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
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>"; };
7A3399AA299063370087DF98 /* SearchControllerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchControllerExt.swift; sourceTree = "<group>"; };
7A3E12D62C7B42B700EE710D /* UserDefaults+Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Settings.swift"; sourceTree = "<group>"; };
@ -333,7 +326,6 @@
7A43F9F7246C8A6200BA5B49 /* JWT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = "<group>"; };
7A45FB372C27073700618694 /* StorageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageService.swift; sourceTree = "<group>"; };
7A4927D42CCE438600851C01 /* OptionalBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalBinding.swift; sourceTree = "<group>"; };
7A4927D62CCEA6DC00851C01 /* VMResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMResult.swift; sourceTree = "<group>"; };
7A52AB292580112E002CD910 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; 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>"; };
@ -623,17 +615,13 @@
7A813DC7250B5C6E00CC93B9 /* Location */,
7A11471923FE839000B424AF /* AuthController.swift */,
7A530B7924001D3300CBFE6E /* CheckController.swift */,
7A33381024990DAE00D878F1 /* FiltersController.swift */,
7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */,
7A11471523FDEB2A00B424AF /* MainSplitController.swift */,
7A27ADF2249F8B650035F39E /* RecordsController.swift */,
7A27ADC6249D43210035F39E /* RegionsController.swift */,
7A11471723FDEBFA00B424AF /* ReportController.swift */,
7A3F07AC2436350B00E59687 /* SearchController.swift */,
7AC3554B29696A1C00889457 /* MainTabController.swift */,
7AC3554D29696C4500889457 /* DummyNewController.swift */,
7AC3554F29696D5A00889457 /* NewNumberController.swift */,
7A4927D62CCEA6DC00851C01 /* VMResult.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -1342,7 +1330,6 @@
7AFBE8C02C3024E5003C491D /* ACHud.swift in Sources */,
7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */,
7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */,
7A4927D72CCEA6DC00851C01 /* VMResult.swift in Sources */,
7AAAFADA2C4D1AFE0050410D /* Zoomable.swift in Sources */,
7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */,
7A2E11292CCE395300E5CA17 /* OptionalDatePicker.swift in Sources */,
@ -1376,12 +1363,10 @@
7ABD1B492D044A4700B43213 /* GalleryViewModel.swift in Sources */,
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */,
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */,
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */,
7AC76D7B270083AE0084DB27 /* TextView.swift in Sources */,
7A1090E824A394F100B4F0B2 /* AudioRecordCell.swift in Sources */,
7A2C96122C3B155B00AE46B5 /* NoteAlertModifier.swift in Sources */,
7A64AE762469DFB600ABE48E /* ContentTransformers.swift in Sources */,
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */,
7AE24C5F251F1B4E00758E39 /* Buttons.swift in Sources */,
7A11471A23FE839000B424AF /* AuthController.swift in Sources */,
7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */,
@ -1422,7 +1407,6 @@
7A71580C2C44453200852088 /* AdsScreen.swift in Sources */,
7A06E0B02C7065D8005731AC /* SettingsCoordinator.swift in Sources */,
7A91894F29A2BD8700519C74 /* GestureRecognizers.swift in Sources */,
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */,
7AFBE8CC2C3085C6003C491D /* ACProgressView.swift in Sources */,
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */,
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,

View File

@ -1,46 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23091" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="pme-aR-UNJ">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="pme-aR-UNJ">
<device id="retina4_7" orientation="portrait" appearance="dark"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23079"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Report Controller-->
<scene sceneID="Lbe-ZV-eei">
<objects>
<viewController storyboardIdentifier="ReportController" id="i1k-Y4-pyh" customClass="ReportController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="u3u-z2-y6J">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="fbN-WR-iQY"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
<navigationItem key="navigationItem" id="goK-kc-WCv">
<rightBarButtonItems>
<barButtonItem systemItem="action" id="2MI-Nh-b8L">
<connections>
<action selector="onShare:" destination="i1k-Y4-pyh" id="SP4-ez-N4e"/>
</connections>
</barButtonItem>
<barButtonItem image="doc.on.doc" catalog="system" id="WZn-dn-wEG">
<connections>
<action selector="onCopy:" destination="i1k-Y4-pyh" id="hOb-Hq-JWH"/>
</connections>
</barButtonItem>
</rightBarButtonItems>
</navigationItem>
<connections>
<outlet property="actionBarItem" destination="2MI-Nh-b8L" id="hPg-h1-dgv"/>
<outlet property="copyBarItem" destination="WZn-dn-wEG" id="NCX-Xv-vOx"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="gzk-86-k5g" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1095" y="965"/>
</scene>
<!--Events-->
<scene sceneID="pPZ-gs-kHF">
<objects>
@ -54,17 +21,17 @@
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="EventCell" id="QIb-Hv-tvk" customClass="EventCell" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="50" width="375" height="436"/>
<rect key="frame" x="0.0" y="50" width="375" height="437"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QIb-Hv-tvk" id="Ypt-ch-fGT">
<rect key="frame" x="0.0" y="0.0" width="375" height="436"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="437"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP">
<rect key="frame" x="16" y="8" width="343" height="420"/>
<rect key="frame" x="16" y="8" width="343" height="421"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="k4Z-KM-byE">
<rect key="frame" x="0.0" y="0.0" width="335" height="420"/>
<rect key="frame" x="0.0" y="0.0" width="335" height="421"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xcQ-Wz-gJ0">
<rect key="frame" x="0.0" y="0.0" width="335" height="201"/>
@ -73,7 +40,7 @@
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1tQ-zM-6T9">
<rect key="frame" x="0.0" y="209" width="335" height="211"/>
<rect key="frame" x="0.0" y="209" width="335" height="212"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/>
@ -81,7 +48,7 @@
</subviews>
</stackView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="750" verticalHuggingPriority="251" image="person" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="CFI-xa-eLs">
<rect key="frame" x="343" y="1" width="0.0" height="417.5"/>
<rect key="frame" x="343" y="1" width="0.0" height="418.5"/>
</imageView>
</subviews>
</stackView>
@ -265,82 +232,12 @@
<connections>
<outlet property="showMapButton" destination="iVh-uQ-fX5" id="19X-3N-bDb"/>
<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"/>
<viewLayoutGuide key="safeArea" id="tol-Qd-fB2"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</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"/>
<connections>
<outlet property="delegate" destination="mwd-dq-ihi" id="q6l-kV-3Og"/>
</connections>
</tableView>
</subviews>
<viewLayoutGuide key="safeArea" id="TQH-W9-FD9"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<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>
</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>
<!--Voice records-->
<scene sceneID="9pI-G0-wG0">
<objects>
@ -742,7 +639,6 @@
<splitViewController storyboardIdentifier="MainSplitController" id="q8g-Bu-ZOb" customClass="MainSplitController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<connections>
<segue destination="s9R-9a-TOT" kind="relationship" relationship="masterViewController" id="Qf1-ZB-fOc"/>
<segue destination="Km4-b6-SGW" kind="relationship" relationship="detailViewController" id="6tT-Vk-xmm"/>
</connections>
</splitViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="zgS-sH-9QV" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
@ -841,24 +737,6 @@
</objects>
<point key="canvasLocation" x="3261.5999999999999" y="142.57871064467767"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="rne-uJ-hKr">
<objects>
<navigationController storyboardIdentifier="ReportNavController" automaticallyAdjustsScrollViewInsets="NO" id="Km4-b6-SGW" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="JaO-tp-k6N">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="i1k-Y4-pyh" kind="relationship" relationship="rootViewController" id="T0m-94-MgM"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2VV-jB-JET" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="198" y="965"/>
</scene>
<!--Records-->
<scene sceneID="oyu-oz-pC4">
<objects>
@ -899,7 +777,6 @@
</scenes>
<resources>
<image name="clock.arrow.circlepath" catalog="system" width="128" height="119"/>
<image name="doc.on.doc" catalog="system" width="116" height="128"/>
<image name="exclamationmark.arrow.triangle.2.circlepath" catalog="system" width="128" height="117"/>
<image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/>
<image name="map" catalog="system" width="128" height="112"/>
@ -913,22 +790,22 @@
<image name="square.and.arrow.up" catalog="system" width="110" height="128"/>
<image name="text.bubble" catalog="system" width="128" height="110"/>
<systemColor name="secondaryLabelColor">
<color red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemBlueColor">
<color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemOrangeColor">
<color red="1" green="0.58431372550000005" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="1" green="0.58431372549019611" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemTealColor">
<color red="0.18823529410000001" green="0.69019607839999997" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.18823529411764706" green="0.69019607843137254" blue="0.7803921568627451" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="tertiaryLabelColor">
<color red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.29803921570000003" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.29803921568627451" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>

View File

@ -259,24 +259,9 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
func updateDetailController(with vehicle: VehicleDto) {
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.getNumber()
// splitViewController.showDetailViewController(detail, sender: self)
// }
Task {
let coordinator = ReportCoordinator(splitController: splitViewController, vehicle: vehicle, isPersistent: true)
try? await coordinator.start()
let coordinator = ReportCoordinator(controller: splitViewController, vehicle: vehicle, isPersistent: true)
_ = try? await coordinator.start()
}
}
}

View File

@ -1,312 +0,0 @@
import UIKit
import Eureka
import AutoCatCore
class FiltersController: FormViewController {
var done = false
var filter: Filter!
var onDone: (() -> Void)?
var regions: [VehicleRegion] = []
override func viewDidLoad() {
super.viewDidLoad()
addMainSection()
addRegionSection()
addAddedBySection()
addTimeSections()
addLocationTimeSection()
addSortSection()
addClearAllSection()
}
func runAsync(_ completion: @escaping () async throws -> Void) {
Task {
do {
try await completion()
} catch {
print("Error: \(error.localizedDescription)")
}
}
}
func addMainSection() {
let brandRow = PushRow<String>("Brand") { row in
row.title = NSLocalizedString("Brand", comment: "")
row.value = self.filter.brand.text
row.selectorTitle = NSLocalizedString("Brands", comment: "")
row.optionsProvider = .lazy({ form, completion in
self.runAsync {
let brands = try await ApiService.shared.getBrands()
completion(["Any"] + brands)
}
})
}
.onPresent(removeSectionName(from:to:))
.onChange { self.filter.brand = .init($0.value) }
.cellUpdate { $1.value = self.filter.brand.text }
let modelRow = PushRow<String>("Model") { row in
row.title = NSLocalizedString("Model", comment: "")
row.value = self.filter.model.text
row.disabled = "$Brand == 'Any'"
row.optionsProvider = .lazy({ form, completion in
guard self.filter.brand != .any else {
completion(["Any"])
return
}
self.runAsync {
let models = try await ApiService.shared.getModels(of: self.filter.brand.text)
completion(["Any"] + models)
}
})
}
.onPresent(removeSectionName(from:to:))
.onChange { self.filter.model = .init($0.value) }
.cellUpdate { $1.value = self.filter.model.text }
let colorRow = PushRow<String>("Color") { row in
row.title = NSLocalizedString("Color", comment: "")
row.value = self.filter.color.text
row.optionsProvider = .lazy({ form, completion in
self.runAsync {
let colors = try await ApiService.shared.getColors()
completion(["Any"] + colors)
}
})
}
.onPresent(removeSectionName(from:to:))
.onChange { self.filter.color = .init($0.value) }
.cellUpdate { $1.value = self.filter.color.text }
let yearRow = PushRow<String>("Year") { row in
row.title = NSLocalizedString("Year", comment: "Manufacturing year")
row.value = self.filter.year.text
row.optionsProvider = .lazy({ form, completion in
self.runAsync {
let years = try await ApiService.shared.getYears()
completion(["Any"] + years.map(String.init))
}
})
}
.onChange { self.filter.year = .init($0.value) }
.cellUpdate { $1.value = self.filter.year.text }
let mainSection = Section(NSLocalizedString("Main filters", comment: "")) { $0.tag = "MainFilters" }
form +++ mainSection
<<< brandRow
<<< modelRow
<<< colorRow
<<< yearRow
}
func addRegionSection() {
form +++ Section() { $0.tag = "Regions" }
<<< LabelRow("RegionsRow") { row in
row.title = NSLocalizedString("Regions", comment: "")
row.value = self.filter.regions?.map(String.init).joined(separator: ",") ?? "Any"
row.cellUpdate { cell, _ in
cell.accessoryType = .disclosureIndicator
row.value = self.filter.regions?.map(String.init).joined(separator: ",") ?? "Any"
}
}
.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)
}
}
func addAddedBySection() {
form +++ Section() { $0.tag = "AddedByMe" }
<<< ActionSheetRow<String>("AddedByMeRow") { row in
row.title = NSLocalizedString("Added by", comment: "")
row.selectorTitle = NSLocalizedString("Added by", comment: "")
row.options = AddedBy.allCases.map { $0.description }
row.value = self.filter.addedBy.description
}
.onChange { row in
if let index = row.options?.firstIndex(of: row.value ?? "") {
self.filter.addedBy = AddedBy.allCases[index]
} else {
self.filter.addedBy = .anyone
}
}
.cellUpdate { cell, row in
row.value = self.filter.addedBy.description
}
}
func addTimeSections() {
form +++ Section(NSLocalizedString("Update time", comment: ""))
<<< DateInlineRow("FromDateUpdated") { row in
row.title = NSLocalizedString("From", comment: "")
row.noValueDisplayText = NSLocalizedString("Beginning", comment: "")
row.value = self.filter.fromDateUpdated
}
.onChange { self.filter.fromDateUpdated = self.nullifyTime(of: $0.value) }
.cellUpdate(self.update(cell:row:))
<<< DateInlineRow("ToDateUpdated") { row in
row.title = NSLocalizedString("To", comment: "")
row.noValueDisplayText = NSLocalizedString("Now", comment: "")
row.value = self.filter.toDateUpdated
}
.onChange { self.filter.toDateUpdated = self.nullifyTime(of: $0.value) }
.cellUpdate(self.update(cell:row:))
form +++ Section(NSLocalizedString("Added time", comment: ""))
<<< DateInlineRow("FromDate") { row in
row.title = NSLocalizedString("From", comment: "")
row.noValueDisplayText = NSLocalizedString("Beginning", comment: "")
row.value = self.filter.fromDate
}
.onChange { self.filter.fromDate = self.nullifyTime(of: $0.value) }
.cellUpdate(self.update(cell:row:))
<<< DateInlineRow("ToDate") { row in
row.title = NSLocalizedString("To", comment: "")
row.noValueDisplayText = NSLocalizedString("Now", comment: "")
row.value = self.filter.toDate
}
.onChange { self.filter.toDate = self.nullifyTime(of: $0.value) }
.cellUpdate(self.update(cell:row:))
}
func addLocationTimeSection() {
form +++ Section(NSLocalizedString("Location adding time", comment: ""))
<<< DateInlineRow("FromLocationDate") { row in
row.title = NSLocalizedString("From", comment: "")
row.noValueDisplayText = NSLocalizedString("Beginning", comment: "")
row.value = self.filter.fromLocationDate
}
.onChange { self.filter.fromLocationDate = self.nullifyTime(of: $0.value) }
.cellUpdate(self.update(cell:row:))
<<< DateInlineRow("ToLocationDate") { row in
row.title = NSLocalizedString("To", comment: "")
row.noValueDisplayText = NSLocalizedString("Now", comment: "")
row.value = self.filter.toLocationDate
}
.onChange { self.filter.toLocationDate = self.nullifyTime(of: $0.value) }
.cellUpdate(self.update(cell:row:))
}
func addSortSection() {
form +++ Section(NSLocalizedString("Sort", comment: "Header section. Noun."))
<<< PickerInlineRow<SortParameter>("SortBy") { row in
row.title = NSLocalizedString("Sort by", comment: "")
row.value = self.filter.sortBy
row.options = SortParameter.allCases
}
.onChange { self.filter.sortBy = $0.value ?? .updatedDate }
.cellUpdate { $1.value = self.filter.sortBy }
<<< SegmentedRow<AutoCatCore.SortOrder>("SortOrder") { row in
row.title = NSLocalizedString("Order", comment: "sort order")
row.value = self.filter.sortOrder
row.options = AutoCatCore.SortOrder.allCases
}
.onChange { self.filter.sortOrder = $0.value ?? .descending }
.cellUpdate { $1.value = self.filter.sortOrder }
}
func addClearAllSection() {
form +++ Section()
<<< ButtonRow("ClearAll") { $0.title = NSLocalizedString("Clear all filters", comment: "") }.onCellSelection { cell, row in
self.filter.clear()
for section in self.form.allSections {
// 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 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 "" }
}
func update(cell: DateInlineRow.Cell, row: DateInlineRow) {
guard let tag = row.tag else { return }
let date = self.date(from: tag)
if date != nil {
let button = UIButton(type: .close)
button.accessibilityLabel = row.tag
button.addTarget(self, action: #selector(self.clearDate(_:)), for: .touchUpInside)
button.sizeToFit()
cell.accessoryView = button
} else {
cell.accessoryView = nil
}
row.value = date
}
func date(from tag: String) -> Date? {
switch tag {
case "FromDate": return self.filter.fromDate
case "ToDate": return self.filter.toDate
case "FromDateUpdated": return self.filter.fromDateUpdated
case "ToDateUpdated": return self.filter.toDateUpdated
case "FromLocationDate": return self.filter.fromLocationDate
case "ToLocationDate": return self.filter.toLocationDate
default: return nil
}
}
@objc func clearDate(_ sender: UIButton) {
guard let tag = sender.accessibilityLabel else { return }
guard let row = self.form.rowBy(tag: tag) as? DateInlineRow else { return }
switch tag {
case "FromDate": self.filter.fromDate = nil
case "ToDate": self.filter.toDate = nil
case "FromDateUpdated": self.filter.fromDateUpdated = nil
case "ToDateUpdated": self.filter.toDateUpdated = nil
case "FromLocationDate": self.filter.fromLocationDate = nil
case "ToLocationDate": self.filter.toLocationDate = nil
default: break
}
row.value = nil
row.baseCell.accessoryView = nil
row.baseCell.update()
}
func nullifyTime(of date: Date?) -> Date? {
guard let date else {
return nil
}
return Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: date)
}
}

View File

@ -4,7 +4,7 @@ class MainSplitController: UISplitViewController, UISplitViewControllerDelegate
override func viewDidLoad() {
super.viewDidLoad()
self.preferredDisplayMode = .allVisible
self.preferredDisplayMode = .oneBesideSecondary
self.delegate = self
}
@ -31,13 +31,13 @@ class MainSplitController: UISplitViewController, UISplitViewControllerDelegate
let tabController = splitViewController.viewControllers.first as? UITabBarController
let selectedNavController = tabController?.selectedViewController as? UINavigationController
if selectedNavController?.viewControllers.count ?? 0 > 1 && selectedNavController?.viewControllers[1] is ReportController {
if let controllers = selectedNavController?.popToRootViewController(animated: false) {
let nav = UINavigationController()
nav.setViewControllers(controllers, animated: true)
return nav
}
}
// if selectedNavController?.viewControllers.count ?? 0 > 1 && selectedNavController?.viewControllers[1] is ReportController {
// if let controllers = selectedNavController?.popToRootViewController(animated: false) {
// let nav = UINavigationController()
// nav.setViewControllers(controllers, animated: true)
// return nav
// }
// }
return nil
}
@ -45,16 +45,12 @@ class MainSplitController: UISplitViewController, UISplitViewControllerDelegate
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool
{
guard let detailNav = secondaryViewController as? UINavigationController,
let detail = detailNav.viewControllers.first as? ReportController
let detail = detailNav.viewControllers.first
else
{
return false
}
if detail.number == nil {
return false
}
if let tabController = primaryViewController as? UITabBarController {
let selectedNavController = tabController.selectedViewController as? UINavigationController
detail.hidesBottomBarWhenPushed = true

View File

@ -17,6 +17,12 @@ class MainTabController: UITabBarController, UITabBarControllerDelegate {
#endif
if #available(iOS 18, *) {
// Setting the horizontal size class will force the tab bar
// to be displayed at the bottom.
traitOverrides.horizontalSizeClass = .compact
}
Task { await addSettings() }
}

View File

@ -1,129 +0,0 @@
import UIKit
import AutoCatCore
class RegionsDataSourse: UITableViewDiffableDataSource<VehicleRegion, 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: [VehicleRegion] = []
var regionsFiltered: [VehicleRegion] = []
var done = false
var onDone: (([Int]?) -> Void)?
var regionCodes: [Int] = []
var datasource: RegionsDataSourse!
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = NSLocalizedString("Search regions", comment: "Search field placeholder")
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
}
Task {
do {
self.regions = try await ApiService.shared.getRegions()
self.regionsFiltered = regions
self.updateTableView()
self.applySelection()
} catch {
print("Get regions error: ", error)
}
}
}
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<VehicleRegion, 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

@ -1,438 +0,0 @@
import UIKit
import Kingfisher
import LinkPresentation
import RealmSwift
import Eureka
import AutoCatCore
import SwiftEntryKit
import MobileCoreServices
import PKHUD
class ReportController: FormViewController, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate {
@IBOutlet weak var actionBarItem: UIBarButtonItem!
@IBOutlet weak var copyBarItem: UIBarButtonItem!
private let logoPlaceholder = UIImage(named: "SteeringWheel")
private let copyableTags = ["Model", "Year", "Color", "Category", "STP", "Japanese",
"PlateNumber", "VIN", "STS", "PTS",
"EngineNumber", "FuelType", "Volume", "PowerHP", "PowerKw"];
var vehicle: VehicleDto? {
didSet {
if isViewLoaded && self.view.window != nil {
self.updateReport()
self.form.allSections.forEach { $0.reload() }
self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: false)
}
if let vehicle {
vehicleUpdated?(vehicle)
}
}
}
private var notificationToken: NotificationToken?
var number: String? {
didSet {
if let realm = try? Realm(), let num = number {
let vehicles = realm.objects(Vehicle.self).filter("number = %@", num)
self.notificationToken?.invalidate()
self.notificationToken = vehicles.observe { _ in self.vehicle = vehicles.first?.dto }
} else {
self.vehicle = nil
}
}
}
public var vehicleUpdated: ((VehicleDto) -> Void)?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
if let vehicle = self.vehicle {
let urls = Array(vehicle.photos.compactMap { URL(string: $0.url) })
let prefetcher = ImagePrefetcher(urls: urls)
prefetcher.start()
}
form +++ Section()
<<< LabelRow("Model").cellUpdate { cell, _ in cell.imageView?.kf.setImage(with: URL(string: self.vehicle?.brand?.logo ?? ""), placeholder: self.logoPlaceholder) }
form +++ Section(NSLocalizedString("General", comment: ""))
<<< LabelRow("Year") { $0.title = NSLocalizedString("Year", comment: "") }
<<< LabelRow("Color") { $0.title = NSLocalizedString("Color", comment: "") }
<<< LabelRow("Category") { $0.title = NSLocalizedString("Category", comment: "") }
<<< LabelRow("STP") { $0.title = NSLocalizedString("Steering wheel position", comment: "") }
<<< LabelRow("Japanese") { $0.title = NSLocalizedString("Japanese", comment: "") }
form +++ Section(NSLocalizedString("Identifiers", comment: ""))
<<< LabelRow("PlateNumber") { $0.title = NSLocalizedString("Plate number", comment: "") }
<<< LabelRow("VIN") { $0.title = NSLocalizedString("VIN", comment: "") }
<<< LabelRow("STS") { $0.title = NSLocalizedString("STS", comment: "") }
<<< LabelRow("PTS") { $0.title = NSLocalizedString("PTS", comment: "") }
form +++ Section(NSLocalizedString("Engine", comment: ""))
<<< LabelRow("EngineNumber") { $0.title = NSLocalizedString("Number", comment: "") }
<<< LabelRow("FuelType") { $0.title = NSLocalizedString("Fuel type", comment: "") }
<<< LabelRow("Volume") { $0.title = NSLocalizedString("Volume (cm³)", comment: "") }
<<< LabelRow("PowerHP") { $0.title = NSLocalizedString("Power (HP)", comment: "") }
<<< LabelRow("PowerKw") { $0.title = NSLocalizedString("Power (kw)", comment: "") }
form +++ Section(NSLocalizedString("History", comment: ""))
<<< LabelRow("Events") { $0.title = NSLocalizedString("Events", comment: "") }
.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
.onCellSelection { _, _ in
let sb = UIStoryboard(name: "Main", bundle: nil)
let controller = sb.instantiateViewController(identifier: "EventsController") as EventsController
controller.vehicle = self.vehicle
controller.vehicleUpdated = { vehicle in
self.vehicle = vehicle
}
self.navigationController?.pushViewController(controller, animated: true)
}
<<< LabelRow("OSAGO") { $0.title = NSLocalizedString("OSAGO", comment: "") }
.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
.onCellSelection { _, _ in
if let contracts = self.vehicle?.osagoContracts, let navController = self.navigationController {
let coordinator = OsagoCoordinator(navController: navController, contracts: contracts)
Task { try await coordinator.start() }
}
}
<<< LabelRow("Owners") { row in
row.title = NSLocalizedString("Owners", comment: "")
row.disabled = "$Owners == '0'"
}
.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
.onCellSelection { _, row in
if row.value != "0" {
if let ownerships = self.vehicle?.ownershipPeriods, let navController = self.navigationController {
let coordinator = OwnersCoordinator(navController: navController, ownerships: ownerships)
Task { try await coordinator.start() }
}
}
}
<<< LabelRow("Photos") { row in
row.title = NSLocalizedString("Photos", comment: "")
row.disabled = "$Photos == '0'"
}
.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
.onCellSelection { _, row in
if row.value != "0" {
let mediaBrowser = MediaBrowserViewController(index: 0, dataSource: self, delegate: self)
mediaBrowser.shouldShowTitle = true
mediaBrowser.title = self.vehicle?.photos.first?.description
self.present(mediaBrowser, animated: true, completion: nil)
}
}
<<< LabelRow("Ads") { row in
row.title = NSLocalizedString("Ads", comment: "")
row.disabled = "$Ads == '0'"
}
.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
.onCellSelection { _, row in
if let ads = self.vehicle?.ads, let navController = self.navigationController {
let coordinator = AdsCoordinator(navController: navController, ads: ads)
Task { try await coordinator.start() }
}
}
<<< LabelRow("Notes") { row in
row.title = NSLocalizedString("Notes", comment: "")
}
.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
.onCellSelection { _, row in
if let vehicle = self.vehicle, let navController = self.navigationController {
let coordinator = NotesCoordinator(navController: navController, vehicle: vehicle)
Task { try await coordinator.start() }
}
}
if Settings.shared.showDebugInfo {
self.form +++ Section(NSLocalizedString("Debug info", comment: "noun"))
<<< SourceStatusRow("DebugAutocod") { $0.title = NSLocalizedString("Autocod", comment: "") }
<<< SourceStatusRow("DebugVin01Vin") { $0.title = NSLocalizedString("Vin01 (VIN)", comment: "") }
<<< SourceStatusRow("DebugVin01Base") { $0.title = NSLocalizedString("Vin01 (base)", comment: "base report") }
<<< SourceStatusRow("DebugVin01History") { $0.title = NSLocalizedString("Vin01 (history)", comment: "GIBDD registration history") }
<<< SourceStatusRow("DebugNomerogram") { $0.title = NSLocalizedString("Nomerogram", comment: "") }
}
form +++ Section("")
<<< ButtonRow("CheckGB") { $0.title = NSLocalizedString("Check GB", comment: "") }.onCellSelection { cell, row in
Task { await self.checkGB() }
}
setupCopyBehaviour()
}
func setupCopyBehaviour() {
for row in form.allRows {
if let labelRow = row as? LabelRow, copyableTags.contains(row.tag ?? "") {
let doubleTap = UITapGestureRecognizer { _ in
guard let text = labelRow.value else {
return
}
UIPasteboard.general.string = text
let generator = UIImpactFeedbackGenerator(style: .rigid)
generator.impactOccurred()
let toastMessage = NSLocalizedString("Copied: ", comment: "") + text
self.showToast(text: toastMessage)
}
doubleTap.numberOfTapsRequired = 2
doubleTap.delaysTouchesBegan = true
labelRow.cell.addGestureRecognizer(doubleTap)
}
}
}
func showToast(text: String) {
let style = EKProperty.LabelStyle(
font: .systemFont(ofSize: 14),
color: .white, //.black,
alignment: .center
)
let labelContent = EKProperty.LabelContent(
text: text,
style: style
)
let contentView = EKNoteMessageView(with: labelContent)
var attributes: EKAttributes = .bottomFloat //.toast
attributes.entryBackground = .visualEffect(style: EKAttributes.BackgroundStyle.BlurStyle(light: .dark, dark: .light)) //.color(color: .init(red: 0, green: 196, blue: 0))
SwiftEntryKit.display(entry: contentView, using: attributes)
}
func update(row tag: String, with value: String) {
if let row = self.form.rowBy(tag: tag) as? LabelRow {
row.value = value
row.reload()
}
}
func update(sourceStatusRow tag: String, with value: DebugInfoEntryDto) {
if let row = self.form.rowBy(tag: tag) as? SourceStatusRow {
row.value = value
row.reload()
}
}
func updateReport() {
self.update(row: "Model", with: self.vehicle?.brand?.name?.original ?? "<unknown>")
self.update(row: "Year", with: String(self.vehicle?.year ?? 0))
self.update(row: "Color", with: self.vehicle?.color ?? "<unknown>")
self.update(row: "Category", with: self.vehicle?.category ?? "<unknown>")
self.update(row: "STP", with: self.stringFromBool(self.vehicle?.isRightWheel, yes: NSLocalizedString("Right", comment: ""), no: NSLocalizedString("Left", comment: "")))
self.update(row: "Japanese", with: self.stringFromBool(self.vehicle?.isJapanese, yes: NSLocalizedString("Yes", comment: ""), no: NSLocalizedString("No", comment: "")))
var num = self.vehicle?.getNumber() ?? "<unknown>"
if self.vehicle?.outdated ?? false, let current = self.vehicle?.currentNumber {
num = "\(self.vehicle!.getNumber()) (\(current))"
}
self.update(row: "PlateNumber", with: num)
self.update(row: "VIN", with: self.vehicle?.vin1 ?? "<unknown>")
self.update(row: "STS", with: self.vehicle?.sts ?? "<unknown>")
self.update(row: "PTS", with: self.vehicle?.pts ?? "<unknown>")
self.update(row: "EngineNumber", with: self.vehicle?.engine?.number ?? "<unknown>")
self.update(row: "FuelType", with: self.vehicle?.engine?.fuelType ?? "<unknown>")
self.update(row: "Volume", with: String(self.vehicle?.engine?.volume ?? 0))
self.update(row: "PowerHP", with: String(self.vehicle?.engine?.powerHp ?? 0))
self.update(row: "PowerKw", with: String(self.vehicle?.engine?.powerKw ?? 0))
self.update(row: "Events", with: String(self.vehicle?.events.count ?? 0))
self.update(row: "OSAGO", with: String(self.vehicle?.osagoContracts.count ?? 0))
self.update(row: "Owners", with: String(self.vehicle?.ownershipPeriods.count ?? 0))
self.update(row: "Photos", with: String(self.vehicle?.photos.count ?? 0))
self.update(row: "Ads", with: String(self.vehicle?.ads.count ?? 0))
self.update(row: "Notes", with: String(self.vehicle?.notes.count ?? 0))
if let dInfo = self.vehicle?.debugInfo {
self.update(sourceStatusRow: "DebugAutocod", with: dInfo.autocod)
self.update(sourceStatusRow: "DebugVin01Vin", with: dInfo.vin01vin)
self.update(sourceStatusRow: "DebugVin01Base", with: dInfo.vin01base)
self.update(sourceStatusRow: "DebugVin01History", with: dInfo.vin01history)
self.update(sourceStatusRow: "DebugNomerogram", with: dInfo.nomerogram)
}
}
func stringFromBool(_ value: Bool?, yes: String, no: String) -> String {
guard let value = value else { return "<unknown>" }
return value ? yes : no
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let ad = UIApplication.shared.delegate as? AppDelegate else { return }
self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: animated)
switch ad.quickAction {
case .check:
self.dismiss(animated: false, completion: nil)
default:
break
}
self.updateReport()
}
func checkGB() async {
guard let vehicle = self.vehicle else { return }
do {
HUD.show(.progress)
let newVehicle = try await ApiService.shared.checkVehicleGb(by: vehicle.getNumber())
let realm = try await Realm()
if let realmVehicle = realm.object(ofType: Vehicle.self, forPrimaryKey: vehicle.getNumber()) {
try? realm.write {
realm.add(Vehicle(dto: newVehicle), update: .all)
}
} else {
self.vehicle?.vin1 = newVehicle.vin1
self.vehicle?.color = newVehicle.color
self.vehicle?.sts = newVehicle.sts
}
self.updateReport()
self.form.allSections.forEach { $0.reload() }
HUD.hide()
} catch {
HUD.hide()
self.show(error: error)
}
}
// 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
Task { @MainActor 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
}
// MARK: - Sharing
@IBAction func onShare(_ sender: UIBarButtonItem) {
guard let vehicle = self.vehicle else { return }
let sheet = UIAlertController(title: NSLocalizedString("Share report", comment: ""), message: nil, preferredStyle: .actionSheet)
sheet.popoverPresentationController?.barButtonItem = self.actionBarItem
let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) }
let shareImage = UIAlertAction(title: NSLocalizedString("As one image", comment: ""), style: .default) { _ in
let image = vehicle.reportImage(width: self.tableView.contentSize.width)
do {
let fm = FileManager.default
let documentDirectory = try fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = documentDirectory.appendingPathComponent("report.png")
if let imageData = image.pngData() {
try imageData.write(to: fileURL)
}
let item = ActivityItemSource(url: fileURL, title: vehicle.getNumber())
let controller = UIActivityViewController(activityItems: [item], applicationActivities: nil)
controller.popoverPresentationController?.barButtonItem = sender
self.present(controller, animated: true)
} catch {
print(error)
}
}
let shareTextAndImage = UIAlertAction(title: NSLocalizedString("As text and photos", comment: ""), style: .default) { _ in
guard let vehicle = self.vehicle else { return }
var items: [Any] = [vehicle.reportText()]
for photo in vehicle.photos {
// TODO: Fix sharing
// if let url = URL(string: photo.url) {
// if let image = ImageCache.default.retrieveImageInDiskCache(forKey: url.cacheKey) {
// items.append(image)
// }
//
// }
}
let controller = UIActivityViewController(activityItems: items, applicationActivities: nil)
controller.popoverPresentationController?.barButtonItem = sender
self.present(controller, animated: true)
}
let shareLink = UIAlertAction(title: NSLocalizedString("As link", comment: ""), style: .default) { _ in
guard let vehicle = self.vehicle else { return }
if let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()),
let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt)
{
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
controller.popoverPresentationController?.barButtonItem = sender
self.present(controller, animated: true)
}
}
let copyLink = UIAlertAction(title: NSLocalizedString("Copy link to report", comment: ""), style: .default) { _ in
guard let vehicle = self.vehicle else { return }
if let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()),
let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt)
{
UIPasteboard.general.string = url.absoluteString
}
}
sheet.addAction(shareImage)
sheet.addAction(shareTextAndImage)
sheet.addAction(shareLink)
sheet.addAction(copyLink)
sheet.addAction(cancel)
self.present(sheet, animated: true, completion: nil)
}
// MARK: - Copy
@IBAction func onCopy(_ sender: UIBarButtonItem) {
let sheet = UIAlertController(title: NSLocalizedString("Copy to pasteboard", comment: ""), message: nil, preferredStyle: .actionSheet)
sheet.popoverPresentationController?.barButtonItem = self.copyBarItem
let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) }
let copyPlateNumber = UIAlertAction(title: NSLocalizedString("Plate number", comment: ""), style: .default) { _ in UIPasteboard.general.string = self.vehicle?.getNumber() }
let copyVin = UIAlertAction(title: NSLocalizedString("VIN", comment: ""), style: .default) { _ in UIPasteboard.general.string = self.vehicle?.vin1 }
sheet.addAction(copyPlateNumber)
sheet.addAction(copyVin)
sheet.addAction(cancel)
self.present(sheet, animated: true, completion: nil)
}
}

View File

@ -102,25 +102,13 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
// FIXME: Code duplication
func updateDetailController(with vehicle: VehicleDto, indexPath: IndexPath) {
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?.vehicle = vehicle
report?.vehicleUpdated = { vehicle in
self.datasource.set(item: vehicle, at: indexPath)
self.tableView.reloadData()
{
Task {
let coordinator = ReportCoordinator(controller: splitViewController, vehicle: vehicle, isPersistent: false)
if let updatedVehicle = try? await coordinator.start() {
datasource.set(item: updatedVehicle, at: indexPath)
tableView.reloadData()
}
splitViewController.showDetailViewController(detail, sender: self)
//self.performSegue(withIdentifier: "OpenDetailSegue", sender: self)
}
}
}

View File

@ -1,39 +0,0 @@
//
// VMResult.swift
// AutoCat
//
// Created by Selim Mustafaev on 27.10.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import Foundation
@Observable
class VMResult<T> {
var value: T
var isDone: Bool
init(value: T) {
self.value = value
self.isDone = false
}
func done() {
isDone = true
}
func cancel() {
isDone = false
}
func set(_ value: T) {
self.value = value
isDone = true
}
func get() -> T? {
isDone ? value : nil
}
}

View File

@ -164,13 +164,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
do {
HUD.show(.progress)
let vehicle = try await ApiService.shared.getReport(for: number)
let sb = UIStoryboard(name: "Main", bundle: nil)
let controller = sb.instantiateViewController(identifier: "ReportController") as ReportController
controller.vehicle = vehicle
let nav = UINavigationController(rootViewController: controller)
nav.modalPresentationStyle = .fullScreen
controller.navigationItem.leftBarButtonItem = BlockBarButtonItem(barButtonSystemItem: .close) { _ in nav.dismiss(animated: true) }
rootController.present(nav, animated: true)
Task {
let coordinator = ReportCoordinator(controller: rootController, vehicle: vehicle, isPersistent: false)
_ = try? await coordinator.start()
}
HUD.hide()
} catch {
HUD.show(error: error)

View File

@ -13,39 +13,29 @@ import AutoCatCore
@MainActor
class ReportCoordinator: Coordinator {
let viewController: UISplitViewController?
let viewController: UIViewController?
let vehicle: VehicleDto
let isPersistent: Bool
weak var navController: UINavigationController?
init(splitController: UISplitViewController?, vehicle: VehicleDto, isPersistent: Bool) {
init(controller: UIViewController?, vehicle: VehicleDto, isPersistent: Bool) {
self.viewController = splitController
self.viewController = controller
self.vehicle = vehicle
self.isPersistent = isPersistent
}
func start() async throws {
func start() async throws -> VehicleDto {
if viewController?.viewControllers.count == 2 {
navController = viewController?.viewControllers.last as? UINavigationController
} else {
let viewModel = ReportViewModel(vehicle: vehicle, isPersistent: isPersistent)
viewModel.coordinator = self
let controller = UIHostingController(rootView: ReportScreen(viewModel: viewModel))
//navController = UINavigationController(rootViewController: controller)
viewController?.showDetailViewController(controller, sender: self)
navController = controller.navigationController
return
}
if let navController {
// navController.popToRootViewController(animated: true)
// let report = navController.viewControllers.first as? ReportController
// report?.number = vehicle.getNumber()
viewController?.showDetailViewController(navController, sender: self)
}
let viewModel = ReportViewModel(vehicle: vehicle, isPersistent: isPersistent)
viewModel.coordinator = self
let controller = CustomHostingController(rootView: ReportScreen(viewModel: viewModel))
let newNavController = UINavigationController(rootViewController: controller)
viewController?.showDetailViewController(newNavController, sender: self)
navController = controller.navigationController
await controller.waitForDisappear()
return viewModel.vehicle
}
func openEvents(vehicle: VehicleDto, onUpdate: @escaping (VehicleDto) -> Void) {