Adding GB bot check

This commit is contained in:
Selim Mustafaev 2024-12-06 00:29:27 +03:00
parent 037cdd3484
commit 97e35ac785
22 changed files with 126 additions and 146 deletions

View File

@ -36,7 +36,6 @@
7A14416C2C297F2100E79018 /* NotesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416B2C297F2100E79018 /* NotesCoordinator.swift */; }; 7A14416C2C297F2100E79018 /* NotesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416B2C297F2100E79018 /* NotesCoordinator.swift */; };
7A14416E2C297F7C00E79018 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416D2C297F7C00E79018 /* Coordinator.swift */; }; 7A14416E2C297F7C00E79018 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416D2C297F7C00E79018 /* Coordinator.swift */; };
7A1441702C2998B200E79018 /* Formatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416F2C2998B200E79018 /* Formatters.swift */; }; 7A1441702C2998B200E79018 /* Formatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416F2C2998B200E79018 /* Formatters.swift */; };
7A176DB22C43071A00999D6B /* ApiServiceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A176DB12C43071A00999D6B /* ApiServiceStub.swift */; };
7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE492A2E820300626A6E /* UIStackView.swift */; }; 7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE492A2E820300626A6E /* UIStackView.swift */; };
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */; }; 7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */; };
7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80429A41C66007962DA /* RealmSwift */; }; 7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80429A41C66007962DA /* RealmSwift */; };
@ -152,7 +151,6 @@
7AABBE3B2CF9F85600346588 /* Binding+Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABBE3A2CF9F85600346588 /* Binding+Map.swift */; }; 7AABBE3B2CF9F85600346588 /* Binding+Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABBE3A2CF9F85600346588 /* Binding+Map.swift */; };
7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */; }; 7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */; };
7AB0EF812C5CC0FE00291EE6 /* SwiftLocationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */; }; 7AB0EF812C5CC0FE00291EE6 /* SwiftLocationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */; };
7AB0EF892C5D307600291EE6 /* LocationServiceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB0EF882C5D307600291EE6 /* LocationServiceStub.swift */; };
7AB5871D2C42C1CF00FA7B66 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7AB5871C2C42C1CF00FA7B66 /* RealmSwift */; }; 7AB5871D2C42C1CF00FA7B66 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7AB5871C2C42C1CF00FA7B66 /* RealmSwift */; };
7AB587322C42D38E00FA7B66 /* StorageServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB587312C42D38E00FA7B66 /* StorageServiceProtocol.swift */; }; 7AB587322C42D38E00FA7B66 /* StorageServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB587312C42D38E00FA7B66 /* StorageServiceProtocol.swift */; };
7AB587342C42D3FA00FA7B66 /* StorageService+Notes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB587332C42D3FA00FA7B66 /* StorageService+Notes.swift */; }; 7AB587342C42D3FA00FA7B66 /* StorageService+Notes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB587332C42D3FA00FA7B66 /* StorageService+Notes.swift */; };
@ -300,7 +298,6 @@
7A14416D2C297F7C00E79018 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; }; 7A14416D2C297F7C00E79018 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
7A14416F2C2998B200E79018 /* Formatters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Formatters.swift; sourceTree = "<group>"; }; 7A14416F2C2998B200E79018 /* Formatters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Formatters.swift; sourceTree = "<group>"; };
7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; }; 7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; };
7A176DB12C43071A00999D6B /* ApiServiceStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiServiceStub.swift; sourceTree = "<group>"; };
7A17CE492A2E820300626A6E /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = "<group>"; }; 7A17CE492A2E820300626A6E /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = "<group>"; };
7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UISegmentedControl.swift; sourceTree = "<group>"; }; 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UISegmentedControl.swift; sourceTree = "<group>"; };
7A1CF81529A42117007962DA /* Realm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Realm.swift; sourceTree = "<group>"; }; 7A1CF81529A42117007962DA /* Realm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Realm.swift; sourceTree = "<group>"; };
@ -424,7 +421,6 @@
7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxSectionedDataSource.swift; sourceTree = "<group>"; }; 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxSectionedDataSource.swift; sourceTree = "<group>"; };
7AAE6AD224CDDF950023860B /* VehicleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleEvent.swift; sourceTree = "<group>"; }; 7AAE6AD224CDDF950023860B /* VehicleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleEvent.swift; sourceTree = "<group>"; };
7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftLocationProtocol.swift; sourceTree = "<group>"; }; 7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftLocationProtocol.swift; sourceTree = "<group>"; };
7AB0EF882C5D307600291EE6 /* LocationServiceStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationServiceStub.swift; sourceTree = "<group>"; };
7AB562B9249C9E9B00473D53 /* VehicleRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleRegion.swift; sourceTree = "<group>"; }; 7AB562B9249C9E9B00473D53 /* VehicleRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleRegion.swift; sourceTree = "<group>"; };
7AB587222C42D27F00FA7B66 /* AutoCatTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutoCatTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 7AB587222C42D27F00FA7B66 /* AutoCatTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutoCatTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
7AB587312C42D38E00FA7B66 /* StorageServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageServiceProtocol.swift; sourceTree = "<group>"; }; 7AB587312C42D38E00FA7B66 /* StorageServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageServiceProtocol.swift; sourceTree = "<group>"; };
@ -979,8 +975,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7A1E78FB2CE91A590004B740 /* Data */, 7A1E78FB2CE91A590004B740 /* Data */,
7A176DB12C43071A00999D6B /* ApiServiceStub.swift */,
7AB0EF882C5D307600291EE6 /* LocationServiceStub.swift */,
); );
path = Preview; path = Preview;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1377,7 +1371,6 @@
7A1090EC24A4E3E100B4F0B2 /* CellProgressView.swift in Sources */, 7A1090EC24A4E3E100B4F0B2 /* CellProgressView.swift in Sources */,
7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */, 7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */,
7A10227B2C557EE900B84627 /* LocationPickerCoordinator.swift in Sources */, 7A10227B2C557EE900B84627 /* LocationPickerCoordinator.swift in Sources */,
7A176DB22C43071A00999D6B /* ApiServiceStub.swift in Sources */,
7A1090EA24A3A26300B4F0B2 /* AudioPlayer.swift in Sources */, 7A1090EA24A3A26300B4F0B2 /* AudioPlayer.swift in Sources */,
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */, 7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */,
7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */, 7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */,
@ -1417,7 +1410,6 @@
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */, 7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */, 7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */, 7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */,
7AB0EF892C5D307600291EE6 /* LocationServiceStub.swift in Sources */,
7A7158042C43EAA200852088 /* OwnersCoordinator.swift in Sources */, 7A7158042C43EAA200852088 /* OwnersCoordinator.swift in Sources */,
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */, 7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */, 7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */,

