Checking number from audio record

This commit is contained in:
Selim Mustafaev 2025-04-02 23:56:17 +03:00
parent ecf64d3280
commit 87074fa61a
10 changed files with 139 additions and 33 deletions

View File

@ -30,6 +30,7 @@
7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470B23FDE7E600B424AF /* LaunchScreen.storyboard */; };
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471523FDEB2A00B424AF /* MainSplitController.swift */; };
7A11471A23FE839000B424AF /* AuthController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471923FE839000B424AF /* AuthController.swift */; };
7A123C742D9DC40A00781F24 /* RecordScreenOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A123C732D9DC40A00781F24 /* RecordScreenOutput.swift */; };
7A131FD32D37B75500DC7755 /* HistoryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD22D37B75500DC7755 /* HistoryScreen.swift */; };
7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD42D37B76A00DC7755 /* HistoryViewModel.swift */; };
7A131FD72D37B77E00DC7755 /* HistoryCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD62D37B77E00DC7755 /* HistoryCoordinator.swift */; };
@ -318,6 +319,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>"; };
7A123C732D9DC40A00781F24 /* RecordScreenOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordScreenOutput.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>"; };
7A131FD62D37B77E00DC7755 /* HistoryCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryCoordinator.swift; sourceTree = "<group>"; };
@ -1046,6 +1048,7 @@
7A95197F2D80B6C100E69883 /* RecordsScreen.swift */,
7A9519812D80B6E500E69883 /* RecordsViewModel.swift */,
7A9519832D80B72B00E69883 /* RecordsCoordinator.swift */,
7A123C732D9DC40A00781F24 /* RecordScreenOutput.swift */,
);
path = RecordsScreen;
sourceTree = "<group>";
@ -1585,6 +1588,7 @@
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */,
7A9519802D80B6C100E69883 /* RecordsScreen.swift in Sources */,
7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */,
7A123C742D9DC40A00781F24 /* RecordScreenOutput.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -15,8 +15,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/Kolos65/Mockable",
"state" : {
"revision" : "a9e5e1d222035567069ed6fff8429c327229b5f6",
"version" : "0.0.11"
"revision" : "68f3ed6c4b62afab27a84425494cb61421a61ac1",
"version" : "0.3.1"
}
},
{
@ -33,8 +33,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/realm-core.git",
"state" : {
"revision" : "85eeca41654cc9070ad81a21a4b1d153ad467c33",
"version" : "14.13.1"
"revision" : "cccb3ca9e26ec452a29f2f0d4050d1e38b8a3d43",
"version" : "14.14.0"
}
},
{
@ -42,17 +42,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/realm-swift.git",
"state" : {
"revision" : "5553cfd1c789efdb3d6daf7f0cc0733cfe601846",
"version" : "10.54.1"
}
},
{
"identity" : "swift-issue-reporting",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-issue-reporting",
"state" : {
"revision" : "770f990d3e4eececb57ac04a6076e22f8c97daeb",
"version" : "1.4.2"
"revision" : "8cb364a6a63695df296f05b53f7c3f3b1dda6af3",
"version" : "10.54.3"
}
},
{
@ -60,8 +51,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/swiftlang/swift-syntax.git",
"state" : {
"revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82",
"version" : "510.0.3"
"revision" : "0687f71944021d616d34d922343dcef086855920",
"version" : "600.0.1"
}
},
{
@ -90,6 +81,15 @@
"revision" : "010073e62cea4daefea61042a51b8619d23cdc35",
"version" : "6.0.0"
}
},
{
"identity" : "xctest-dynamic-overlay",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state" : {
"revision" : "39de59b2d47f7ef3ca88a039dff3084688fe27f4",
"version" : "1.5.2"
}
}
],
"version" : 3

View File

@ -40,7 +40,7 @@ class MainTabController: UITabBarController, UITabBarControllerDelegate {
func addRecordsTab() {
let coordinator = RecordsCoordinator()
let controller = coordinator.start()
let controller = coordinator.start(output: self)
controller.tabBarItem = UITabBarItem(title: NSLocalizedString("Records", comment: ""),
image: UIImage(named: "record"), tag: 0)
viewControllers?[1] = controller
@ -108,3 +108,11 @@ class MainTabController: UITabBarController, UITabBarControllerDelegate {
Task { try? await RxLocationManager.requestCurrentLocation() }
}
}
extension MainTabController: RecordScreenOutput {
func checkRecord(number: String, event: VehicleEventDto?) {
selectedIndex = 0
Task { await historyViewModel?.checkRecord(number: number, event: event) }
}
}

View File

@ -9,6 +9,13 @@
import SwiftUI
import AutoCatCore
enum CheckType {
case normal
case update
case record(VehicleEventDto?)
}
@MainActor
@Observable
final class HistoryViewModel: ACHudContainer {
@ -112,11 +119,15 @@ final class HistoryViewModel: ACHudContainer {
}
}
func checkVehicle(number: String, isUpdate: Bool) async {
func checkVehicle(number: String, type: CheckType) async {
do {
hud = .progress
let (vehicle, errors) = isUpdate ? try await vehicleService.updateHistory(number: number)
: try await vehicleService.check(number: number)
let (vehicle, errors) = switch type {
case .normal: try await vehicleService.check(number: number)
case .update: try await vehicleService.updateHistory(number: number)
case .record(let event): try await vehicleService.checkRecord(number: number, event: event)
}
await loadVehicles()
if errors.isEmpty {
@ -133,7 +144,7 @@ final class HistoryViewModel: ACHudContainer {
}
func checkNewNumber(_ number: String) async {
await checkVehicle(number: number, isUpdate: false)
await checkVehicle(number: number, type: .normal)
}
func deleteVehicle(_ vehicle: VehicleDto) async {
@ -145,6 +156,10 @@ final class HistoryViewModel: ACHudContainer {
}
func updateVehicle(_ vehicle: VehicleDto) async {
await checkVehicle(number: vehicle.getNumber(), isUpdate: true)
await checkVehicle(number: vehicle.getNumber(), type: .update)
}
func checkRecord(number: String, event: VehicleEventDto?) async {
await checkVehicle(number: number, type: .record(event))
}
}

View File

@ -0,0 +1,15 @@
//
// RecordScreenOutput.swift
// AutoCat
//
// Created by Selim Mustafaev on 02.04.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import AutoCatCore
@MainActor
protocol RecordScreenOutput: AnyObject {
func checkRecord(number: String, event: VehicleEventDto?)
}

View File

@ -15,7 +15,7 @@ final class RecordsCoordinator {
var navController = UINavigationController()
func start() -> UIViewController {
func start(output: RecordScreenOutput?) -> UIViewController {
let resolver = ServiceContainer.shared
let viewModel = RecordsViewModel(
@ -25,6 +25,7 @@ final class RecordsCoordinator {
)
viewModel.coordinator = self
viewModel.output = output
let view = RecordsScreen(viewModel: viewModel)
let controller = UIHostingController(rootView: view)

View File

@ -100,5 +100,11 @@ struct RecordsScreen: View {
} label: {
Label("Show on map", systemImage: "map")
}
Button {
viewModel.check(id: record.id)
} label: {
Label("Check", systemImage: "eye")
}
}
}

View File

@ -17,6 +17,7 @@ final class RecordsViewModel: ACHudContainer {
let storageService: StorageServiceProtocol
let recordPlayer: RecordPlayerServiceProtocol
var coordinator: RecordsCoordinator?
weak var output: RecordScreenOutput?
var hud: ACHud?
var showRecordingAlert: Bool = false
@ -122,4 +123,14 @@ final class RecordsViewModel: ACHudContainer {
coordinator?.showOnMap(event: event)
}
func check(id: String) {
guard let record = records.first(where: { $0.id == id }),
let number = record.number
else {
return
}
output?.checkRecord(number: number, event: record.event)
}
}

View File

@ -31,17 +31,27 @@ public final class VehicleService {
extension VehicleService: VehicleServiceProtocol {
func check(number: String,
func check(
number: String,
forceUpdate: Bool,
trackLocation: Bool,
dbUpdatePolicy: DbUpdatePolicy) async throws -> VehicleWithErrors {
additionalEvents: [VehicleEventDto],
dbUpdatePolicy: DbUpdatePolicy
) async throws -> VehicleWithErrors {
var vehicle = (try? await storageService.loadVehicle(number: number)) ?? VehicleDto(number: number)
var errors: [Error] = []
let events = vehicle.events
// TODO: Check if additionalEvents already was added earlier (avoid duplication)
let events = vehicle.events + additionalEvents
let notes = vehicle.notes
if !additionalEvents.isEmpty {
vehicle.events = events
vehicle.updatedDate = Date().timeIntervalSince1970
vehicle.synchronized = false
}
async let locationTask = trackLocation ? locationService.getRecentLocation() : nil
async let vehicleTask = apiService.checkVehicle(by: number, notes: notes, events: events, force: forceUpdate)
@ -75,19 +85,54 @@ extension VehicleService: VehicleServiceProtocol {
public func check(number: String) async throws -> VehicleWithErrors {
#if targetEnvironment(macCatalyst)
try await check(number: number, forceUpdate: false, trackLocation: false, dbUpdatePolicy: .always)
try await check(
number: number,
forceUpdate: false,
trackLocation: false,
additionalEvents: [],
dbUpdatePolicy: .always
)
#else
try await check(number: number, forceUpdate: false, trackLocation: true, dbUpdatePolicy: .always)
try await check(
number: number,
forceUpdate: false,
trackLocation: true,
additionalEvents: [],
dbUpdatePolicy: .always
)
#endif
}
public func updateHistory(number: String) async throws -> VehicleWithErrors {
try await check(number: number, forceUpdate: true, trackLocation: false, dbUpdatePolicy: .always)
try await check(
number: number,
forceUpdate: true,
trackLocation: false,
additionalEvents: [],
dbUpdatePolicy: .always
)
}
public func updateSearch(number: String) async throws -> VehicleWithErrors {
try await check(number: number, forceUpdate: true, trackLocation: false, dbUpdatePolicy: .ifExists)
try await check(
number: number,
forceUpdate: true,
trackLocation: false,
additionalEvents: [],
dbUpdatePolicy: .ifExists
)
}
public func checkRecord(number: String, event: VehicleEventDto?) async throws -> VehicleWithErrors {
try await check(
number: number,
forceUpdate: false,
trackLocation: false,
additionalEvents: event.flatMap { [$0] } ?? [],
dbUpdatePolicy: .always
)
}
}

View File

@ -14,4 +14,5 @@ public protocol VehicleServiceProtocol: Sendable {
func check(number: String) 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
}