Showing debug info in new report screen

This commit is contained in:
Selim Mustafaev 2024-12-03 23:11:39 +03:00
parent c125f9ffab
commit aa008d5443
9 changed files with 125 additions and 11 deletions

View File

@ -268,7 +268,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
// }
Task {
let coordinator = ReportCoordinator(splitController: splitViewController, vehicle: vehicle)
let coordinator = ReportCoordinator(splitController: splitViewController, vehicle: vehicle, isPersistent: true)
try? await coordinator.start()
}
}

View File

@ -15,13 +15,15 @@ class ReportCoordinator: Coordinator {
let viewController: UISplitViewController?
let vehicle: VehicleDto
let isPersistent: Bool
var navController: UINavigationController?
init(splitController: UISplitViewController?, vehicle: VehicleDto) {
init(splitController: UISplitViewController?, vehicle: VehicleDto, isPersistent: Bool) {
self.viewController = splitController
self.vehicle = vehicle
self.isPersistent = isPersistent
}
func start() async throws {
@ -29,7 +31,7 @@ class ReportCoordinator: Coordinator {
if viewController?.viewControllers.count == 2 {
navController = viewController?.viewControllers.last as? UINavigationController
} else {
let viewModel = ReportViewModel(vehicle: vehicle)
let viewModel = ReportViewModel(vehicle: vehicle, isPersistent: isPersistent)
viewModel.coordinator = self
let controller = UIHostingController(rootView: ReportScreen(viewModel: viewModel))
navController = UINavigationController(rootViewController: controller)

View File

@ -65,13 +65,49 @@ struct ReportScreen: View {
LabeledContent("Notes", value: String(viewModel.vehicle.notes.count))
.navigationLink(onTap: viewModel.openNotes)
}
if viewModel.showDebugInfo {
Section("Debug info") {
makeDebugInfoCell(title: "Avtocod", model: viewModel.vehicle.debugInfo?.autocod)
makeDebugInfoCell(title: "Vin01 (VIN)", model: viewModel.vehicle.debugInfo?.vin01vin)
makeDebugInfoCell(title: "Vin01 (base)", model: viewModel.vehicle.debugInfo?.vin01base)
makeDebugInfoCell(title: "Vin01 (history)", model: viewModel.vehicle.debugInfo?.vin01history)
makeDebugInfoCell(title: "Nomerogram", model: viewModel.vehicle.debugInfo?.nomerogram)
}
}
}
.onAppear {
Task { await viewModel.loadVehicle() }
Task { await viewModel.onAppear() }
}
.hud($viewModel.hud)
}
@ViewBuilder
func makeDebugInfoCell(title: String, model: DebugInfoEntryDto?) -> some View {
let color: Color = switch model?.status {
case .success: .green
case .warning: .orange
case .error: .red
case .none: .gray
}
let cell = LabeledContent(title) {
Circle()
.fill(color)
.frame(width: 16, height: 16)
}
if let model, let error = model.error {
cell.navigationLink {
viewModel.showAlert(text: error, status: model.status)
}
} else {
cell
}
}
}
#Preview {
ReportScreen(viewModel: .init(vehicle: .preview))
ReportScreen(viewModel: .init(vehicle: .preview, isPersistent: false))
}

View File

@ -15,9 +15,11 @@ class ReportViewModel: ACHudContainer {
@ObservationIgnored @Service var api: ApiServiceProtocol
@ObservationIgnored @Service var storageService: StorageServiceProtocol
@ObservationIgnored @Service var settings: SettingsServiceProtocol
var coordinator: ReportCoordinator?
let isPersistent: Bool
var vehicle: VehicleDto
var hud: ACHud?
@ -41,8 +43,19 @@ class ReportViewModel: ACHudContainer {
: NSLocalizedString("No", comment: "")
}
init(vehicle: VehicleDto) {
var showDebugInfo: Bool {
settings.showDebugInfo
}
init(vehicle: VehicleDto, isPersistent: Bool) {
self.vehicle = vehicle
self.isPersistent = isPersistent
}
func onAppear() async {
if isPersistent {
await loadVehicle()
}
}
func loadVehicle() async {
@ -53,6 +66,14 @@ class ReportViewModel: ACHudContainer {
}
}
func showAlert(text: String, status: DebugInfoStatus) {
switch status {
case .success: showSuccess(text: text)
case .warning: showWarning(text: text)
case .error: showError(text: text)
}
}
func openEvents() {
coordinator?.openEvents(vehicle: vehicle)
}

View File

@ -10,6 +10,7 @@ enum ACHud: Equatable, Identifiable, Sendable {
case progress
case error(Error)
case message(String, ACMessageView.MessageType = .info)
var id: String {
switch self {
@ -17,6 +18,8 @@ enum ACHud: Equatable, Identifiable, Sendable {
"progress"
case .error(let error):
error.localizedDescription
case .message(let text, _):
text
}
}
@ -26,6 +29,8 @@ enum ACHud: Equatable, Identifiable, Sendable {
true
case (let .error(lerr), let .error(rerr)):
lerr.localizedDescription == rerr.localizedDescription
case (let .message(lmsg, ltype), let .message(rmsg, rtype)):
lmsg == rmsg && ltype == rtype
default:
false
}

View File

@ -31,4 +31,24 @@ extension ACHudContainer where Self: AnyObject {
hud = .error(error)
}
}
func showInfo(text: String) {
hud = .message(text, .info)
}
func showWarning(text: String) {
hud = .message(text, .warning)
}
func showSuccess(text: String) {
hud = .message(text, .success)
}
func showError(text: String) {
hud = .message(text, .error)
}
func showError(_ error: Error) {
hud = .error(error)
}
}

View File

@ -38,6 +38,11 @@ struct ACProgressHudModifier: ViewModifier {
type: .error) {
self.item = nil
}
case .message(let message, let type):
ACMessageView(message: message,
type: type) {
self.item = nil
}
}
}
}

