Adding switchers for disabling location and for selecting VIN input
This commit is contained in:
parent
b7439b144a
commit
8a875ab7a1
@ -16,6 +16,7 @@
|
||||
7A1022772C557EC400B84627 /* LocationPickerScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1022762C557EC400B84627 /* LocationPickerScreen.swift */; };
|
||||
7A1022792C557ED600B84627 /* LocationPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1022782C557ED600B84627 /* LocationPickerViewModel.swift */; };
|
||||
7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470923FDE7E600B424AF /* Assets.xcassets */; };
|
||||
7A11BB002DE48FC500E3239F /* ProportionalHStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11BAFF2DE48FC500E3239F /* ProportionalHStack.swift */; };
|
||||
7A131FD32D37B75500DC7755 /* HistoryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD22D37B75500DC7755 /* HistoryScreen.swift */; };
|
||||
7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD42D37B76A00DC7755 /* HistoryViewModel.swift */; };
|
||||
7A1441662C297EDE00E79018 /* NotesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1441652C297EDE00E79018 /* NotesScreen.swift */; };
|
||||
@ -40,6 +41,7 @@
|
||||
7A4927D52CCE438600851C01 /* OptionalBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4927D42CCE438600851C01 /* OptionalBinding.swift */; };
|
||||
7A4955822D58CCF900912E66 /* HistoryFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4955812D58CCF900912E66 /* HistoryFilter.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 */; };
|
||||
7A5911EE2D63226F00EC51BA /* SearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911ED2D63226F00EC51BA /* SearchScreen.swift */; };
|
||||
7A5911F02D63266B00EC51BA /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911EF2D63266B00EC51BA /* SearchViewModel.swift */; };
|
||||
@ -97,6 +99,7 @@
|
||||
7A7AA2CB2DA2C85100276D83 /* RealmSwift in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 7A7AA2C92DA2C85100276D83 /* RealmSwift */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */; };
|
||||
7A809F392D66755B00CF1B3C /* Error+Canceled.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A809F382D66755B00CF1B3C /* Error+Canceled.swift */; };
|
||||
7A8652462DE4484700AEBF27 /* ACVinKeyboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8652452DE4484700AEBF27 /* ACVinKeyboardView.swift */; };
|
||||
7A8AB76525A0DB8F00ECF2C1 /* BundleVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */; };
|
||||
7A912F372D381B7400002938 /* LicensePlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A912F362D381B7400002938 /* LicensePlateView.swift */; };
|
||||
7A91CE952DC2422B00DBA953 /* HideTabBarModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A91CE942DC2422B00DBA953 /* HideTabBarModifier.swift */; };
|
||||
@ -260,6 +263,7 @@
|
||||
7A11474623FF2AA500B424AF /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
|
||||
7A11474823FF2B2D00B424AF /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = "<group>"; };
|
||||
7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; };
|
||||
7A11BAFF2DE48FC500E3239F /* ProportionalHStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProportionalHStack.swift; sourceTree = "<group>"; };
|
||||
7A131FD22D37B75500DC7755 /* HistoryScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryScreen.swift; sourceTree = "<group>"; };
|
||||
7A131FD42D37B76A00DC7755 /* HistoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryViewModel.swift; sourceTree = "<group>"; };
|
||||
7A1441652C297EDE00E79018 /* NotesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesScreen.swift; sourceTree = "<group>"; };
|
||||
@ -289,6 +293,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -344,6 +349,7 @@
|
||||
7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordView.swift; sourceTree = "<group>"; };
|
||||
7A809F382D66755B00CF1B3C /* Error+Canceled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+Canceled.swift"; sourceTree = "<group>"; };
|
||||
7A813DBD2506A57100CC93B9 /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/AuthenticationServices.framework; sourceTree = DEVELOPER_DIR; };
|
||||
7A8652452DE4484700AEBF27 /* ACVinKeyboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACVinKeyboardView.swift; sourceTree = "<group>"; };
|
||||
7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleVersion.swift; sourceTree = "<group>"; };
|
||||
7A8AB76725A0DC8200ECF2C1 /* DebugInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugInfo.swift; sourceTree = "<group>"; };
|
||||
7A912F362D381B7400002938 /* LicensePlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensePlateView.swift; sourceTree = "<group>"; };
|
||||
@ -992,8 +998,10 @@
|
||||
children = (
|
||||
7AD176AF2DC127540023049D /* PNButtonType.swift */,
|
||||
7AB490282D6B1217002F39C6 /* ACKeyboardView.swift */,
|
||||
7A8652452DE4484700AEBF27 /* ACVinKeyboardView.swift */,
|
||||
7AB4902A2D6B1446002F39C6 /* ACKeyboardButton.swift */,
|
||||
7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */,
|
||||
7A5631CD2DE4B638001070D6 /* VehicleCheckType.swift */,
|
||||
);
|
||||
path = NumberEditView;
|
||||
sourceTree = "<group>";
|
||||
@ -1076,6 +1084,7 @@
|
||||
7AB4E42B2D397D8E0006D052 /* VehicleCellView.swift */,
|
||||
7AC8B2752D6A01C700190706 /* UISearchTextField+Dumb.swift */,
|
||||
7AF231982DA27C1B00AE5EB3 /* ACButtonView.swift */,
|
||||
7A11BAFF2DE48FC500E3239F /* ProportionalHStack.swift */,
|
||||
7A6974C62DCA5024008AA6A1 /* ListItemStyle.swift */,
|
||||
);
|
||||
path = SwiftUI;
|
||||
@ -1328,12 +1337,15 @@
|
||||
7A06E0AE2C7065C7005731AC /* SettingsViewModel.swift in Sources */,
|
||||
7AB4E42C2D397D8E0006D052 /* VehicleCellView.swift in Sources */,
|
||||
7A91CE9A2DC2470F00DBA953 /* TextFieldDumbModifier.swift in Sources */,
|
||||
7A5631CE2DE4B638001070D6 /* VehicleCheckType.swift in Sources */,
|
||||
7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */,
|
||||
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */,
|
||||
7AC44B822DB390B900ADC026 /* MainTabScreen.swift in Sources */,
|
||||
7A7158122C444A6400852088 /* AdsViewModel.swift in Sources */,
|
||||
7AD176B02DC127540023049D /* PNButtonType.swift in Sources */,
|
||||
7AF231952DA1C29300AE5EB3 /* AuthViewModel.swift in Sources */,
|
||||
7A8652462DE4484700AEBF27 /* ACVinKeyboardView.swift in Sources */,
|
||||
7A11BB002DE48FC500E3239F /* ProportionalHStack.swift in Sources */,
|
||||
7AB4E4662D58A16C0006D052 /* GenericError.swift in Sources */,
|
||||
7AFBE8CA2C3081C7003C491D /* ACProgressHud+Modifiers.swift in Sources */,
|
||||
7A6974C72DCA5024008AA6A1 /* ListItemStyle.swift in Sources */,
|
||||
|
||||
@ -131,11 +131,11 @@ final class HistoryViewModel: ACHudContainer {
|
||||
}
|
||||
}
|
||||
|
||||
func checkVehicle(number: String, type: CheckType) async {
|
||||
func checkVehicle(number: String, type: CheckType, trackLocation: Bool = true) async {
|
||||
do {
|
||||
hud = .progress
|
||||
let (vehicle, errors) = switch type {
|
||||
case .normal: try await vehicleService.check(number: number)
|
||||
case .normal: try await vehicleService.check(number: number, trackLocation: trackLocation)
|
||||
case .update: try await vehicleService.updateHistory(number: number)
|
||||
case .record(let event): try await vehicleService.checkRecord(number: number, event: event)
|
||||
}
|
||||
@ -163,8 +163,13 @@ final class HistoryViewModel: ACHudContainer {
|
||||
}
|
||||
}
|
||||
|
||||
func checkNewNumber(_ number: String) async {
|
||||
await checkVehicle(number: number, type: .normal)
|
||||
func checkNewNumber(_ number: String, checkType: VehicleCheckType, enableLocation: Bool) async {
|
||||
|
||||
await checkVehicle(
|
||||
number: number,
|
||||
type: .normal,
|
||||
trackLocation: enableLocation
|
||||
)
|
||||
}
|
||||
|
||||
func deleteVehicle(_ vehicle: VehicleDto) async {
|
||||
|
||||
@ -70,10 +70,17 @@ struct MainSplitScreen: View {
|
||||
}
|
||||
|
||||
var numberEditSheet: some View {
|
||||
NumberEditView { number in
|
||||
NumberEditView { number, checkType, enableLocation in
|
||||
|
||||
checkNumberSheetOpened = false
|
||||
selection = .history
|
||||
Task { await historyViewModel.checkNewNumber(number) }
|
||||
Task {
|
||||
await historyViewModel.checkNewNumber(
|
||||
number,
|
||||
checkType: checkType,
|
||||
enableLocation: enableLocation
|
||||
)
|
||||
}
|
||||
}
|
||||
.presentationDetents([.height(350)])
|
||||
}
|
||||
|
||||
@ -102,10 +102,17 @@ struct MainTabScreen: View {
|
||||
}
|
||||
|
||||
var numberEditSheet: some View {
|
||||
NumberEditView { number in
|
||||
NumberEditView { number, checkType, enableLocation in
|
||||
|
||||
checkNumberSheetOpened = false
|
||||
selection = .history
|
||||
Task { await historyViewModel.checkNewNumber(number) }
|
||||
Task {
|
||||
await historyViewModel.checkNewNumber(
|
||||
number,
|
||||
checkType: checkType,
|
||||
enableLocation: enableLocation
|
||||
)
|
||||
}
|
||||
}
|
||||
.presentationDetents([.height(350)])
|
||||
}
|
||||
|
||||
@ -41,6 +41,9 @@ struct ACKeyboardButton: View {
|
||||
Text(String(Constants.pnLettersMap[s] ?? s))
|
||||
.font(.custom("RoadNumbers", size: 36 - 2*sizeDelta))
|
||||
.offset(y: sizeDelta/2)
|
||||
case .vin(let s):
|
||||
Text(String(Constants.pnLettersMap[s] ?? s))
|
||||
.font(.system(size: 26, weight: .semibold))
|
||||
case .backspace:
|
||||
Image(systemName: "delete.left")
|
||||
case .done:
|
||||
@ -50,7 +53,7 @@ struct ACKeyboardButton: View {
|
||||
|
||||
var backgroundColor: Color {
|
||||
switch type {
|
||||
case .symbol: Color("KeyBackground")
|
||||
case .symbol, .vin: Color("KeyBackground")
|
||||
case .backspace: Color("DarkKeyBackground")
|
||||
case .done: .blue
|
||||
}
|
||||
@ -70,6 +73,7 @@ struct ACKeyboardButton: View {
|
||||
|
||||
HStack(spacing: 0) {
|
||||
ACKeyboardButton(type: .symbol("A")) { _ in }
|
||||
ACKeyboardButton(type: .vin("A")) { _ in }
|
||||
ACKeyboardButton(type: .symbol("1")) { _ in }
|
||||
ACKeyboardButton(type: .backspace) { _ in }
|
||||
ACKeyboardButton(type: .done) { _ in }
|
||||
|
||||
80
AutoCat/SwiftUI/NumberEditView/ACVinKeyboardView.swift
Normal file
80
AutoCat/SwiftUI/NumberEditView/ACVinKeyboardView.swift
Normal file
@ -0,0 +1,80 @@
|
||||
//
|
||||
// ACVinKeyboardView.swift
|
||||
// AutoCat
|
||||
//
|
||||
// Created by Selim Mustafaev on 26.05.2025.
|
||||
// Copyright © 2025 Selim Mustafaev. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ACVinKeyboardView: View {
|
||||
|
||||
let buttonPressed: (PNButtonType) -> Void
|
||||
|
||||
var body: some View {
|
||||
ProportionalHStack(widthWeights: [2/3, 1/3], spacing: 16) {
|
||||
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .vin("A"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("B"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("C"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("D"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("E"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("F"), onTap: buttonPressed)
|
||||
}
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .vin("G"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("H"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("J"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("K"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("L"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("M"), onTap: buttonPressed)
|
||||
}
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .vin("N"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("P"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("R"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("S"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("T"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("U"), onTap: buttonPressed)
|
||||
}
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .vin("V"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("W"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("X"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("Y"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .vin("Z"), onTap: buttonPressed)
|
||||
}
|
||||
}
|
||||
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .symbol("1"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .symbol("2"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .symbol("3"), onTap: buttonPressed)
|
||||
}
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .symbol("4"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .symbol("5"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .symbol("6"), onTap: buttonPressed)
|
||||
}
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .symbol("7"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .symbol("8"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .symbol("9"), onTap: buttonPressed)
|
||||
}
|
||||
GridRow {
|
||||
ACKeyboardButton(type: .symbol("0"), onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .backspace, onTap: buttonPressed)
|
||||
ACKeyboardButton(type: .done, onTap: buttonPressed)
|
||||
}
|
||||
}
|
||||
}
|
||||
.font(.system(size: 24))
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ACVinKeyboardView { _ in }
|
||||
.frame(height: 240)
|
||||
}
|
||||
@ -11,9 +11,11 @@ import AutoCatCore
|
||||
|
||||
struct NumberEditView: View {
|
||||
|
||||
let onCheck: (String) -> Void
|
||||
let onCheck: (String, VehicleCheckType, Bool) -> Void
|
||||
|
||||
@State var number = PlateNumber("")
|
||||
@State var enableLocation: Bool = true
|
||||
@State var checkType: VehicleCheckType = .plateNumber
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 16) {
|
||||
@ -27,7 +29,7 @@ struct NumberEditView: View {
|
||||
.fixedSize(horizontal: true, vertical: false)
|
||||
|
||||
Button {
|
||||
onCheck(number.asString())
|
||||
onCheck(number.asString(), checkType, enableLocation)
|
||||
} label: {
|
||||
Text("Check")
|
||||
.frame(maxWidth: .infinity)
|
||||
@ -43,11 +45,36 @@ struct NumberEditView: View {
|
||||
.frame(height: 50)
|
||||
.opacity(number.isValid ? 1 : 0.5)
|
||||
}
|
||||
.padding(.leading, 4)
|
||||
.padding(.trailing, 4)
|
||||
.padding(.horizontal, 4)
|
||||
|
||||
HStack(spacing: 16) {
|
||||
Picker("Location", selection: $enableLocation) {
|
||||
Image(systemName: "location")
|
||||
.tag(true)
|
||||
Image(systemName: "location.slash")
|
||||
.tag(false)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.frame(width: 120)
|
||||
|
||||
Picker("Check type", selection: $checkType) {
|
||||
ForEach(VehicleCheckType.allCases) { type in
|
||||
Text(type.title)
|
||||
.selectionDisabled(!type.enabled)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
.padding(.horizontal, 4)
|
||||
|
||||
switch checkType {
|
||||
case .plateNumber:
|
||||
ACKeyboardView(buttonPressed: buttonPressed)
|
||||
.frame(height: 220)
|
||||
case .vin:
|
||||
ACVinKeyboardView(buttonPressed: buttonPressed)
|
||||
.frame(height: 220)
|
||||
}
|
||||
}
|
||||
.padding(16)
|
||||
.gesture(DragGesture(), including: .gesture)
|
||||
@ -55,16 +82,16 @@ struct NumberEditView: View {
|
||||
|
||||
func buttonPressed(type: PNButtonType) {
|
||||
switch type {
|
||||
case .symbol(let s):
|
||||
case .symbol(let s), .vin(let s):
|
||||
number.insertText(String(s))
|
||||
case .backspace:
|
||||
number.deleteBackward()
|
||||
case .done:
|
||||
onCheck(number.asString())
|
||||
onCheck(number.asString(), checkType, enableLocation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NumberEditView() { _ in }
|
||||
NumberEditView() { _ , _, _ in }
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
enum PNButtonType {
|
||||
|
||||
case symbol(Character)
|
||||
case vin(Character)
|
||||
case backspace
|
||||
case done
|
||||
}
|
||||
|
||||
33
AutoCat/SwiftUI/NumberEditView/VehicleCheckType.swift
Normal file
33
AutoCat/SwiftUI/NumberEditView/VehicleCheckType.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// VehicleCheckType.swift
|
||||
// AutoCat
|
||||
//
|
||||
// Created by Selim Mustafaev on 26.05.2025.
|
||||
// Copyright © 2025 Selim Mustafaev. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum VehicleCheckType: Hashable, CaseIterable, Identifiable {
|
||||
|
||||
case plateNumber
|
||||
case vin
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .plateNumber:
|
||||
return String(localized: "Plate number")
|
||||
case .vin:
|
||||
return String(localized: "VIN")
|
||||
}
|
||||
}
|
||||
|
||||
var enabled: Bool {
|
||||
switch self {
|
||||
case .plateNumber: true
|
||||
case .vin: true
|
||||
}
|
||||
}
|
||||
|
||||
var id: Self { self }
|
||||
}
|
||||
55
AutoCat/SwiftUI/ProportionalHStack.swift
Normal file
55
AutoCat/SwiftUI/ProportionalHStack.swift
Normal file
@ -0,0 +1,55 @@
|
||||
//
|
||||
// ProportionalHStack.swift
|
||||
// NavTest
|
||||
//
|
||||
// Created by Selim Mustafaev on 26.05.2025.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ProportionalHStack: Layout {
|
||||
|
||||
let widthWeights: [CGFloat]
|
||||
let spacing: CGFloat
|
||||
|
||||
init(widthWeights: [CGFloat], spacing: CGFloat? = nil) {
|
||||
self.widthWeights = widthWeights
|
||||
self.spacing = spacing ?? .zero
|
||||
}
|
||||
|
||||
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
|
||||
let maxHeight = subviews
|
||||
.map { proxy in
|
||||
return proxy.sizeThatFits(.unspecified).height
|
||||
}
|
||||
.max() ?? .zero
|
||||
|
||||
return CGSize(width: proposal.width ?? .zero, height: maxHeight)
|
||||
}
|
||||
|
||||
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
|
||||
let subviewSizes = subviews.map { proxy in
|
||||
return proxy.sizeThatFits(.infinity)
|
||||
}
|
||||
|
||||
var x = bounds.minX
|
||||
let y = bounds.minY
|
||||
let parentTotalWith = (proposal.width ?? .zero) - (CGFloat((widthWeights.count - 1)) * spacing)
|
||||
|
||||
for index in subviews.indices {
|
||||
let widthWeight = widthWeights[index]
|
||||
let proposedWidth = widthWeight * parentTotalWith
|
||||
|
||||
let sizeProposal = ProposedViewSize(width: proposedWidth, height: subviewSizes[index].height)
|
||||
|
||||
subviews[index]
|
||||
.place(
|
||||
at: CGPoint(x: x, y: y),
|
||||
anchor: .topLeading,
|
||||
proposal: sizeProposal
|
||||
)
|
||||
|
||||
x += (proposedWidth + spacing)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@ extension VehicleService: VehicleServiceProtocol {
|
||||
return VehicleWithErrors(vehicle: vehicle, errors: errors)
|
||||
}
|
||||
|
||||
public func check(number: String) async throws -> VehicleWithErrors {
|
||||
public func check(number: String, trackLocation: Bool) async throws -> VehicleWithErrors {
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
try await check(
|
||||
@ -101,7 +101,7 @@ extension VehicleService: VehicleServiceProtocol {
|
||||
try await check(
|
||||
number: number,
|
||||
forceUpdate: false,
|
||||
trackLocation: true,
|
||||
trackLocation: trackLocation,
|
||||
additionalEvent: nil,
|
||||
dbUpdatePolicy: .always
|
||||
)
|
||||
|
||||
@ -11,7 +11,7 @@ import Mockable
|
||||
@Mockable
|
||||
public protocol VehicleServiceProtocol: Sendable {
|
||||
|
||||
func check(number: String) async throws -> VehicleWithErrors
|
||||
func check(number: String, trackLocation: Bool) async throws -> VehicleWithErrors
|
||||
func updateHistory(number: String) async throws -> VehicleWithErrors
|
||||
func updateSearch(number: String) async throws -> VehicleWithErrors
|
||||
func checkRecord(number: String, event: VehicleEventDto?) async throws -> VehicleWithErrors
|
||||
|
||||
@ -53,7 +53,7 @@ struct VehicleServiceTests {
|
||||
.willThrow(TestError.generic)
|
||||
|
||||
await #expect(throws: TestError.generic) {
|
||||
_ = try await vehicleService.check(number: existingVehicleNumber)
|
||||
_ = try await vehicleService.check(number: existingVehicleNumber, trackLocation: true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ struct VehicleServiceTests {
|
||||
.updateVehicle(dto: .any, policy: .any)
|
||||
.willReturn(true)
|
||||
|
||||
let result = try await vehicleService.check(number: existingVehicleNumber)
|
||||
let result = try await vehicleService.check(number: existingVehicleNumber, trackLocation: true)
|
||||
|
||||
#expect(result.vehicle.unrecognized)
|
||||
#expect(result.vehicle.events.isEmpty)
|
||||
@ -113,7 +113,7 @@ struct VehicleServiceTests {
|
||||
.updateVehicle(dto: .any, policy: .any)
|
||||
.willReturn(true)
|
||||
|
||||
let result = try await vehicleService.check(number: existingVehicleNumber)
|
||||
let result = try await vehicleService.check(number: existingVehicleNumber, trackLocation: true)
|
||||
|
||||
#expect(result.vehicle.vin1 == testVin)
|
||||
#expect(result.errors.count == 2)
|
||||
@ -145,7 +145,7 @@ struct VehicleServiceTests {
|
||||
.updateVehicle(dto: .any, policy: .any)
|
||||
.willReturn(true)
|
||||
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber, trackLocation: true)
|
||||
|
||||
#expect(result.vehicle.vin1 == testVin)
|
||||
#expect(result.errors.count == 1)
|
||||
@ -181,7 +181,7 @@ struct VehicleServiceTests {
|
||||
.add(event: .any, to: .any)
|
||||
.willThrow(TestError.generic)
|
||||
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber, trackLocation: true)
|
||||
|
||||
#expect(result.vehicle.number == VehicleDto.validNumber)
|
||||
#expect(result.errors.count == 2)
|
||||
@ -217,7 +217,7 @@ struct VehicleServiceTests {
|
||||
.add(event: .any, to: .any)
|
||||
.willReturn(.normal.addEvent(.valid))
|
||||
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber, trackLocation: true)
|
||||
|
||||
#expect(result.vehicle.number == VehicleDto.validNumber)
|
||||
#expect(result.errors.count == 1)
|
||||
@ -253,7 +253,7 @@ struct VehicleServiceTests {
|
||||
.add(event: .any, to: .any)
|
||||
.willReturn(.normal.addEvent(.valid))
|
||||
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||||
let result = try await vehicleService.check(number: VehicleDto.validNumber, trackLocation: true)
|
||||
|
||||
#expect(result.vehicle.number == VehicleDto.validNumber)
|
||||
#expect(result.errors.count == 0)
|
||||
@ -291,7 +291,7 @@ struct VehicleServiceTests {
|
||||
.add(event: .any, to: .any)
|
||||
.willReturn(vehicle.addEvent(.valid))
|
||||
|
||||
let result = try await vehicleService.check(number: vehicle.number)
|
||||
let result = try await vehicleService.check(number: vehicle.number, trackLocation: true)
|
||||
|
||||
verify(apiServiceMock)
|
||||
.checkVehicle(by: .any, notes: .any, events: .any, force: .value(false))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user