View File

@ -259,25 +259,25 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
func updateDetailController(with vehicle: VehicleDto) { func updateDetailController(with vehicle: VehicleDto) {
if let splitViewController = self.view.window?.rootViewController as? UISplitViewController if let splitViewController = self.view.window?.rootViewController as? UISplitViewController
{ {
var detail: UINavigationController? // var detail: UINavigationController?
if splitViewController.viewControllers.count == 2 { // if splitViewController.viewControllers.count == 2 {
detail = splitViewController.viewControllers.last as? UINavigationController // detail = splitViewController.viewControllers.last as? UINavigationController
} else { // } else {
let storyboard = UIStoryboard(name: "Main", bundle: nil) // let storyboard = UIStoryboard(name: "Main", bundle: nil)
detail = storyboard.instantiateViewController(identifier: "ReportNavController") // 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()
// } // }
//
// 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()
}
} }
} }

View File

@ -1,46 +0,0 @@
//
// ApiServiceStub.swift
// AutoCat
//
// Created by Selim Mustafaev on 13.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import AutoCatCore
actor ApiServiceStub: ApiServiceProtocol {
let vehicle = VehicleDto()
func add(notes: [VehicleNoteDto], to number: String) async throws -> VehicleDto {
vehicle
}
func edit(note: VehicleNoteDto) async throws -> VehicleDto {
vehicle
}
func remove(note id: String) async throws -> VehicleDto {
vehicle
}
func getBrands() async throws -> [String] {
[]
}
func getModels(of brand: String) async throws -> [String] {
[]
}
func getColors() async throws -> [String] {
[]
}
func getRegions() async throws -> [AutoCatCore.VehicleRegion] {
[]
}
func getYears() async throws -> [Int] {
[]
}
}

