AutoCat/AutoCat/Screens/RecordsScreen/RecordsScreen.swift

148 lines
4.7 KiB
Swift

//
// RecordsScreen.swift
// AutoCat
//
// Created by Selim Mustafaev on 11.03.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import SwiftUI
import AutoCatCore
struct RecordsScreen: View {
@State var viewModel: RecordsViewModel
@State var showEditAlert = false
@State var numberText = ""
@State var selectedRecordId: String = ""
init() {
let resolver = ServiceContainer.shared
self.viewModel = RecordsViewModel(
recordService: resolver.resolve(VehicleRecordServiceProtocol.self),
storageService: resolver.resolve(StorageServiceProtocol.self),
recordPlayer: resolver.resolve(RecordPlayerServiceProtocol.self)
)
}
init(viewModel: RecordsViewModel) {
self.viewModel = viewModel
}
var body: some View {
NavigationStack {
List {
ForEach(viewModel.recordSections) { section in
Section(header: Text(section.header)) {
ForEach(section.elements) { model in
AudioRecordView(
record: .init(
dto: model,
isPlaying: model.id == viewModel.playingRecord?.id
),
progress: viewModel.progress
) {
viewModel.onPlayTapped(record: model)
}
.listRowInsets(EdgeInsets())
.swipeActions(allowsFullSwipe: false) {
makeActions(for: model)
}
.contextMenu {
makeActions(for: model, useLabels: true)
}
}
}
}
}
.listStyle(.inset)
.hud($viewModel.hud)
.navigationTitle("Voice records")
.navigationBarTitleDisplayMode(.inline)
.onAppear {
Task { await viewModel.onAppear() }
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button {
Task { await viewModel.startRecording() }
} label: {
Image(systemName: "plus")
}
.alert("Recording...", isPresented: $viewModel.showRecordingAlert) {
Button("Cancel", role: .cancel) {
Task { await viewModel.cancelRecording() }
}
Button("Done") {
Task { await viewModel.stopRecording() }
}
}
}
}
.noteAlert(
title: String(localized: "Edit plate number"),
body: $numberText,
isPresented: $showEditAlert
) { text in
Task { await viewModel.editRecord(id: selectedRecordId, number: numberText) }
}
.navigationDestination(for: VehicleEventDto.self) { event in
MapScreen(mapInput: .event(event))
}
}
}
@ViewBuilder
func makeActions(for record: AudioRecordDto, useLabels: Bool = false) -> some View {
if useLabels {
makeMenuActions(for: record)
}
if let url = record.url {
ShareLink(item: url)
}
Button {
selectedRecordId = record.id
numberText = record.number ?? ""
showEditAlert = true
} label: {
Label(useLabels ? "Edit plate number" : "", systemImage: "pencil")
}
Button(role: .destructive) {
Task { await viewModel.deleteRecord(id: record.id) }
} label: {
Label(useLabels ? "Delete" : "", systemImage: "trash")
}
}
@ViewBuilder
func makeMenuActions(for record: AudioRecordDto) -> some View {
Button {
viewModel.showRawRecognizedText(record)
} label: {
Label("Show recognized text", systemImage: "textformat")
}
if let event = record.event {
NavigationLink(value: event) {
Label("Show on map", systemImage: "map")
}
}
if record.number != nil {
Button {
viewModel.check(record)
} label: {
Label("Check", systemImage: "eye")
}
}
}
}