diff --git a/AutoCat.xcodeproj/project.pbxproj b/AutoCat.xcodeproj/project.pbxproj index c259511..93f5dd4 100644 --- a/AutoCat.xcodeproj/project.pbxproj +++ b/AutoCat.xcodeproj/project.pbxproj @@ -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 = ""; }; 7A11470E23FDE7E600B424AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 7A11471523FDEB2A00B424AF /* MainSplitController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitController.swift; sourceTree = ""; }; - 7A11471723FDEBFA00B424AF /* ReportController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportController.swift; sourceTree = ""; }; 7A11471923FE839000B424AF /* AuthController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthController.swift; sourceTree = ""; }; 7A11474323FF06CA00B424AF /* ApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiService.swift; sourceTree = ""; }; 7A11474623FF2AA500B424AF /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; @@ -311,7 +306,6 @@ 7A1E78FE2CE91A740004B740 /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = ""; }; 7A22B6EA2C67FDEA00E60173 /* GeocoderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeocoderMock.swift; sourceTree = ""; }; 7A22B6EB2C67FDEA00E60173 /* SwiftLocationMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftLocationMock.swift; sourceTree = ""; }; - 7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = ""; }; 7A27ADF2249F8B650035F39E /* RecordsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsController.swift; sourceTree = ""; }; 7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExt.swift; sourceTree = ""; }; 7A27ADF6249FEF690035F39E /* Recorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recorder.swift; sourceTree = ""; }; @@ -320,7 +314,6 @@ 7A2DE69725868AC800A113FC /* VehicleAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleAd.swift; sourceTree = ""; }; 7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalDatePicker.swift; sourceTree = ""; }; 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 = ""; }; 7A333813249A532400D878F1 /* Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filter.swift; sourceTree = ""; }; 7A3399AA299063370087DF98 /* SearchControllerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchControllerExt.swift; sourceTree = ""; }; 7A3E12D62C7B42B700EE710D /* UserDefaults+Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Settings.swift"; sourceTree = ""; }; @@ -333,7 +326,6 @@ 7A43F9F7246C8A6200BA5B49 /* JWT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = ""; }; 7A45FB372C27073700618694 /* StorageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageService.swift; sourceTree = ""; }; 7A4927D42CCE438600851C01 /* OptionalBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalBinding.swift; sourceTree = ""; }; - 7A4927D62CCEA6DC00851C01 /* VMResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMResult.swift; sourceTree = ""; }; 7A52AB292580112E002CD910 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 7A530B7924001D3300CBFE6E /* CheckController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckController.swift; sourceTree = ""; }; 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCell.swift; sourceTree = ""; }; @@ -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 = ""; @@ -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 */, diff --git a/AutoCat/Base.lproj/Main.storyboard b/AutoCat/Base.lproj/Main.storyboard index 4301ff6..8936fbd 100644 --- a/AutoCat/Base.lproj/Main.storyboard +++ b/AutoCat/Base.lproj/Main.storyboard @@ -1,46 +1,13 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -54,17 +21,17 @@ - + - + - + - + - + @@ -265,82 +232,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -742,7 +639,6 @@ - @@ -841,24 +737,6 @@ - - - - - - - - - - - - - - - - - - @@ -899,7 +777,6 @@ - @@ -913,22 +790,22 @@ - + - + - + - + - + diff --git a/AutoCat/Controllers/CheckController.swift b/AutoCat/Controllers/CheckController.swift index 508e191..a302bde 100644 --- a/AutoCat/Controllers/CheckController.swift +++ b/AutoCat/Controllers/CheckController.swift @@ -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() } } } diff --git a/AutoCat/Controllers/FiltersController.swift b/AutoCat/Controllers/FiltersController.swift deleted file mode 100644 index a850cce..0000000 --- a/AutoCat/Controllers/FiltersController.swift +++ /dev/null @@ -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("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("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("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("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("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("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("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>>) { - 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) - } -} diff --git a/AutoCat/Controllers/MainSplitController.swift b/AutoCat/Controllers/MainSplitController.swift index 0a01342..fb8c8ac 100644 --- a/AutoCat/Controllers/MainSplitController.swift +++ b/AutoCat/Controllers/MainSplitController.swift @@ -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 diff --git a/AutoCat/Controllers/MainTabController.swift b/AutoCat/Controllers/MainTabController.swift index 2e13248..bd6b5d6 100644 --- a/AutoCat/Controllers/MainTabController.swift +++ b/AutoCat/Controllers/MainTabController.swift @@ -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() } } diff --git a/AutoCat/Controllers/RegionsController.swift b/AutoCat/Controllers/RegionsController.swift deleted file mode 100644 index 075fdf1..0000000 --- a/AutoCat/Controllers/RegionsController.swift +++ /dev/null @@ -1,129 +0,0 @@ -import UIKit -import AutoCatCore - -class RegionsDataSourse: UITableViewDiffableDataSource { - 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() - 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() - } -} diff --git a/AutoCat/Controllers/ReportController.swift b/AutoCat/Controllers/ReportController.swift deleted file mode 100644 index 1969160..0000000 --- a/AutoCat/Controllers/ReportController.swift +++ /dev/null @@ -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 ?? "") - self.update(row: "Year", with: String(self.vehicle?.year ?? 0)) - self.update(row: "Color", with: self.vehicle?.color ?? "") - self.update(row: "Category", with: self.vehicle?.category ?? "") - 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() ?? "" - 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 ?? "") - self.update(row: "STS", with: self.vehicle?.sts ?? "") - self.update(row: "PTS", with: self.vehicle?.pts ?? "") - self.update(row: "EngineNumber", with: self.vehicle?.engine?.number ?? "") - self.update(row: "FuelType", with: self.vehicle?.engine?.fuelType ?? "") - 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 "" } - 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.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.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) - } -} diff --git a/AutoCat/Controllers/SearchController.swift b/AutoCat/Controllers/SearchController.swift index 0f26657..c38f45f 100644 --- a/AutoCat/Controllers/SearchController.swift +++ b/AutoCat/Controllers/SearchController.swift @@ -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) } } } diff --git a/AutoCat/Controllers/VMResult.swift b/AutoCat/Controllers/VMResult.swift deleted file mode 100644 index b54309d..0000000 --- a/AutoCat/Controllers/VMResult.swift +++ /dev/null @@ -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 { - - 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 - } -} diff --git a/AutoCat/SceneDelegate.swift b/AutoCat/SceneDelegate.swift index 4c9dea3..022456a 100644 --- a/AutoCat/SceneDelegate.swift +++ b/AutoCat/SceneDelegate.swift @@ -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) diff --git a/AutoCat/Screens/ReportScreen/ReportCoordinator.swift b/AutoCat/Screens/ReportScreen/ReportCoordinator.swift index 64db1a3..dda0619 100644 --- a/AutoCat/Screens/ReportScreen/ReportCoordinator.swift +++ b/AutoCat/Screens/ReportScreen/ReportCoordinator.swift @@ -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) {