View File

@ -1,27 +0,0 @@
//
// LocationServiceStub.swift
// AutoCat
//
// Created by Selim Mustafaev on 02.08.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import Foundation
import AutoCatCore
final class LocationServiceStub: LocationServiceProtocol {
let event: VehicleEventDto
init(event: VehicleEventDto) {
self.event = event
}
func getAddressForLocation(latitude: Double, longitude: Double) async throws -> String {
event.address ?? ""
}
func requestCurrentLocation() async throws -> AutoCatCore.VehicleEventDto {
event
}
}

View File

@ -51,7 +51,6 @@ struct LocationPickerScreen: View {
var event = VehicleEventDto(lat: 47.250049, lon: 39.711821) var event = VehicleEventDto(lat: 47.250049, lon: 39.711821)
event.address = "Ул. Ленина, 123" event.address = "Ул. Ленина, 123"
let locationService = LocationServiceStub(event: event)
let viewModel = LocationPickerViewModel(event: event) let viewModel = LocationPickerViewModel(event: event)
return LocationPickerScreen(viewModel: viewModel) return LocationPickerScreen(viewModel: viewModel)

View File

@ -27,56 +27,49 @@ class NotesViewModel: ACHudContainer {
} }
func addNote(text: String) async { func addNote(text: String) async {
if vehicle.unrecognized {
await wrapWithToast(showProgress: false) { [weak self] in await noteOperation {
guard let self else { return } try await self.storageService.addNote(text: text, to: self.vehicle.getNumber())
vehicle = try await storageService.addNote(text: text, to: vehicle.getNumber()) } apiOp: {
} let note = VehicleNoteDto(text: text)
return return try await self.apiService.add(notes: [note], to: self.vehicle.getNumber())
}
let note = VehicleNoteDto(text: text)
await wrapWithToast { [weak self] in
guard let self else { return }
let vehicle = try await apiService.add(notes: [note], to: vehicle.getNumber())
try await storageService.updateVehicleIfExists(dto: vehicle)
self.vehicle = vehicle
} }
} }
func deleteNote(id: String) async { func deleteNote(id: String) async {
if vehicle.unrecognized {
await wrapWithToast(showProgress: false) { [weak self] in await noteOperation {
guard let self else { return } try await self.storageService.deleteNote(id: id, for: self.vehicle.getNumber())
vehicle = try await storageService.deleteNote(id: id, for: vehicle.getNumber()) } apiOp: {
} try await self.apiService.remove(note: id)
return
}
await wrapWithToast { [weak self] in
guard let self else { return }
let vehicle = try await apiService.remove(note: id)
try await storageService.updateVehicleIfExists(dto: vehicle)
self.vehicle = vehicle
} }
} }
func editNote(id: String, text: String) async { func editNote(id: String, text: String) async {
await noteOperation {
try await self.storageService.editNote(id: id, text: text, for: self.vehicle.getNumber())
} apiOp: {
var note = VehicleNoteDto(text: text)
note.id = id
return try await self.apiService.edit(note: note)
}
}
func noteOperation(_ storageOp: @escaping () async throws -> VehicleDto,
apiOp: @escaping () async throws -> VehicleDto) async {
if vehicle.unrecognized { if vehicle.unrecognized {
await wrapWithToast(showProgress: false) { [weak self] in await wrapWithToast(showProgress: false) { [weak self] in
guard let self else { return } guard let self else { return }
vehicle = try await storageService.editNote(id: id, text: text, for: vehicle.getNumber()) vehicle = try await storageOp()
} }
return return
} }
var note = VehicleNoteDto(text: text)
note.id = id
await wrapWithToast { [weak self] in await wrapWithToast { [weak self] in
guard let self else { return } guard let self else { return }
let vehicle = try await apiService.edit(note: note) let vehicle = try await apiOp()
try await storageService.updateVehicleIfExists(dto: vehicle) try await storageService.updateVehicleIfExists(dto: vehicle)
self.vehicle = vehicle self.vehicle = vehicle
} }

View File

@ -75,6 +75,12 @@ struct ReportScreen: View {
makeDebugInfoCell(title: "Nomerogram", model: viewModel.vehicle.debugInfo?.nomerogram) makeDebugInfoCell(title: "Nomerogram", model: viewModel.vehicle.debugInfo?.nomerogram)
} }
} }
Section {
Button("Check GB") {
Task { await viewModel.checkGB() }
}
}
} }
.onAppear { .onAppear {
Task { await viewModel.onAppear() } Task { await viewModel.onAppear() }

View File

@ -74,6 +74,15 @@ class ReportViewModel: ACHudContainer {
} }
} }
func checkGB() async {
await wrapWithToast {
self.vehicle = try await self.api.checkVehicleGb(by: self.vehicle.getNumber())
try await self.storageService.updateVehicleIfExists(dto: self.vehicle)
}
}
// MARK: Open detail screens
func openEvents() { func openEvents() {
coordinator?.openEvents(vehicle: vehicle) coordinator?.openEvents(vehicle: vehicle)
} }

