diff --git a/AutoCat.xcodeproj/project.pbxproj b/AutoCat.xcodeproj/project.pbxproj index 85c9232..93d5ab0 100644 --- a/AutoCat.xcodeproj/project.pbxproj +++ b/AutoCat.xcodeproj/project.pbxproj @@ -37,7 +37,6 @@ 7A1441682C297EFD00E79018 /* NotesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1441672C297EFD00E79018 /* NotesViewModel.swift */; }; 7A14416C2C297F2100E79018 /* NotesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416B2C297F2100E79018 /* NotesCoordinator.swift */; }; 7A14416E2C297F7C00E79018 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416D2C297F7C00E79018 /* Coordinator.swift */; }; - 7A1441702C2998B200E79018 /* Formatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416F2C2998B200E79018 /* Formatters.swift */; }; 7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE492A2E820300626A6E /* UIStackView.swift */; }; 7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */; }; 7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80429A41C66007962DA /* RealmSwift */; }; @@ -105,6 +104,7 @@ 7A64AE762469DFB600ABE48E /* ContentTransformers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE722469DFB600ABE48E /* ContentTransformers.swift */; }; 7A6B65B32CFB0DB500AABA6B /* NullifyDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6B65B22CFB0DB500AABA6B /* NullifyDate.swift */; }; 7A6C4D9E2C56BCA600982597 /* SwiftLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 7A6C4D9D2C56BCA600982597 /* SwiftLocation */; }; + 7A6C65222D999325001240C2 /* AudioRecordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6C65212D999325001240C2 /* AudioRecordViewModel.swift */; }; 7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD902242BF4A5009DE740 /* PlateView.swift */; }; 7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD90724329144009DE740 /* CenterTextLayer.swift */; }; 7A6DD90A24329541009DE740 /* RoadNumbers2.0.otf in Resources */ = {isa = PBXBuildFile; fileRef = 7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */; }; @@ -126,6 +126,7 @@ 7A761C08267E8EA20005F28F /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A43F9F7246C8A6200BA5B49 /* JWT.swift */; }; 7A761C09267E8EE40005F28F /* Base64FS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE32246C095700297C33 /* Base64FS.swift */; }; 7A761C0B267E8FF90005F28F /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A761C0A267E8FF90005F28F /* Error.swift */; }; + 7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */; }; 7A809F392D66755B00CF1B3C /* Error+Canceled.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A809F382D66755B00CF1B3C /* Error+Canceled.swift */; }; 7A813DC32508EE4F00CC93B9 /* EventCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A813DC22508EE4F00CC93B9 /* EventCell.swift */; }; 7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */; }; @@ -321,7 +322,6 @@ 7A1441672C297EFD00E79018 /* NotesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesViewModel.swift; sourceTree = ""; }; 7A14416B2C297F2100E79018 /* NotesCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesCoordinator.swift; sourceTree = ""; }; 7A14416D2C297F7C00E79018 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; - 7A14416F2C2998B200E79018 /* Formatters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Formatters.swift; sourceTree = ""; }; 7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = ""; }; 7A17CE492A2E820300626A6E /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = ""; }; 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UISegmentedControl.swift; sourceTree = ""; }; @@ -401,6 +401,7 @@ 7A64AE722469DFB600ABE48E /* ContentTransformers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentTransformers.swift; sourceTree = ""; }; 7A659B5824A2B1BA0043A0F2 /* AudioRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecord.swift; sourceTree = ""; }; 7A6B65B22CFB0DB500AABA6B /* NullifyDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NullifyDate.swift; sourceTree = ""; }; + 7A6C65212D999325001240C2 /* AudioRecordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordViewModel.swift; sourceTree = ""; }; 7A6DD902242BF4A5009DE740 /* PlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateView.swift; sourceTree = ""; }; 7A6DD90724329144009DE740 /* CenterTextLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterTextLayer.swift; sourceTree = ""; }; 7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = RoadNumbers2.0.otf; sourceTree = ""; }; @@ -418,6 +419,7 @@ 7A7158112C444A6400852088 /* AdsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsViewModel.swift; sourceTree = ""; }; 7A71EF562D0A26B200943129 /* EventModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventModel.swift; sourceTree = ""; }; 7A761C0A267E8FF90005F28F /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; }; + 7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordView.swift; sourceTree = ""; }; 7A809F382D66755B00CF1B3C /* Error+Canceled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+Canceled.swift"; sourceTree = ""; }; 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; }; 7A813DC22508EE4F00CC93B9 /* EventCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventCell.swift; sourceTree = ""; }; @@ -696,7 +698,6 @@ 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */, 7A3E30F22C18840600567704 /* ActivityItemSource.swift */, 7A14416D2C297F7C00E79018 /* Coordinator.swift */, - 7A14416F2C2998B200E79018 /* Formatters.swift */, 7AB4E4652D58A16C0006D052 /* GenericError.swift */, ); path = Utils; @@ -934,6 +935,15 @@ path = ATGMediaBrowser; sourceTree = ""; }; + 7A6C65202D99930C001240C2 /* AudioRecordView */ = { + isa = PBXGroup; + children = ( + 7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */, + 7A6C65212D999325001240C2 /* AudioRecordViewModel.swift */, + ); + path = AudioRecordView; + sourceTree = ""; + }; 7A6DD901242BF48D009DE740 /* Views */ = { isa = PBXGroup; children = ( @@ -1025,6 +1035,7 @@ 7A95197E2D80B69800E69883 /* RecordsScreen */ = { isa = PBXGroup; children = ( + 7A6C65202D99930C001240C2 /* AudioRecordView */, 7A95197F2D80B6C100E69883 /* RecordsScreen.swift */, 7A9519812D80B6E500E69883 /* RecordsViewModel.swift */, 7A9519832D80B72B00E69883 /* RecordsCoordinator.swift */, @@ -1469,6 +1480,7 @@ 7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */, 7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */, 7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */, + 7A6C65222D999325001240C2 /* AudioRecordViewModel.swift in Sources */, 7A06E0AE2C7065C7005731AC /* SettingsViewModel.swift in Sources */, 7AB4E42C2D397D8E0006D052 /* VehicleCellView.swift in Sources */, 7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */, @@ -1500,6 +1512,7 @@ 7A11471A23FE839000B424AF /* AuthController.swift in Sources */, 7A64AE742469DFB600ABE48E /* MediaContentView.swift in Sources */, 7A5911F22D63268400EC51BA /* SearchCoordinator.swift in Sources */, + 7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */, 7A1090EC24A4E3E100B4F0B2 /* CellProgressView.swift in Sources */, 7AB9FE2A2D08CF35005DE374 /* EventsScreenMode.swift in Sources */, 7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */, @@ -1534,7 +1547,6 @@ 7A131FD72D37B77E00DC7755 /* HistoryCoordinator.swift in Sources */, 7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */, 7A4955822D58CCF900912E66 /* HistoryFilter.swift in Sources */, - 7A1441702C2998B200E79018 /* Formatters.swift in Sources */, 7A4322912CB2CC8A00085CF6 /* FiltersScreen.swift in Sources */, 7ABD1B472D044A3200B43213 /* GalleryScreen.swift in Sources */, 7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */, diff --git a/AutoCat/Screens/RecordsScreen/AudioRecordView/AudioRecordView.swift b/AutoCat/Screens/RecordsScreen/AudioRecordView/AudioRecordView.swift new file mode 100644 index 0000000..e940017 --- /dev/null +++ b/AutoCat/Screens/RecordsScreen/AudioRecordView/AudioRecordView.swift @@ -0,0 +1,66 @@ +// +// AudioRecordView.swift +// AutoCat +// +// Created by Selim Mustafaev on 30.03.2025. +// Copyright © 2025 Selim Mustafaev. All rights reserved. +// + +import SwiftUI +import AutoCatCore + +struct AudioRecordView: View { + + let record: AudioRecordViewModel + + var body: some View { + + return HStack { + playButton + duration + Spacer(minLength: 0) + number + Spacer(minLength: 0) + Text(record.date) + .font(.subheadline) + } + .padding(.trailing) + } + + var playButton: some View { + Button { + record.onPlay() + } label: { + Image(systemName: record.isPlaying ? "pause.fill" : "play.fill") + .padding() + } + } + + @ViewBuilder + var duration: some View { + if let duration = record.duration { + Text(duration) + .font(.subheadline) + } + } + + @ViewBuilder + var number: some View { + if let number = record.number { + Text(number) + .font(.headline) + } + } +} + +#Preview { + AudioRecordView( + record: AudioRecordViewModel(dto: .init( + path: "qwe.m4a", + number: "А123АА761", + raw: "бла-бла", + duration: 145, + event: nil + ), onPlay: {}) + ) +} diff --git a/AutoCat/Screens/RecordsScreen/AudioRecordView/AudioRecordViewModel.swift b/AutoCat/Screens/RecordsScreen/AudioRecordView/AudioRecordViewModel.swift new file mode 100644 index 0000000..624fd2c --- /dev/null +++ b/AutoCat/Screens/RecordsScreen/AudioRecordView/AudioRecordViewModel.swift @@ -0,0 +1,32 @@ +// +// AudioRecordViewModel.swift +// AutoCat +// +// Created by Selim Mustafaev on 30.03.2025. +// Copyright © 2025 Selim Mustafaev. All rights reserved. +// + +import AutoCatCore +import Foundation + +struct AudioRecordViewModel: Identifiable { + + var id: TimeInterval + var isPlaying: Bool + var duration: String? + var number: String? + var date: String + var onPlay: () -> Void + + init(dto: AudioRecordDto, onPlay: @escaping () -> Void) { + + self.id = dto.id + self.duration = Formatters.time.string(from: dto.duration) + self.number = dto.number + self.date = Formatters.short.string( + from: Date(timeIntervalSince1970: dto.addedDate) + ) + self.isPlaying = false + self.onPlay = onPlay + } +} diff --git a/AutoCat/Screens/RecordsScreen/RecordsScreen.swift b/AutoCat/Screens/RecordsScreen/RecordsScreen.swift index 601eb4e..bf515cd 100644 --- a/AutoCat/Screens/RecordsScreen/RecordsScreen.swift +++ b/AutoCat/Screens/RecordsScreen/RecordsScreen.swift @@ -14,10 +14,12 @@ struct RecordsScreen: View { var body: some View { List { - ForEach(viewModel.records) { record in - Text(record.path) + ForEach(viewModel.recordModels) { record in + AudioRecordView(record: record) + .listRowInsets(EdgeInsets()) } } + .buttonStyle(BorderlessButtonStyle()) .listStyle(.plain) .hud($viewModel.hud) .navigationTitle("Voice records") diff --git a/AutoCat/Screens/RecordsScreen/RecordsViewModel.swift b/AutoCat/Screens/RecordsScreen/RecordsViewModel.swift index 97be2e4..d5bfb68 100644 --- a/AutoCat/Screens/RecordsScreen/RecordsViewModel.swift +++ b/AutoCat/Screens/RecordsScreen/RecordsViewModel.swift @@ -20,6 +20,14 @@ final class RecordsViewModel: ACHudContainer { var showRecordingAlert: Bool = false var records: [AudioRecordDto] = [] + var recordModels: [AudioRecordViewModel] { + records.map { record in + AudioRecordViewModel(dto: record) { [weak self] in + self?.onPlayTapped(record: record) + } + } + } + init(recordService: VehicleRecordServiceProtocol, storageService: StorageServiceProtocol) { @@ -55,4 +63,7 @@ final class RecordsViewModel: ACHudContainer { func cancelRecording() async { await recordService.cancelRecording() } + + func onPlayTapped(record: AudioRecordDto) { + } } diff --git a/AutoCat/Utils/Formatters.swift b/AutoCat/Utils/Formatters.swift deleted file mode 100644 index b3d03bc..0000000 --- a/AutoCat/Utils/Formatters.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// Formatters.swift -// AutoCat -// -// Created by Selim Mustafaev on 24.06.2024. -// Copyright © 2024 Selim Mustafaev. All rights reserved. -// - -import Foundation - -struct Formatters { - - static let standard: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .medium - formatter.timeStyle = .medium - return formatter - }() - - static let marker: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .medium - formatter.timeStyle = .short - return formatter - }() - - static let short: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .short - formatter.timeStyle = .short - return formatter - }() -} diff --git a/AutoCatCore/Utils/Formatters.swift b/AutoCatCore/Utils/Formatters.swift index 5d8c74b..386be91 100644 --- a/AutoCatCore/Utils/Formatters.swift +++ b/AutoCatCore/Utils/Formatters.swift @@ -26,6 +26,13 @@ public struct Formatters { return formatter }() + public static let marker: DateFormatter = { + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .short + return formatter + }() + public static let time: DateComponentsFormatter = { let formatter = DateComponentsFormatter()