Adding navigation from new report to all detail screens. Adding sharing report link.
This commit is contained in:
parent
97e35ac785
commit
37b94aca62
@ -157,6 +157,9 @@
|
|||||||
7AB587412C42FFE200FA7B66 /* ApiServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB587402C42FFE200FA7B66 /* ApiServiceProtocol.swift */; };
|
7AB587412C42FFE200FA7B66 /* ApiServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB587402C42FFE200FA7B66 /* ApiServiceProtocol.swift */; };
|
||||||
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; };
|
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; };
|
||||||
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
|
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
|
||||||
|
7ABD1B472D044A3200B43213 /* GalleryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABD1B462D044A3200B43213 /* GalleryScreen.swift */; };
|
||||||
|
7ABD1B492D044A4700B43213 /* GalleryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABD1B482D044A4700B43213 /* GalleryViewModel.swift */; };
|
||||||
|
7ABD1B4B2D044A7D00B43213 /* GalleryCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABD1B4A2D044A7D00B43213 /* GalleryCoordinator.swift */; };
|
||||||
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7AC355492969652F00889457 /* SwiftEntryKit */; };
|
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7AC355492969652F00889457 /* SwiftEntryKit */; };
|
||||||
7AC3554C29696A1C00889457 /* MainTabController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3554B29696A1C00889457 /* MainTabController.swift */; };
|
7AC3554C29696A1C00889457 /* MainTabController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3554B29696A1C00889457 /* MainTabController.swift */; };
|
||||||
7AC3554E29696C4500889457 /* DummyNewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3554D29696C4500889457 /* DummyNewController.swift */; };
|
7AC3554E29696C4500889457 /* DummyNewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3554D29696C4500889457 /* DummyNewController.swift */; };
|
||||||
@ -428,6 +431,9 @@
|
|||||||
7AB587402C42FFE200FA7B66 /* ApiServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiServiceProtocol.swift; sourceTree = "<group>"; };
|
7AB587402C42FFE200FA7B66 /* ApiServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiServiceProtocol.swift; sourceTree = "<group>"; };
|
||||||
7AB67E8B2435C38700258F61 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
|
7AB67E8B2435C38700258F61 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
|
||||||
7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
|
7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
|
||||||
|
7ABD1B462D044A3200B43213 /* GalleryScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryScreen.swift; sourceTree = "<group>"; };
|
||||||
|
7ABD1B482D044A4700B43213 /* GalleryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
7ABD1B4A2D044A7D00B43213 /* GalleryCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryCoordinator.swift; sourceTree = "<group>"; };
|
||||||
7AC3554B29696A1C00889457 /* MainTabController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabController.swift; sourceTree = "<group>"; };
|
7AC3554B29696A1C00889457 /* MainTabController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabController.swift; sourceTree = "<group>"; };
|
||||||
7AC3554D29696C4500889457 /* DummyNewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyNewController.swift; sourceTree = "<group>"; };
|
7AC3554D29696C4500889457 /* DummyNewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyNewController.swift; sourceTree = "<group>"; };
|
||||||
7AC3554F29696D5A00889457 /* NewNumberController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNumberController.swift; sourceTree = "<group>"; };
|
7AC3554F29696D5A00889457 /* NewNumberController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNumberController.swift; sourceTree = "<group>"; };
|
||||||
@ -688,6 +694,7 @@
|
|||||||
7A1441632C297E9800E79018 /* Screens */ = {
|
7A1441632C297E9800E79018 /* Screens */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
7ABD1B452D044A0900B43213 /* GalleryScreen */,
|
||||||
7A1E78F42CE9001A0004B740 /* ReportScreen */,
|
7A1E78F42CE9001A0004B740 /* ReportScreen */,
|
||||||
7A43228F2CB2CC5D00085CF6 /* FiltersScreen */,
|
7A43228F2CB2CC5D00085CF6 /* FiltersScreen */,
|
||||||
7A06E0AA2C706550005731AC /* SettingsScreen */,
|
7A06E0AA2C706550005731AC /* SettingsScreen */,
|
||||||
@ -989,6 +996,16 @@
|
|||||||
path = ApiService;
|
path = ApiService;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
7ABD1B452D044A0900B43213 /* GalleryScreen */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
7ABD1B462D044A3200B43213 /* GalleryScreen.swift */,
|
||||||
|
7ABD1B482D044A4700B43213 /* GalleryViewModel.swift */,
|
||||||
|
7ABD1B4A2D044A7D00B43213 /* GalleryCoordinator.swift */,
|
||||||
|
);
|
||||||
|
path = GalleryScreen;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
7AC355552969742800889457 /* ACUIKit */ = {
|
7AC355552969742800889457 /* ACUIKit */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -1356,6 +1373,7 @@
|
|||||||
7A1E78F62CE900330004B740 /* ReportScreen.swift in Sources */,
|
7A1E78F62CE900330004B740 /* ReportScreen.swift in Sources */,
|
||||||
7A10226C2C551EC500B84627 /* LocationEditScreen.swift in Sources */,
|
7A10226C2C551EC500B84627 /* LocationEditScreen.swift in Sources */,
|
||||||
7A7158072C44085600852088 /* OsagoScreen.swift in Sources */,
|
7A7158072C44085600852088 /* OsagoScreen.swift in Sources */,
|
||||||
|
7ABD1B492D044A4700B43213 /* GalleryViewModel.swift in Sources */,
|
||||||
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */,
|
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */,
|
||||||
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */,
|
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */,
|
||||||
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */,
|
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */,
|
||||||
@ -1399,6 +1417,7 @@
|
|||||||
7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */,
|
7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */,
|
||||||
7A1441702C2998B200E79018 /* Formatters.swift in Sources */,
|
7A1441702C2998B200E79018 /* Formatters.swift in Sources */,
|
||||||
7A4322912CB2CC8A00085CF6 /* FiltersScreen.swift in Sources */,
|
7A4322912CB2CC8A00085CF6 /* FiltersScreen.swift in Sources */,
|
||||||
|
7ABD1B472D044A3200B43213 /* GalleryScreen.swift in Sources */,
|
||||||
7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */,
|
7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */,
|
||||||
7A71580C2C44453200852088 /* AdsScreen.swift in Sources */,
|
7A71580C2C44453200852088 /* AdsScreen.swift in Sources */,
|
||||||
7A06E0B02C7065D8005731AC /* SettingsCoordinator.swift in Sources */,
|
7A06E0B02C7065D8005731AC /* SettingsCoordinator.swift in Sources */,
|
||||||
@ -1407,6 +1426,7 @@
|
|||||||
7AFBE8CC2C3085C6003C491D /* ACProgressView.swift in Sources */,
|
7AFBE8CC2C3085C6003C491D /* ACProgressView.swift in Sources */,
|
||||||
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */,
|
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */,
|
||||||
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
|
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
|
||||||
|
7ABD1B4B2D044A7D00B43213 /* GalleryCoordinator.swift in Sources */,
|
||||||
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
|
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
|
||||||
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
|
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
|
||||||
7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */,
|
7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */,
|
||||||
|
|||||||
31
AutoCat/Screens/GalleryScreen/GalleryCoordinator.swift
Normal file
31
AutoCat/Screens/GalleryScreen/GalleryCoordinator.swift
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// GalleryCoordinator.swift
|
||||||
|
// AutoCat
|
||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 07.12.2024.
|
||||||
|
// Copyright © 2024 Selim Mustafaev. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SwiftUI
|
||||||
|
import AutoCatCore
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class GalleryCoordinator: Coordinator {
|
||||||
|
|
||||||
|
let viewController: UINavigationController
|
||||||
|
let photos: [VehiclePhotoDto]
|
||||||
|
|
||||||
|
init(navController: UINavigationController, photos: [VehiclePhotoDto]) {
|
||||||
|
|
||||||
|
self.viewController = navController
|
||||||
|
self.photos = photos
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() async throws {
|
||||||
|
|
||||||
|
let viewModel = GalleryViewModel(photos: photos)
|
||||||
|
let controller = UIHostingController(rootView: GalleryScreen(viewModel: viewModel))
|
||||||
|
viewController.pushViewController(controller, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
72
AutoCat/Screens/GalleryScreen/GalleryScreen.swift
Normal file
72
AutoCat/Screens/GalleryScreen/GalleryScreen.swift
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//
|
||||||
|
// GalleryScreen.swift
|
||||||
|
// AutoCat
|
||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 07.12.2024.
|
||||||
|
// Copyright © 2024 Selim Mustafaev. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import AutoCatCore
|
||||||
|
|
||||||
|
struct GalleryScreen: View {
|
||||||
|
|
||||||
|
@State var viewModel: GalleryViewModel
|
||||||
|
|
||||||
|
@State var galleryModel: ACImageSliderModel?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView {
|
||||||
|
LazyVGrid(columns: columns, spacing: 2) {
|
||||||
|
ForEach(viewModel.photos) { photo in
|
||||||
|
ZStack {
|
||||||
|
AsyncImage(url: URL(string: photo.url)) { phase in
|
||||||
|
switch phase {
|
||||||
|
case .success(let image):
|
||||||
|
image
|
||||||
|
.resizable()
|
||||||
|
.scaledToFill()
|
||||||
|
default:
|
||||||
|
ZStack {
|
||||||
|
Rectangle()
|
||||||
|
.foregroundStyle(.quaternary)
|
||||||
|
Image(systemName: "photo")
|
||||||
|
.font(.system(size: 48))
|
||||||
|
.foregroundStyle(.tertiary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.layoutPriority(-1)
|
||||||
|
.onTapGesture {
|
||||||
|
guard let url = URL(string: photo.url) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
galleryModel = ACImageSliderModel(
|
||||||
|
urls: viewModel.photos.compactMap { URL(string: $0.url) },
|
||||||
|
selected: url
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Color.clear
|
||||||
|
}
|
||||||
|
.aspectRatio(1, contentMode: .fit)
|
||||||
|
.clipped()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.imageSlider($galleryModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
var columns: [GridItem] {
|
||||||
|
[
|
||||||
|
GridItem(.flexible(), spacing: 2),
|
||||||
|
GridItem(.flexible(), spacing: 2),
|
||||||
|
GridItem(.flexible(), spacing: 2)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
GalleryScreen(viewModel: .init(photos: []))
|
||||||
|
}
|
||||||
21
AutoCat/Screens/GalleryScreen/GalleryViewModel.swift
Normal file
21
AutoCat/Screens/GalleryScreen/GalleryViewModel.swift
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// GalleryViewModel.swift
|
||||||
|
// AutoCat
|
||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 07.12.2024.
|
||||||
|
// Copyright © 2024 Selim Mustafaev. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import AutoCatCore
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
@Observable
|
||||||
|
class GalleryViewModel {
|
||||||
|
|
||||||
|
let photos: [VehiclePhotoDto]
|
||||||
|
|
||||||
|
init(photos: [VehiclePhotoDto]) {
|
||||||
|
self.photos = photos
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -22,10 +22,12 @@ class NotesCoordinator: Coordinator {
|
|||||||
self.vehicle = vehicle
|
self.vehicle = vehicle
|
||||||
}
|
}
|
||||||
|
|
||||||
func start() async throws {
|
func start() async throws -> VehicleDto {
|
||||||
|
|
||||||
let viewModel = NotesViewModel(vehicle: vehicle)
|
let viewModel = NotesViewModel(vehicle: vehicle)
|
||||||
let controller = UIHostingController(rootView: NotesScreen(viewModel: viewModel))
|
let controller = CustomHostingController(rootView: NotesScreen(viewModel: viewModel))
|
||||||
viewController?.pushViewController(controller, animated: true)
|
viewController?.pushViewController(controller, animated: true)
|
||||||
|
await controller.waitForDisappear()
|
||||||
|
return viewModel.vehicle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class ReportCoordinator: Coordinator {
|
|||||||
let vehicle: VehicleDto
|
let vehicle: VehicleDto
|
||||||
let isPersistent: Bool
|
let isPersistent: Bool
|
||||||
|
|
||||||
var navController: UINavigationController?
|
weak var navController: UINavigationController?
|
||||||
|
|
||||||
init(splitController: UISplitViewController?, vehicle: VehicleDto, isPersistent: Bool) {
|
init(splitController: UISplitViewController?, vehicle: VehicleDto, isPersistent: Bool) {
|
||||||
|
|
||||||
@ -34,26 +34,26 @@ class ReportCoordinator: Coordinator {
|
|||||||
let viewModel = ReportViewModel(vehicle: vehicle, isPersistent: isPersistent)
|
let viewModel = ReportViewModel(vehicle: vehicle, isPersistent: isPersistent)
|
||||||
viewModel.coordinator = self
|
viewModel.coordinator = self
|
||||||
let controller = UIHostingController(rootView: ReportScreen(viewModel: viewModel))
|
let controller = UIHostingController(rootView: ReportScreen(viewModel: viewModel))
|
||||||
navController = UINavigationController(rootViewController: controller)
|
//navController = UINavigationController(rootViewController: controller)
|
||||||
|
viewController?.showDetailViewController(controller, sender: self)
|
||||||
|
navController = controller.navigationController
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if let navController {
|
if let navController {
|
||||||
navController.popToRootViewController(animated: true)
|
// navController.popToRootViewController(animated: true)
|
||||||
let report = navController.viewControllers.first as? ReportController
|
// let report = navController.viewControllers.first as? ReportController
|
||||||
report?.number = vehicle.getNumber()
|
// report?.number = vehicle.getNumber()
|
||||||
viewController?.showDetailViewController(navController, sender: self)
|
viewController?.showDetailViewController(navController, sender: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openEvents(vehicle: VehicleDto) {
|
func openEvents(vehicle: VehicleDto, onUpdate: @escaping (VehicleDto) -> Void) {
|
||||||
|
|
||||||
let sb = UIStoryboard(name: "Main", bundle: nil)
|
let sb = UIStoryboard(name: "Main", bundle: nil)
|
||||||
let controller = sb.instantiateViewController(identifier: "EventsController") as EventsController
|
let controller = sb.instantiateViewController(identifier: "EventsController") as EventsController
|
||||||
controller.vehicle = self.vehicle
|
controller.vehicle = vehicle
|
||||||
controller.vehicleUpdated = { vehicle in
|
controller.vehicleUpdated = onUpdate
|
||||||
// TODO: Propagate vehicle update upwards
|
|
||||||
//self.vehicle = vehicle
|
|
||||||
}
|
|
||||||
navController?.pushViewController(controller, animated: true)
|
navController?.pushViewController(controller, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,4 +76,35 @@ class ReportCoordinator: Coordinator {
|
|||||||
try? await coordiantor.start()
|
try? await coordiantor.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func openNotes(vehicle: VehicleDto) async -> VehicleDto? {
|
||||||
|
guard let navController else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let coordinator = NotesCoordinator(navController: navController, vehicle: vehicle)
|
||||||
|
return try? await coordinator.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func openAds(_ ads: [VehicleAdDto]) {
|
||||||
|
guard let navController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Task {
|
||||||
|
let coordinator = AdsCoordinator(navController: navController, ads: ads)
|
||||||
|
try? await coordinator.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func openPhotos(_ photos: [VehiclePhotoDto]) {
|
||||||
|
guard let navController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Task {
|
||||||
|
let coordinator = GalleryCoordinator(navController: navController, photos: photos)
|
||||||
|
try? await coordinator.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,17 +53,23 @@ struct ReportScreen: View {
|
|||||||
|
|
||||||
Section("History") {
|
Section("History") {
|
||||||
LabeledContent("Events", value: String(viewModel.vehicle.events.count))
|
LabeledContent("Events", value: String(viewModel.vehicle.events.count))
|
||||||
.navigationLink(onTap: viewModel.openEvents)
|
.navigationLink(isActive: !viewModel.vehicle.events.isEmpty,
|
||||||
|
onTap: viewModel.openEvents)
|
||||||
LabeledContent("OSAGO", value: String(viewModel.vehicle.osagoContracts.count))
|
LabeledContent("OSAGO", value: String(viewModel.vehicle.osagoContracts.count))
|
||||||
.navigationLink(onTap: viewModel.openOsago)
|
.navigationLink(isActive: !viewModel.vehicle.osagoContracts.isEmpty,
|
||||||
|
onTap: viewModel.openOsago)
|
||||||
LabeledContent("Owners", value: String(viewModel.vehicle.ownershipPeriods.count))
|
LabeledContent("Owners", value: String(viewModel.vehicle.ownershipPeriods.count))
|
||||||
.navigationLink(onTap: viewModel.openOwners)
|
.navigationLink(isActive: !viewModel.vehicle.ownershipPeriods.isEmpty,
|
||||||
|
onTap: viewModel.openOwners)
|
||||||
LabeledContent("Photos", value: String(viewModel.vehicle.photos.count))
|
LabeledContent("Photos", value: String(viewModel.vehicle.photos.count))
|
||||||
.navigationLink(onTap: viewModel.openPhotoGallery)
|
.navigationLink(isActive: !viewModel.vehicle.photos.isEmpty,
|
||||||
|
onTap: viewModel.openPhotoGallery)
|
||||||
LabeledContent("Ads", value: String(viewModel.vehicle.ads.count))
|
LabeledContent("Ads", value: String(viewModel.vehicle.ads.count))
|
||||||
.navigationLink(onTap: viewModel.openAds)
|
.navigationLink(isActive: !viewModel.vehicle.ads.isEmpty,
|
||||||
|
onTap: viewModel.openAds)
|
||||||
LabeledContent("Notes", value: String(viewModel.vehicle.notes.count))
|
LabeledContent("Notes", value: String(viewModel.vehicle.notes.count))
|
||||||
.navigationLink(onTap: viewModel.openNotes)
|
.navigationLink(isActive: !viewModel.vehicle.notes.isEmpty,
|
||||||
|
onTap: viewModel.openNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if viewModel.showDebugInfo {
|
if viewModel.showDebugInfo {
|
||||||
@ -86,6 +92,11 @@ struct ReportScreen: View {
|
|||||||
Task { await viewModel.onAppear() }
|
Task { await viewModel.onAppear() }
|
||||||
}
|
}
|
||||||
.hud($viewModel.hud)
|
.hud($viewModel.hud)
|
||||||
|
.toolbar {
|
||||||
|
if let link = viewModel.shareLink {
|
||||||
|
ShareLink(item: link)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
|
|||||||
@ -47,6 +47,14 @@ class ReportViewModel: ACHudContainer {
|
|||||||
settings.showDebugInfo
|
settings.showDebugInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var shareLink: URL? {
|
||||||
|
guard let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return URL(string: Constants.reportLinkBaseURL + "?token=" + jwt)
|
||||||
|
}
|
||||||
|
|
||||||
init(vehicle: VehicleDto, isPersistent: Bool) {
|
init(vehicle: VehicleDto, isPersistent: Bool) {
|
||||||
self.vehicle = vehicle
|
self.vehicle = vehicle
|
||||||
self.isPersistent = isPersistent
|
self.isPersistent = isPersistent
|
||||||
@ -84,7 +92,9 @@ class ReportViewModel: ACHudContainer {
|
|||||||
// MARK: Open detail screens
|
// MARK: Open detail screens
|
||||||
|
|
||||||
func openEvents() {
|
func openEvents() {
|
||||||
coordinator?.openEvents(vehicle: vehicle)
|
coordinator?.openEvents(vehicle: vehicle) { [weak self] vehicle in
|
||||||
|
self?.vehicle = vehicle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openOsago() {
|
func openOsago() {
|
||||||
@ -96,14 +106,18 @@ class ReportViewModel: ACHudContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func openPhotoGallery() {
|
func openPhotoGallery() {
|
||||||
|
coordinator?.openPhotos(vehicle.photos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func openNotes() {
|
func openNotes() {
|
||||||
|
Task {
|
||||||
|
if let vehicle = await coordinator?.openNotes(vehicle: vehicle) {
|
||||||
|
self.vehicle = vehicle
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openAds() {
|
func openAds() {
|
||||||
|
coordinator?.openAds(vehicle.ads)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,10 +11,14 @@ import SwiftUI
|
|||||||
struct NavigationLinkModifier: ViewModifier {
|
struct NavigationLinkModifier: ViewModifier {
|
||||||
|
|
||||||
var onTap: (() -> Void)?
|
var onTap: (() -> Void)?
|
||||||
|
var isActive: Bool
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
|
|
||||||
if let onTap {
|
if !isActive {
|
||||||
|
content
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
} else if let onTap {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
content
|
content
|
||||||
Spacer()
|
Spacer()
|
||||||
@ -33,7 +37,7 @@ struct NavigationLinkModifier: ViewModifier {
|
|||||||
|
|
||||||
extension View {
|
extension View {
|
||||||
|
|
||||||
func navigationLink(onTap: (() -> Void)?) -> some View {
|
func navigationLink(isActive: Bool = true, onTap: (() -> Void)?) -> some View {
|
||||||
modifier(NavigationLinkModifier(onTap: onTap))
|
modifier(NavigationLinkModifier(onTap: onTap, isActive: isActive))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,13 +8,19 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct VehiclePhotoDto: Decodable, Sendable, Equatable {
|
public struct VehiclePhotoDto: Decodable, Sendable, Equatable, Identifiable {
|
||||||
|
|
||||||
|
public let id = UUID()
|
||||||
public var brand: String?
|
public var brand: String?
|
||||||
public var model: String?
|
public var model: String?
|
||||||
public var date: TimeInterval = 0
|
public var date: TimeInterval = 0
|
||||||
public var url: String = ""
|
public var url: String = ""
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
|
||||||
|
case brand, model, date, url
|
||||||
|
}
|
||||||
|
|
||||||
public var description: String {
|
public var description: String {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.timeZone = TimeZone(identifier:"GMT")
|
formatter.timeZone = TimeZone(identifier:"GMT")
|
||||||
@ -24,4 +30,15 @@ public struct VehiclePhotoDto: Decodable, Sendable, Equatable {
|
|||||||
let dateStr = formatter.string(from: date)
|
let dateStr = formatter.string(from: date)
|
||||||
return "\(self.brand ?? "") \(self.model ?? "") (\(dateStr))"
|
return "\(self.brand ?? "") \(self.model ?? "") (\(dateStr))"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public init(brand: String? = nil,
|
||||||
|
model: String? = nil,
|
||||||
|
date: TimeInterval,
|
||||||
|
url: String) {
|
||||||
|
|
||||||
|
self.brand = brand
|
||||||
|
self.model = model
|
||||||
|
self.date = date
|
||||||
|
self.url = url
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user