View File

@ -165,6 +165,7 @@ extension Vehicle: DtoConvertible {
notes.append(objectsIn: dto.notes.map(VehicleNote.init))
self.notes = notes
self.debugInfo = DebugInfo(dto: dto.debugInfo)
self.synchronized = dto.synchronized
}
}

View File

@ -12,21 +12,24 @@ import AutoCatCore
@testable import AutoCat
@MainActor
struct ReportTests {
class ReportTests {
let existingVehicleNumber = "А123АА761"
let nonExistingVehicleNumber = "А999АА761"
let testColor = "testColor"
var storageServiceMock: MockStorageServiceProtocol
var settingsServiceMock: MockSettingsServiceProtocol
var viewModel: ReportViewModel
init() {
storageServiceMock = MockStorageServiceProtocol()
settingsServiceMock = MockSettingsServiceProtocol()
ServiceContainer.shared.register(StorageServiceProtocol.self, instance: storageServiceMock)
viewModel = ReportViewModel(vehicle: VehicleDto())
ServiceContainer.shared.register(SettingsServiceProtocol.self, instance: settingsServiceMock)
viewModel = ReportViewModel(vehicle: VehicleDto(), isPersistent: true)
}
@Test("Load vehicle detail")
@ -35,7 +38,7 @@ struct ReportTests {
let incompleteVehicleModel = VehicleDto(number: existingVehicleNumber)
let fullVehicleModel = VehicleDto(number: existingVehicleNumber, color: testColor)
viewModel.vehicle = incompleteVehicleModel
viewModel = ReportViewModel(vehicle: incompleteVehicleModel, isPersistent: true)
#expect(viewModel.vehicle.color == nil)
@ -43,7 +46,11 @@ struct ReportTests {
.loadVehicle(number: .value(existingVehicleNumber))
.willReturn(fullVehicleModel)
await viewModel.loadVehicle()
await viewModel.onAppear()
verify(storageServiceMock)
.loadVehicle(number: .value(existingVehicleNumber))
.called(.once)
#expect(viewModel.vehicle.color == testColor)
#expect(viewModel.hud == nil)
@ -52,12 +59,29 @@ struct ReportTests {
@Test("Load vehicle error")
func loadVehicleError() async throws {
viewModel = ReportViewModel(vehicle: VehicleDto(), isPersistent: true)
given(storageServiceMock)
.loadVehicle(number: .any)
.willThrow(StorageError.vehicleNotFound)
await viewModel.loadVehicle()
await viewModel.onAppear()
verify(storageServiceMock)
.loadVehicle(number: .any)
.called(.once)
#expect(viewModel.hud == .error(StorageError.vehicleNotFound))
}
@Test("Show debug info", arguments: [true, false])
func showDebugInfo(value: Bool) async throws {
viewModel = ReportViewModel(vehicle: VehicleDto(), isPersistent: false)
given(settingsServiceMock)
.showDebugInfo.willReturn(value)
#expect(viewModel.showDebugInfo == value)
}
}