Checking vehicles by VIN
This commit is contained in:
parent
fe46f42fea
commit
0c8fa61601
@ -26,6 +26,7 @@
|
|||||||
7A1E78F62CE900330004B740 /* ReportScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78F52CE900330004B740 /* ReportScreen.swift */; };
|
7A1E78F62CE900330004B740 /* ReportScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78F52CE900330004B740 /* ReportScreen.swift */; };
|
||||||
7A1E78F82CE900440004B740 /* ReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78F72CE900440004B740 /* ReportViewModel.swift */; };
|
7A1E78F82CE900440004B740 /* ReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78F72CE900440004B740 /* ReportViewModel.swift */; };
|
||||||
7A1E78FF2CE91A740004B740 /* Vehicle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78FE2CE91A740004B740 /* Vehicle.swift */; };
|
7A1E78FF2CE91A740004B740 /* Vehicle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78FE2CE91A740004B740 /* Vehicle.swift */; };
|
||||||
|
7A2A8F772DEF205A00FC0AE2 /* VehicleNumberType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2A8F762DEF205A00FC0AE2 /* VehicleNumberType.swift */; };
|
||||||
7A2C96122C3B155B00AE46B5 /* NoteAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2C96112C3B155B00AE46B5 /* NoteAlertModifier.swift */; };
|
7A2C96122C3B155B00AE46B5 /* NoteAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2C96112C3B155B00AE46B5 /* NoteAlertModifier.swift */; };
|
||||||
7A2E11292CCE395300E5CA17 /* OptionalDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */; };
|
7A2E11292CCE395300E5CA17 /* OptionalDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */; };
|
||||||
7A2E6FA72C42B3AD00C40DA7 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; };
|
7A2E6FA72C42B3AD00C40DA7 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; };
|
||||||
@ -41,7 +42,6 @@
|
|||||||
7A4927D52CCE438600851C01 /* OptionalBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4927D42CCE438600851C01 /* OptionalBinding.swift */; };
|
7A4927D52CCE438600851C01 /* OptionalBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4927D42CCE438600851C01 /* OptionalBinding.swift */; };
|
||||||
7A4955822D58CCF900912E66 /* HistoryFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4955812D58CCF900912E66 /* HistoryFilter.swift */; };
|
7A4955822D58CCF900912E66 /* HistoryFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4955812D58CCF900912E66 /* HistoryFilter.swift */; };
|
||||||
7A54BFD32D43B95E00176D6D /* DbUpdatePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A54BFD22D43B95E00176D6D /* DbUpdatePolicy.swift */; };
|
7A54BFD32D43B95E00176D6D /* DbUpdatePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A54BFD22D43B95E00176D6D /* DbUpdatePolicy.swift */; };
|
||||||
7A5631CE2DE4B638001070D6 /* VehicleCheckType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5631CD2DE4B638001070D6 /* VehicleCheckType.swift */; };
|
|
||||||
7A589E0F2D6B6E8E00EF3FBE /* NumberEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */; };
|
7A589E0F2D6B6E8E00EF3FBE /* NumberEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */; };
|
||||||
7A5911EE2D63226F00EC51BA /* SearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911ED2D63226F00EC51BA /* SearchScreen.swift */; };
|
7A5911EE2D63226F00EC51BA /* SearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911ED2D63226F00EC51BA /* SearchScreen.swift */; };
|
||||||
7A5911F02D63266B00EC51BA /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911EF2D63266B00EC51BA /* SearchViewModel.swift */; };
|
7A5911F02D63266B00EC51BA /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911EF2D63266B00EC51BA /* SearchViewModel.swift */; };
|
||||||
@ -275,6 +275,7 @@
|
|||||||
7A1E78F72CE900440004B740 /* ReportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportViewModel.swift; sourceTree = "<group>"; };
|
7A1E78F72CE900440004B740 /* ReportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportViewModel.swift; sourceTree = "<group>"; };
|
||||||
7A1E78FE2CE91A740004B740 /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = "<group>"; };
|
7A1E78FE2CE91A740004B740 /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = "<group>"; };
|
||||||
7A27ADF824A09CAD0035F39E /* CocoaError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CocoaError.swift; sourceTree = "<group>"; };
|
7A27ADF824A09CAD0035F39E /* CocoaError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CocoaError.swift; sourceTree = "<group>"; };
|
||||||
|
7A2A8F762DEF205A00FC0AE2 /* VehicleNumberType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleNumberType.swift; sourceTree = "<group>"; };
|
||||||
7A2C96112C3B155B00AE46B5 /* NoteAlertModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteAlertModifier.swift; sourceTree = "<group>"; };
|
7A2C96112C3B155B00AE46B5 /* NoteAlertModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteAlertModifier.swift; sourceTree = "<group>"; };
|
||||||
7A2DE69725868AC800A113FC /* VehicleAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleAd.swift; sourceTree = "<group>"; };
|
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>"; };
|
7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalDatePicker.swift; sourceTree = "<group>"; };
|
||||||
@ -293,7 +294,6 @@
|
|||||||
7A52AB292580112E002CD910 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
7A52AB292580112E002CD910 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
7A530B7F2401803A00CBFE6E /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = "<group>"; };
|
7A530B7F2401803A00CBFE6E /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = "<group>"; };
|
||||||
7A54BFD22D43B95E00176D6D /* DbUpdatePolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DbUpdatePolicy.swift; sourceTree = "<group>"; };
|
7A54BFD22D43B95E00176D6D /* DbUpdatePolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DbUpdatePolicy.swift; sourceTree = "<group>"; };
|
||||||
7A5631CD2DE4B638001070D6 /* VehicleCheckType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCheckType.swift; sourceTree = "<group>"; };
|
|
||||||
7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberEditView.swift; sourceTree = "<group>"; };
|
7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberEditView.swift; sourceTree = "<group>"; };
|
||||||
7A5911ED2D63226F00EC51BA /* SearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchScreen.swift; sourceTree = "<group>"; };
|
7A5911ED2D63226F00EC51BA /* SearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchScreen.swift; sourceTree = "<group>"; };
|
||||||
7A5911EF2D63266B00EC51BA /* SearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = "<group>"; };
|
7A5911EF2D63266B00EC51BA /* SearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = "<group>"; };
|
||||||
@ -915,6 +915,7 @@
|
|||||||
children = (
|
children = (
|
||||||
7AB4E43A2D3D3F4F0006D052 /* VehicleServiceProtocol.swift */,
|
7AB4E43A2D3D3F4F0006D052 /* VehicleServiceProtocol.swift */,
|
||||||
7AB4E43C2D3D3F7A0006D052 /* VehicleService.swift */,
|
7AB4E43C2D3D3F7A0006D052 /* VehicleService.swift */,
|
||||||
|
7A2A8F762DEF205A00FC0AE2 /* VehicleNumberType.swift */,
|
||||||
);
|
);
|
||||||
path = VehicleService;
|
path = VehicleService;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1001,7 +1002,6 @@
|
|||||||
7A8652452DE4484700AEBF27 /* ACVinKeyboardView.swift */,
|
7A8652452DE4484700AEBF27 /* ACVinKeyboardView.swift */,
|
||||||
7AB4902A2D6B1446002F39C6 /* ACKeyboardButton.swift */,
|
7AB4902A2D6B1446002F39C6 /* ACKeyboardButton.swift */,
|
||||||
7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */,
|
7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */,
|
||||||
7A5631CD2DE4B638001070D6 /* VehicleCheckType.swift */,
|
|
||||||
);
|
);
|
||||||
path = NumberEditView;
|
path = NumberEditView;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1337,7 +1337,6 @@
|
|||||||
7A06E0AE2C7065C7005731AC /* SettingsViewModel.swift in Sources */,
|
7A06E0AE2C7065C7005731AC /* SettingsViewModel.swift in Sources */,
|
||||||
7AB4E42C2D397D8E0006D052 /* VehicleCellView.swift in Sources */,
|
7AB4E42C2D397D8E0006D052 /* VehicleCellView.swift in Sources */,
|
||||||
7A91CE9A2DC2470F00DBA953 /* TextFieldDumbModifier.swift in Sources */,
|
7A91CE9A2DC2470F00DBA953 /* TextFieldDumbModifier.swift in Sources */,
|
||||||
7A5631CE2DE4B638001070D6 /* VehicleCheckType.swift in Sources */,
|
|
||||||
7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */,
|
7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */,
|
||||||
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */,
|
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */,
|
||||||
7AC44B822DB390B900ADC026 /* MainTabScreen.swift in Sources */,
|
7AC44B822DB390B900ADC026 /* MainTabScreen.swift in Sources */,
|
||||||
@ -1446,6 +1445,7 @@
|
|||||||
7A95197B2D80B41600E69883 /* AudioRecordServiceProtocol.swift in Sources */,
|
7A95197B2D80B41600E69883 /* AudioRecordServiceProtocol.swift in Sources */,
|
||||||
7AF6D21C2677C1680086EA64 /* DebugInfo.swift in Sources */,
|
7AF6D21C2677C1680086EA64 /* DebugInfo.swift in Sources */,
|
||||||
7ABDA80D2D8721B10083C715 /* Substrings.swift in Sources */,
|
7ABDA80D2D8721B10083C715 /* Substrings.swift in Sources */,
|
||||||
|
7A2A8F772DEF205A00FC0AE2 /* VehicleNumberType.swift in Sources */,
|
||||||
7AF6D2142677C1680086EA64 /* VehicleEvent.swift in Sources */,
|
7AF6D2142677C1680086EA64 /* VehicleEvent.swift in Sources */,
|
||||||
7A64A2102C19E1EB00284124 /* VehicleBrandDto.swift in Sources */,
|
7A64A2102C19E1EB00284124 /* VehicleBrandDto.swift in Sources */,
|
||||||
7A599C392C18B22900D47C18 /* FbRefreshTokenModel.swift in Sources */,
|
7A599C392C18B22900D47C18 /* FbRefreshTokenModel.swift in Sources */,
|
||||||
|
|||||||
@ -28,7 +28,7 @@ struct HistoryScreen: View {
|
|||||||
ForEach(section.elements) { vehicle in
|
ForEach(section.elements) { vehicle in
|
||||||
vehicleCell(vehicle)
|
vehicleCell(vehicle)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
viewModel.openVehicleDetail(vehicle)
|
viewModel.openVehicleDetail(vehicle, numberType: .plateNumber)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -131,11 +131,16 @@ final class HistoryViewModel: ACHudContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkVehicle(number: String, type: CheckType, trackLocation: Bool = true) async {
|
func checkVehicle(
|
||||||
|
number: String,
|
||||||
|
numberType: VehicleNumberType = .plateNumber,
|
||||||
|
checkType: CheckType,
|
||||||
|
trackLocation: Bool = true
|
||||||
|
) async {
|
||||||
do {
|
do {
|
||||||
hud = .progress
|
hud = .progress
|
||||||
let (vehicle, errors) = switch type {
|
let (vehicle, errors) = switch checkType {
|
||||||
case .normal: try await vehicleService.check(number: number, trackLocation: trackLocation)
|
case .normal: try await vehicleService.check(number: number, numberType: numberType, trackLocation: trackLocation)
|
||||||
case .update: try await vehicleService.updateHistory(number: number)
|
case .update: try await vehicleService.updateHistory(number: number)
|
||||||
case .record(let event): try await vehicleService.checkRecord(number: number, event: event)
|
case .record(let event): try await vehicleService.checkRecord(number: number, event: event)
|
||||||
}
|
}
|
||||||
@ -145,7 +150,7 @@ final class HistoryViewModel: ACHudContainer {
|
|||||||
if errors.isEmpty {
|
if errors.isEmpty {
|
||||||
hud = nil
|
hud = nil
|
||||||
if !vehicle.unrecognized {
|
if !vehicle.unrecognized {
|
||||||
openVehicleDetail(vehicle)
|
openVehicleDetail(vehicle, numberType: numberType)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showErrors(errors)
|
showErrors(errors)
|
||||||
@ -155,19 +160,25 @@ final class HistoryViewModel: ACHudContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openVehicleDetail(_ vehicle: VehicleDto) {
|
func openVehicleDetail(_ vehicle: VehicleDto, numberType: VehicleNumberType) {
|
||||||
if Device.isIPhone {
|
if Device.isIPhone {
|
||||||
|
switch numberType {
|
||||||
|
case .plateNumber:
|
||||||
Router.shared.openLocalReport(vehicle: vehicle)
|
Router.shared.openLocalReport(vehicle: vehicle)
|
||||||
|
case .vin:
|
||||||
|
Router.shared.openSharedReport(vehicle: vehicle)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
selectedVehicleId = vehicle.id
|
selectedVehicleId = vehicle.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkNewNumber(_ number: String, checkType: VehicleCheckType, enableLocation: Bool) async {
|
func checkNewNumber(_ number: String, numberType: VehicleNumberType, enableLocation: Bool) async {
|
||||||
|
|
||||||
await checkVehicle(
|
await checkVehicle(
|
||||||
number: number,
|
number: number,
|
||||||
type: .normal,
|
numberType: numberType,
|
||||||
|
checkType: .normal,
|
||||||
trackLocation: enableLocation
|
trackLocation: enableLocation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -181,11 +192,11 @@ final class HistoryViewModel: ACHudContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateVehicle(_ vehicle: VehicleDto) async {
|
func updateVehicle(_ vehicle: VehicleDto) async {
|
||||||
await checkVehicle(number: vehicle.getNumber(), type: .update)
|
await checkVehicle(number: vehicle.getNumber(), checkType: .update)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkRecord(number: String, event: VehicleEventDto?) async {
|
func checkRecord(number: String, event: VehicleEventDto?) async {
|
||||||
await checkVehicle(number: number, type: .record(event))
|
await checkVehicle(number: number, checkType: .record(event))
|
||||||
}
|
}
|
||||||
|
|
||||||
func onVehicleChanged(_ vehicle: VehicleDto) {
|
func onVehicleChanged(_ vehicle: VehicleDto) {
|
||||||
|
|||||||
@ -70,14 +70,14 @@ struct MainSplitScreen: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var numberEditSheet: some View {
|
var numberEditSheet: some View {
|
||||||
NumberEditView { number, checkType, enableLocation in
|
NumberEditView { number, numberType, enableLocation in
|
||||||
|
|
||||||
checkNumberSheetOpened = false
|
checkNumberSheetOpened = false
|
||||||
selection = .history
|
selection = .history
|
||||||
Task {
|
Task {
|
||||||
await historyViewModel.checkNewNumber(
|
await historyViewModel.checkNewNumber(
|
||||||
number,
|
number,
|
||||||
checkType: checkType,
|
numberType: numberType,
|
||||||
enableLocation: enableLocation
|
enableLocation: enableLocation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,14 +102,14 @@ struct MainTabScreen: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var numberEditSheet: some View {
|
var numberEditSheet: some View {
|
||||||
NumberEditView { number, checkType, enableLocation in
|
NumberEditView { number, numberType, enableLocation in
|
||||||
|
|
||||||
checkNumberSheetOpened = false
|
checkNumberSheetOpened = false
|
||||||
selection = .history
|
selection = .history
|
||||||
Task {
|
Task {
|
||||||
await historyViewModel.checkNewNumber(
|
await historyViewModel.checkNewNumber(
|
||||||
number,
|
number,
|
||||||
checkType: checkType,
|
numberType: numberType,
|
||||||
enableLocation: enableLocation
|
enableLocation: enableLocation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,21 @@ import AutoCatCore
|
|||||||
|
|
||||||
struct NumberEditView: View {
|
struct NumberEditView: View {
|
||||||
|
|
||||||
let onCheck: (String, VehicleCheckType, Bool) -> Void
|
let onCheck: (String, VehicleNumberType, Bool) -> Void
|
||||||
|
|
||||||
@State var number = PlateNumber("")
|
@State var number = PlateNumber("")
|
||||||
@State var enableLocation: Bool = true
|
@State var enableLocation: Bool = true
|
||||||
@State var checkType: VehicleCheckType = .plateNumber
|
@State var checkType: VehicleNumberType = .plateNumber
|
||||||
|
@State var vin: String = ""
|
||||||
|
|
||||||
|
var checkButtonEnabled: Bool {
|
||||||
|
switch checkType {
|
||||||
|
case .plateNumber:
|
||||||
|
number.isValid
|
||||||
|
case .vin:
|
||||||
|
vin.count == 17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
@ -23,32 +33,13 @@ struct NumberEditView: View {
|
|||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
|
||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
LicensePlateView(number: number, foreground: .primary)
|
numberField
|
||||||
.layoutPriority(1)
|
checkButton
|
||||||
.frame(height: 50)
|
|
||||||
.fixedSize(horizontal: true, vertical: false)
|
|
||||||
|
|
||||||
Button {
|
|
||||||
onCheck(number.asString(), checkType, enableLocation)
|
|
||||||
} label: {
|
|
||||||
Text("Check")
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
.padding(.vertical, 16)
|
|
||||||
.padding(.horizontal, 12)
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 6)
|
|
||||||
.fill(.blue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//.layoutPriority(0)
|
|
||||||
.frame(height: 50)
|
|
||||||
.opacity(number.isValid ? 1 : 0.5)
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 4)
|
.padding(.horizontal, 4)
|
||||||
|
|
||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
Picker("Location", selection: $enableLocation) {
|
Picker("Location", selection: checkType == .vin ? .constant(false) : $enableLocation) {
|
||||||
Image(systemName: "location")
|
Image(systemName: "location")
|
||||||
.tag(true)
|
.tag(true)
|
||||||
Image(systemName: "location.slash")
|
Image(systemName: "location.slash")
|
||||||
@ -56,9 +47,10 @@ struct NumberEditView: View {
|
|||||||
}
|
}
|
||||||
.pickerStyle(.segmented)
|
.pickerStyle(.segmented)
|
||||||
.frame(width: 120)
|
.frame(width: 120)
|
||||||
|
.disabled(checkType == .vin)
|
||||||
|
|
||||||
Picker("Check type", selection: $checkType) {
|
Picker("Check type", selection: $checkType) {
|
||||||
ForEach(VehicleCheckType.allCases) { type in
|
ForEach(VehicleNumberType.allCases) { type in
|
||||||
Text(type.title)
|
Text(type.title)
|
||||||
.selectionDisabled(!type.enabled)
|
.selectionDisabled(!type.enabled)
|
||||||
}
|
}
|
||||||
@ -80,14 +72,113 @@ struct NumberEditView: View {
|
|||||||
.gesture(DragGesture(), including: .gesture)
|
.gesture(DragGesture(), including: .gesture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var numberField: some View {
|
||||||
|
|
||||||
|
Group {
|
||||||
|
switch checkType {
|
||||||
|
case .plateNumber:
|
||||||
|
LicensePlateView(number: number, foreground: .primary)
|
||||||
|
.fixedSize(horizontal: true, vertical: false)
|
||||||
|
case .vin:
|
||||||
|
Text(vin)
|
||||||
|
.padding(12)
|
||||||
|
.frame(height: 50)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.font(.system(size: 20))
|
||||||
|
.background {
|
||||||
|
RoundedRectangle(cornerRadius: 6)
|
||||||
|
.stroke(.gray)
|
||||||
|
.fill(.background)
|
||||||
|
}
|
||||||
|
.contextMenu { pasteboardMenu }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(height: 50)
|
||||||
|
.layoutPriority(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
var pasteboardMenu: some View {
|
||||||
|
if !vin.isEmpty {
|
||||||
|
Button {
|
||||||
|
UIPasteboard.general.string = vin
|
||||||
|
} label: {
|
||||||
|
Label("Copy", systemImage: "document.on.document")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let value = UIPasteboard.general.string {
|
||||||
|
Button {
|
||||||
|
vin = value
|
||||||
|
} label: {
|
||||||
|
Label("Paste", systemImage: "document.on.clipboard")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkButton: some View {
|
||||||
|
|
||||||
|
Button {
|
||||||
|
switch checkType {
|
||||||
|
case .plateNumber:
|
||||||
|
onCheck(number.asString(), checkType, enableLocation)
|
||||||
|
case .vin:
|
||||||
|
onCheck(vin, .vin, false)
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Text("Check")
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.padding(.vertical, 16)
|
||||||
|
.padding(.horizontal, 12)
|
||||||
|
.background {
|
||||||
|
RoundedRectangle(cornerRadius: 6)
|
||||||
|
.fill(.blue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//.layoutPriority(0)
|
||||||
|
.frame(height: 50)
|
||||||
|
.opacity(checkButtonEnabled ? 1 : 0.5)
|
||||||
|
.disabled(!checkButtonEnabled)
|
||||||
|
.fixedSize(horizontal: checkType == .vin, vertical: false)
|
||||||
|
}
|
||||||
|
|
||||||
func buttonPressed(type: PNButtonType) {
|
func buttonPressed(type: PNButtonType) {
|
||||||
|
|
||||||
|
switch checkType {
|
||||||
|
case .plateNumber:
|
||||||
|
plateNumberChanged(type: type)
|
||||||
|
case .vin:
|
||||||
|
vinChanged(type: type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func plateNumberChanged(type: PNButtonType) {
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .symbol(let s), .vin(let s):
|
case .symbol(let s):
|
||||||
number.insertText(String(s))
|
number.insertText(String(s))
|
||||||
case .backspace:
|
case .backspace:
|
||||||
number.deleteBackward()
|
number.deleteBackward()
|
||||||
case .done:
|
case .done:
|
||||||
onCheck(number.asString(), checkType, enableLocation)
|
onCheck(number.asString(), .plateNumber, enableLocation)
|
||||||
|
case .vin:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func vinChanged(type: PNButtonType) {
|
||||||
|
guard vin.count < 17 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .symbol(let s), .vin(let s):
|
||||||
|
vin.append(String(s))
|
||||||
|
case .backspace:
|
||||||
|
vin.removeLast()
|
||||||
|
case .done:
|
||||||
|
onCheck(vin, .vin, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -188,4 +188,8 @@ extension VehicleDto {
|
|||||||
public var needSync: Bool {
|
public var needSync: Bool {
|
||||||
!synchronized && !unrecognized
|
!synchronized && !unrecognized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var plateNumberComplete: Bool {
|
||||||
|
number.count >= 8 && !number.contains { $0 == "*" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,22 +3,22 @@ import RealmSwift
|
|||||||
|
|
||||||
public final class DebugInfo: Object {
|
public final class DebugInfo: Object {
|
||||||
|
|
||||||
@Persisted public var autocod: DebugInfoEntry!
|
@Persisted public var autocod: DebugInfoEntry?
|
||||||
@Persisted public var vin01vin: DebugInfoEntry!
|
@Persisted public var vin01vin: DebugInfoEntry?
|
||||||
@Persisted public var vin01base: DebugInfoEntry!
|
@Persisted public var vin01base: DebugInfoEntry?
|
||||||
@Persisted public var vin01history: DebugInfoEntry!
|
@Persisted public var vin01history: DebugInfoEntry?
|
||||||
@Persisted public var nomerogram: DebugInfoEntry!
|
@Persisted public var nomerogram: DebugInfoEntry?
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DebugInfo: DtoConvertible {
|
extension DebugInfo: DtoConvertible {
|
||||||
|
|
||||||
public var dto: DebugInfoDto {
|
public var dto: DebugInfoDto {
|
||||||
|
|
||||||
DebugInfoDto(autocod: autocod.dto,
|
DebugInfoDto(autocod: autocod?.dto,
|
||||||
vin01vin: vin01vin.dto,
|
vin01vin: vin01vin?.dto,
|
||||||
vin01base: vin01base.dto,
|
vin01base: vin01base?.dto,
|
||||||
vin01history: vin01history.dto,
|
vin01history: vin01history?.dto,
|
||||||
nomerogram: nomerogram.dto)
|
nomerogram: nomerogram?.dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(dto: DebugInfoDto) {
|
public convenience init(dto: DebugInfoDto) {
|
||||||
|
|||||||
@ -247,13 +247,20 @@ public actor ApiService: ApiServiceProtocol {
|
|||||||
return try await makeGetRequest(api: "vehicles", params: params)
|
return try await makeGetRequest(api: "vehicles", params: params)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func checkVehicle(by number: String, notes: [VehicleNoteDto], events: [VehicleEventDto], force: Bool = false) async throws -> VehicleDto {
|
public func checkVehicle(
|
||||||
|
by number: String,
|
||||||
|
numberType: VehicleNumberType,
|
||||||
|
notes: [VehicleNoteDto],
|
||||||
|
events: [VehicleEventDto],
|
||||||
|
force: Bool = false
|
||||||
|
) async throws -> VehicleDto {
|
||||||
|
|
||||||
try await refreshFbToken()
|
try await refreshFbToken()
|
||||||
|
|
||||||
var body = [
|
var body = [
|
||||||
"number": AnyEncodable(number),
|
"number": AnyEncodable(number),
|
||||||
"forceUpdate": AnyEncodable(force)
|
"forceUpdate": AnyEncodable(force),
|
||||||
|
"type": AnyEncodable(numberType.value)
|
||||||
]
|
]
|
||||||
|
|
||||||
if let token = await settingsService.user.firebaseIdToken {
|
if let token = await settingsService.user.firebaseIdToken {
|
||||||
|
|||||||
@ -29,7 +29,13 @@ public protocol ApiServiceProtocol: Sendable {
|
|||||||
func getRegions() async throws -> [VehicleRegion]
|
func getRegions() async throws -> [VehicleRegion]
|
||||||
func getYears() async throws -> [Int]
|
func getYears() async throws -> [Int]
|
||||||
|
|
||||||
func checkVehicle(by number: String, notes: [VehicleNoteDto], events: [VehicleEventDto], force: Bool) async throws -> VehicleDto
|
func checkVehicle(
|
||||||
|
by number: String,
|
||||||
|
numberType: VehicleNumberType,
|
||||||
|
notes: [VehicleNoteDto],
|
||||||
|
events: [VehicleEventDto],
|
||||||
|
force: Bool
|
||||||
|
) async throws -> VehicleDto
|
||||||
func checkVehicleGb(by number: String) async throws -> VehicleDto
|
func checkVehicleGb(by number: String) async throws -> VehicleDto
|
||||||
|
|
||||||
func getVehicles(with filter: Filter, pageToken: String?, pageSize: Int) async throws -> PagedResponse<VehicleDto>
|
func getVehicles(with filter: Filter, pageToken: String?, pageSize: Int) async throws -> PagedResponse<VehicleDto>
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public actor StorageService: StorageServiceProtocol {
|
|||||||
realmConfig.inMemoryIdentifier = UUID().uuidString
|
realmConfig.inMemoryIdentifier = UUID().uuidString
|
||||||
} else {
|
} else {
|
||||||
realmConfig = Realm.Configuration(
|
realmConfig = Realm.Configuration(
|
||||||
schemaVersion: 42,
|
schemaVersion: 43,
|
||||||
migrationBlock: { migration, oldSchemaVersion in }
|
migrationBlock: { migration, oldSchemaVersion in }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum VehicleCheckType: Hashable, CaseIterable, Identifiable {
|
public enum VehicleNumberType: Hashable, CaseIterable, Identifiable, Sendable {
|
||||||
|
|
||||||
case plateNumber
|
case plateNumber
|
||||||
case vin
|
case vin
|
||||||
|
|
||||||
var title: String {
|
public var title: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .plateNumber:
|
case .plateNumber:
|
||||||
return String(localized: "Plate number")
|
return String(localized: "Plate number")
|
||||||
@ -22,12 +22,19 @@ enum VehicleCheckType: Hashable, CaseIterable, Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var enabled: Bool {
|
public var value: String {
|
||||||
|
switch self {
|
||||||
|
case .plateNumber: "GRZ"
|
||||||
|
case .vin: "VIN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var enabled: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
case .plateNumber: true
|
case .plateNumber: true
|
||||||
case .vin: true
|
case .vin: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var id: Self { self }
|
public var id: Self { self }
|
||||||
}
|
}
|
||||||
@ -33,13 +33,20 @@ extension VehicleService: VehicleServiceProtocol {
|
|||||||
|
|
||||||
func check(
|
func check(
|
||||||
number: String,
|
number: String,
|
||||||
|
numberType: VehicleNumberType,
|
||||||
forceUpdate: Bool,
|
forceUpdate: Bool,
|
||||||
trackLocation: Bool,
|
trackLocation: Bool,
|
||||||
additionalEvent: VehicleEventDto?,
|
additionalEvent: VehicleEventDto?,
|
||||||
dbUpdatePolicy: DbUpdatePolicy
|
dbUpdatePolicy: DbUpdatePolicy
|
||||||
) async throws -> VehicleWithErrors {
|
) async throws -> VehicleWithErrors {
|
||||||
|
|
||||||
var vehicle = (try? await storageService.loadVehicle(number: number)) ?? VehicleDto(number: number)
|
var vehicle = switch numberType {
|
||||||
|
case .plateNumber:
|
||||||
|
(try? await storageService.loadVehicle(number: number)) ?? VehicleDto(number: number)
|
||||||
|
case .vin:
|
||||||
|
VehicleDto()
|
||||||
|
}
|
||||||
|
|
||||||
var errors: [Error] = []
|
var errors: [Error] = []
|
||||||
|
|
||||||
let notes = vehicle.notes
|
let notes = vehicle.notes
|
||||||
@ -58,7 +65,13 @@ extension VehicleService: VehicleServiceProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async let locationTask = trackLocation ? locationService.getRecentLocation() : nil
|
async let locationTask = trackLocation ? locationService.getRecentLocation() : nil
|
||||||
async let vehicleTask = apiService.checkVehicle(by: number, notes: notes, events: events, force: forceUpdate)
|
async let vehicleTask = apiService.checkVehicle(
|
||||||
|
by: number,
|
||||||
|
numberType: numberType,
|
||||||
|
notes: notes,
|
||||||
|
events: events,
|
||||||
|
force: forceUpdate
|
||||||
|
)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
vehicle = try await vehicleTask
|
vehicle = try await vehicleTask
|
||||||
@ -82,16 +95,20 @@ extension VehicleService: VehicleServiceProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await locationService.resetLastEvent()
|
await locationService.resetLastEvent()
|
||||||
|
|
||||||
|
if vehicle.plateNumberComplete {
|
||||||
try await storageService.updateVehicle(dto: vehicle, policy: dbUpdatePolicy)
|
try await storageService.updateVehicle(dto: vehicle, policy: dbUpdatePolicy)
|
||||||
|
}
|
||||||
|
|
||||||
return VehicleWithErrors(vehicle: vehicle, errors: errors)
|
return VehicleWithErrors(vehicle: vehicle, errors: errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func check(number: String, trackLocation: Bool) async throws -> VehicleWithErrors {
|
public func check(number: String, numberType: VehicleNumberType, trackLocation: Bool) async throws -> VehicleWithErrors {
|
||||||
|
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
try await check(
|
try await check(
|
||||||
number: number,
|
number: number,
|
||||||
|
numberType: numberType,
|
||||||
forceUpdate: false,
|
forceUpdate: false,
|
||||||
trackLocation: false,
|
trackLocation: false,
|
||||||
additionalEvent: nil,
|
additionalEvent: nil,
|
||||||
@ -100,6 +117,7 @@ extension VehicleService: VehicleServiceProtocol {
|
|||||||
#else
|
#else
|
||||||
try await check(
|
try await check(
|
||||||
number: number,
|
number: number,
|
||||||
|
numberType: numberType,
|
||||||
forceUpdate: false,
|
forceUpdate: false,
|
||||||
trackLocation: trackLocation,
|
trackLocation: trackLocation,
|
||||||
additionalEvent: nil,
|
additionalEvent: nil,
|
||||||
@ -112,6 +130,7 @@ extension VehicleService: VehicleServiceProtocol {
|
|||||||
|
|
||||||
try await check(
|
try await check(
|
||||||
number: number,
|
number: number,
|
||||||
|
numberType: .plateNumber,
|
||||||
forceUpdate: true,
|
forceUpdate: true,
|
||||||
trackLocation: false,
|
trackLocation: false,
|
||||||
additionalEvent: nil,
|
additionalEvent: nil,
|
||||||
@ -123,6 +142,7 @@ extension VehicleService: VehicleServiceProtocol {
|
|||||||
|
|
||||||
try await check(
|
try await check(
|
||||||
number: number,
|
number: number,
|
||||||
|
numberType: .plateNumber,
|
||||||
forceUpdate: true,
|
forceUpdate: true,
|
||||||
trackLocation: false,
|
trackLocation: false,
|
||||||
additionalEvent: nil,
|
additionalEvent: nil,
|
||||||
@ -134,6 +154,7 @@ extension VehicleService: VehicleServiceProtocol {
|
|||||||
|
|
||||||
try await check(
|
try await check(
|
||||||
number: number,
|
number: number,
|
||||||
|
numberType: .plateNumber,
|
||||||
forceUpdate: false,
|
forceUpdate: false,
|
||||||
trackLocation: false,
|
trackLocation: false,
|
||||||
additionalEvent: event,
|
additionalEvent: event,
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import Mockable
|
|||||||
@Mockable
|
@Mockable
|
||||||
public protocol VehicleServiceProtocol: Sendable {
|
public protocol VehicleServiceProtocol: Sendable {
|
||||||
|
|
||||||
func check(number: String, trackLocation: Bool) async throws -> VehicleWithErrors
|
func check(number: String, numberType: VehicleNumberType, trackLocation: Bool) async throws -> VehicleWithErrors
|
||||||
func updateHistory(number: String) async throws -> VehicleWithErrors
|
func updateHistory(number: String) async throws -> VehicleWithErrors
|
||||||
func updateSearch(number: String) async throws -> VehicleWithErrors
|
func updateSearch(number: String) async throws -> VehicleWithErrors
|
||||||
func checkRecord(number: String, event: VehicleEventDto?) async throws -> VehicleWithErrors
|
func checkRecord(number: String, event: VehicleEventDto?) async throws -> VehicleWithErrors
|
||||||
|
|||||||
@ -19,8 +19,8 @@ public enum Constants {
|
|||||||
public var baseUrl: String {
|
public var baseUrl: String {
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//"http://127.0.0.1:3000/"
|
"http://127.0.0.1:3000/"
|
||||||
"https://charon.aliencat.pro:8444/"
|
//"https://charon.aliencat.pro:8444/"
|
||||||
#else
|
#else
|
||||||
rawValue
|
rawValue
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user