View File

@ -8,13 +8,13 @@
import Foundation import Foundation
public enum DebugInfoStatus: Int, Sendable, Decodable { public enum DebugInfoStatus: Int, Sendable, Decodable, Equatable {
case success = 0 case success = 0
case error = 1 case error = 1
case warning = 2 case warning = 2
} }
public struct DebugInfoDto: Decodable, Sendable { public struct DebugInfoDto: Decodable, Sendable, Equatable {
public var autocod: DebugInfoEntryDto public var autocod: DebugInfoEntryDto
public var vin01vin: DebugInfoEntryDto public var vin01vin: DebugInfoEntryDto

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct OsagoDto: Decodable, Sendable { public struct OsagoDto: Decodable, Sendable, Equatable {
public var date: TimeInterval = 0 public var date: TimeInterval = 0
public var number: String = "" public var number: String = ""

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleAdDto: Decodable, Sendable, Hashable { public struct VehicleAdDto: Decodable, Sendable, Hashable, Equatable {
public var id: Int = 0 public var id: Int = 0
public var url: String? public var url: String?

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleBrandDto: Decodable, Sendable { public struct VehicleBrandDto: Decodable, Sendable, Equatable {
public var name: VehicleNameDto? public var name: VehicleNameDto?
public var logo: String? public var logo: String?

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleDto: Sendable { public struct VehicleDto: Sendable, Equatable {
public var brand: VehicleBrandDto? public var brand: VehicleBrandDto?
public var model: VehicleModelDto? public var model: VehicleModelDto?

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleEngineDto: Decodable, Sendable { public struct VehicleEngineDto: Decodable, Sendable, Equatable {
public var number: String? public var number: String?
public var volume: Int? = 0 public var volume: Int? = 0

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleEventDto: Codable, Sendable { public struct VehicleEventDto: Codable, Sendable, Equatable {
public var id: String = UUID().uuidString public var id: String = UUID().uuidString
public var date: TimeInterval = Date().timeIntervalSince1970 public var date: TimeInterval = Date().timeIntervalSince1970

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleModelDto: Decodable, Sendable { public struct VehicleModelDto: Decodable, Sendable, Equatable {
public var name: VehicleNameDto? public var name: VehicleNameDto?
} }

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleNameDto: Decodable, Sendable { public struct VehicleNameDto: Decodable, Sendable, Equatable {
public var original: String? public var original: String?
public var normalized: String? public var normalized: String?

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleNoteDto: Codable, Sendable, Identifiable { public struct VehicleNoteDto: Codable, Sendable, Identifiable, Equatable {
public var id: String = UUID().uuidString public var id: String = UUID().uuidString
public var user: String = "" public var user: String = ""

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehicleOwnershipPeriodDto: Decodable, Sendable { public struct VehicleOwnershipPeriodDto: Decodable, Sendable, Equatable {
public var lastOperation: String = "" public var lastOperation: String = ""
public var ownerType: String = "" public var ownerType: String = ""

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public struct VehiclePhotoDto: Decodable, Sendable { public struct VehiclePhotoDto: Decodable, Sendable, Equatable {
public var brand: String? public var brand: String?
public var model: String? public var model: String?

View File

@ -20,4 +20,6 @@ public protocol ApiServiceProtocol: Sendable {
func getColors() async throws -> [String] func getColors() async throws -> [String]
func getRegions() async throws -> [VehicleRegion] func getRegions() async throws -> [VehicleRegion]
func getYears() async throws -> [Int] func getYears() async throws -> [Int]
func checkVehicleGb(by number: String) async throws -> VehicleDto
} }

View File

@ -20,15 +20,18 @@ class ReportTests {
var storageServiceMock: MockStorageServiceProtocol var storageServiceMock: MockStorageServiceProtocol
var settingsServiceMock: MockSettingsServiceProtocol var settingsServiceMock: MockSettingsServiceProtocol
var apiServiceMock: MockApiServiceProtocol
var viewModel: ReportViewModel var viewModel: ReportViewModel
init() { init() {
storageServiceMock = MockStorageServiceProtocol() storageServiceMock = MockStorageServiceProtocol()
settingsServiceMock = MockSettingsServiceProtocol() settingsServiceMock = MockSettingsServiceProtocol()
apiServiceMock = MockApiServiceProtocol()
ServiceContainer.shared.register(StorageServiceProtocol.self, instance: storageServiceMock) ServiceContainer.shared.register(StorageServiceProtocol.self, instance: storageServiceMock)
ServiceContainer.shared.register(SettingsServiceProtocol.self, instance: settingsServiceMock) ServiceContainer.shared.register(SettingsServiceProtocol.self, instance: settingsServiceMock)
ServiceContainer.shared.register(ApiServiceProtocol.self, instance: apiServiceMock)
viewModel = ReportViewModel(vehicle: VehicleDto(), isPersistent: true) viewModel = ReportViewModel(vehicle: VehicleDto(), isPersistent: true)
} }
@ -84,4 +87,53 @@ class ReportTests {
#expect(viewModel.showDebugInfo == value) #expect(viewModel.showDebugInfo == value)
} }
@Test("Check GB bot report", arguments: [true, false])
func checkGbBotReport(isPersistent: Bool) async throws {
let vehicle = VehicleDto(number: existingVehicleNumber)
let updatedVehicle = VehicleDto(number: existingVehicleNumber, color: testColor)
viewModel = ReportViewModel(vehicle: vehicle, isPersistent: isPersistent)
given(apiServiceMock)
.checkVehicleGb(by: .value(existingVehicleNumber))
.willReturn(updatedVehicle)
given(storageServiceMock)
.updateVehicleIfExists(dto: .value(updatedVehicle))
.willReturn()
await viewModel.checkGB()
verify(apiServiceMock)
.checkVehicleGb(by: .value(existingVehicleNumber))
.called(.once)
verify(storageServiceMock)
.updateVehicleIfExists(dto: .value(updatedVehicle))
.called(.once)
#expect(viewModel.vehicle.color == testColor)
#expect(viewModel.hud == nil)
}
@Test("Check GB error", arguments: [true, false])
func checkGbError(isPersistent: Bool) async throws {
let vehicle = VehicleDto(number: existingVehicleNumber)
viewModel = ReportViewModel(vehicle: vehicle, isPersistent: isPersistent)
given(apiServiceMock)
.checkVehicleGb(by: .value(existingVehicleNumber))
.willThrow(TestError.generic)
await viewModel.checkGB()
verify(apiServiceMock)
.checkVehicleGb(by: .value(existingVehicleNumber))
.called(.once)
#expect(viewModel.hud == .error(TestError.generic))
}
} }