Removing Kingfisher package.
Adding License Plate view. Adding stub for new SwiftUI history screen.
This commit is contained in:
parent
57c222b937
commit
67977f1ebf
@ -30,6 +30,9 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
7A1441662C297EDE00E79018 /* NotesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1441652C297EDE00E79018 /* NotesScreen.swift */; };
|
||||
7A1441682C297EFD00E79018 /* NotesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1441672C297EFD00E79018 /* NotesViewModel.swift */; };
|
||||
7A14416C2C297F2100E79018 /* NotesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416B2C297F2100E79018 /* NotesCoordinator.swift */; };
|
||||
@ -115,7 +118,6 @@
|
||||
7A71580E2C4445A200852088 /* AdsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A71580D2C4445A200852088 /* AdsCoordinator.swift */; };
|
||||
7A7158122C444A6400852088 /* AdsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158112C444A6400852088 /* AdsViewModel.swift */; };
|
||||
7A71EF572D0A26B200943129 /* EventModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A71EF562D0A26B200943129 /* EventModel.swift */; };
|
||||
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */; };
|
||||
7A761C042677F18E0005F28F /* ApiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474323FF06CA00B424AF /* ApiService.swift */; };
|
||||
7A761C052677F1BC0005F28F /* CocoaError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF824A09CAD0035F39E /* CocoaError.swift */; };
|
||||
7A761C07267E8E7F0005F28F /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A15051124DB3E3000F39631 /* AnyEncodable.swift */; };
|
||||
@ -124,8 +126,8 @@
|
||||
7A761C0B267E8FF90005F28F /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A761C0A267E8FF90005F28F /* Error.swift */; };
|
||||
7A813DC32508EE4F00CC93B9 /* EventCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A813DC22508EE4F00CC93B9 /* EventCell.swift */; };
|
||||
7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */; };
|
||||
7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8A220A248D67B60073DFD9 /* VehicleReportImage.swift */; };
|
||||
7A8AB76525A0DB8F00ECF2C1 /* BundleVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */; };
|
||||
7A912F372D381B7400002938 /* LicensePlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A912F362D381B7400002938 /* LicensePlateView.swift */; };
|
||||
7A91894F29A2BD8700519C74 /* GestureRecognizers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A91894E29A2BD8700519C74 /* GestureRecognizers.swift */; };
|
||||
7A961C6C2C4C3C8600CE2211 /* TextRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A961C6B2C4C3C8600CE2211 /* TextRowView.swift */; };
|
||||
7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A961C6D2C4C3C9E00CE2211 /* LinkRowView.swift */; };
|
||||
@ -134,7 +136,6 @@
|
||||
7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A99406326E4BFAE002E9CB6 /* VehicleNoteCell.swift */; };
|
||||
7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FEEC72529AB23001CA50E /* RxRealmDataSource.swift */; };
|
||||
7AA514E02D0B75B3001CAC50 /* StorageService+Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA514DF2D0B75B3001CAC50 /* StorageService+Events.swift */; };
|
||||
7AA7BC3325A5DFB80053A5D5 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D332402A91C00CE01A0 /* Kingfisher */; };
|
||||
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; };
|
||||
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABDE1C2532F3EB0041AFC6 /* PKHUD */; };
|
||||
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFAD22C4D0FD00050410D /* ACImageSliderView.swift */; };
|
||||
@ -289,6 +290,9 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
7A1441652C297EDE00E79018 /* NotesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesScreen.swift; sourceTree = "<group>"; };
|
||||
7A1441672C297EFD00E79018 /* NotesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesViewModel.swift; sourceTree = "<group>"; };
|
||||
7A14416B2C297F2100E79018 /* NotesCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesCoordinator.swift; sourceTree = "<group>"; };
|
||||
@ -387,14 +391,13 @@
|
||||
7A71580D2C4445A200852088 /* AdsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsCoordinator.swift; sourceTree = "<group>"; };
|
||||
7A7158112C444A6400852088 /* AdsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsViewModel.swift; sourceTree = "<group>"; };
|
||||
7A71EF562D0A26B200943129 /* EventModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventModel.swift; sourceTree = "<group>"; };
|
||||
7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehiclePhotoCell.swift; sourceTree = "<group>"; };
|
||||
7A761C0A267E8FF90005F28F /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizeImage.swift; sourceTree = "<group>"; };
|
||||
7A8A220A248D67B60073DFD9 /* VehicleReportImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleReportImage.swift; sourceTree = "<group>"; };
|
||||
7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleVersion.swift; sourceTree = "<group>"; };
|
||||
7A8AB76725A0DC8200ECF2C1 /* DebugInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugInfo.swift; sourceTree = "<group>"; };
|
||||
7A912F362D381B7400002938 /* LicensePlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensePlateView.swift; sourceTree = "<group>"; };
|
||||
7A91894E29A2BD8700519C74 /* GestureRecognizers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureRecognizers.swift; sourceTree = "<group>"; };
|
||||
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; };
|
||||
7A961C6B2C4C3C8600CE2211 /* TextRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRowView.swift; sourceTree = "<group>"; };
|
||||
@ -468,7 +471,6 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */,
|
||||
7AA7BC3325A5DFB80053A5D5 /* Kingfisher in Frameworks */,
|
||||
7ADF23062C25B5BF002624FF /* RealmSwift in Frameworks */,
|
||||
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */,
|
||||
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */,
|
||||
@ -670,9 +672,20 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7A131FD12D37B74100DC7755 /* HistoryScreen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7A131FD22D37B75500DC7755 /* HistoryScreen.swift */,
|
||||
7A131FD42D37B76A00DC7755 /* HistoryViewModel.swift */,
|
||||
7A131FD62D37B77E00DC7755 /* HistoryCoordinator.swift */,
|
||||
);
|
||||
path = HistoryScreen;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7A1441632C297E9800E79018 /* Screens */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7A131FD12D37B74100DC7755 /* HistoryScreen */,
|
||||
7AB9FE202D08C28E005DE374 /* EventsScreen */,
|
||||
7ABD1B452D044A0900B43213 /* GalleryScreen */,
|
||||
7A1E78F42CE9001A0004B740 /* ReportScreen */,
|
||||
@ -729,7 +742,6 @@
|
||||
7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */,
|
||||
7A659B5A24A3768A0043A0F2 /* Substrings.swift */,
|
||||
7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */,
|
||||
7A8A220A248D67B60073DFD9 /* VehicleReportImage.swift */,
|
||||
7A761C0A267E8FF90005F28F /* Error.swift */,
|
||||
7AC76D7A270083AE0084DB27 /* TextView.swift */,
|
||||
);
|
||||
@ -761,7 +773,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */,
|
||||
7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */,
|
||||
7A1090E724A394F100B4F0B2 /* AudioRecordCell.swift */,
|
||||
7A813DC22508EE4F00CC93B9 /* EventCell.swift */,
|
||||
7AEFC3BD2529D3CC00BADFB2 /* ConfigurableCell.swift */,
|
||||
@ -1070,6 +1081,7 @@
|
||||
7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */,
|
||||
7A4927D42CCE438600851C01 /* OptionalBinding.swift */,
|
||||
7AABBE3A2CF9F85600346588 /* Binding+Map.swift */,
|
||||
7A912F362D381B7400002938 /* LicensePlateView.swift */,
|
||||
);
|
||||
path = SwiftUI;
|
||||
sourceTree = "<group>";
|
||||
@ -1115,7 +1127,6 @@
|
||||
);
|
||||
name = AutoCat;
|
||||
packageProductDependencies = (
|
||||
7AF58D332402A91C00CE01A0 /* Kingfisher */,
|
||||
7A813DC02508C4D900CC93B9 /* ExceptionCatcher */,
|
||||
7AABDE1C2532F3EB0041AFC6 /* PKHUD */,
|
||||
7AC355492969652F00889457 /* SwiftEntryKit */,
|
||||
@ -1236,7 +1247,6 @@
|
||||
);
|
||||
mainGroup = 7A1146F423FDE7E500B424AF;
|
||||
packageReferences = (
|
||||
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */,
|
||||
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */,
|
||||
7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */,
|
||||
@ -1354,6 +1364,7 @@
|
||||
7A7158072C44085600852088 /* OsagoScreen.swift in Sources */,
|
||||
7ABD1B492D044A4700B43213 /* GalleryViewModel.swift in Sources */,
|
||||
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */,
|
||||
7A912F372D381B7400002938 /* LicensePlateView.swift in Sources */,
|
||||
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */,
|
||||
7AC76D7B270083AE0084DB27 /* TextView.swift in Sources */,
|
||||
7A1090E824A394F100B4F0B2 /* AudioRecordCell.swift in Sources */,
|
||||
@ -1387,11 +1398,11 @@
|
||||
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */,
|
||||
7AC35554296973E100889457 /* ACButton.swift in Sources */,
|
||||
7AAAFADC2C4D1E130050410D /* ACImageSliderView+Modifier.swift in Sources */,
|
||||
7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */,
|
||||
7AFBE8C42C302561003C491D /* ACHudContainer.swift in Sources */,
|
||||
7AC3555B296995B200889457 /* UIEdgeInsets.swift in Sources */,
|
||||
7A06E0AC2C7065AC005731AC /* SettingsScreen.swift in Sources */,
|
||||
7A4322952CB2CD0F00085CF6 /* FiltersCoordinator.swift in Sources */,
|
||||
7A131FD72D37B77E00DC7755 /* HistoryCoordinator.swift in Sources */,
|
||||
7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */,
|
||||
7A1441702C2998B200E79018 /* Formatters.swift in Sources */,
|
||||
7A4322912CB2CC8A00085CF6 /* FiltersScreen.swift in Sources */,
|
||||
@ -1401,6 +1412,7 @@
|
||||
7A06E0B02C7065D8005731AC /* SettingsCoordinator.swift in Sources */,
|
||||
7A91894F29A2BD8700519C74 /* GestureRecognizers.swift in Sources */,
|
||||
7AFBE8CC2C3085C6003C491D /* ACProgressView.swift in Sources */,
|
||||
7A131FD32D37B75500DC7755 /* HistoryScreen.swift in Sources */,
|
||||
7AB9FE222D08C2A5005DE374 /* EventsScreen.swift in Sources */,
|
||||
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */,
|
||||
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
|
||||
@ -1409,8 +1421,8 @@
|
||||
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
|
||||
7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */,
|
||||
7A7158042C43EAA200852088 /* OwnersCoordinator.swift in Sources */,
|
||||
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
|
||||
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */,
|
||||
7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -2013,14 +2025,6 @@
|
||||
minimumVersion = 0.0.11;
|
||||
};
|
||||
};
|
||||
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
||||
requirement = {
|
||||
branch = "8.0.0-alpha.1";
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
@ -2074,11 +2078,6 @@
|
||||
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
|
||||
productName = RealmSwift;
|
||||
};
|
||||
7AF58D332402A91C00CE01A0 /* Kingfisher */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||
productName = Kingfisher;
|
||||
};
|
||||
7AF8606B2CB9B20C00954D2F /* Mockable */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"originHash" : "d6bab97967371dd248cd5b3fdb49293879398c897bea34714c48fd3d4cb90fb1",
|
||||
"originHash" : "6fccb9fdc0d29647d4f0b927aef60f375302d72b5b724992eab52ac0d8ec71c3",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "exceptioncatcher",
|
||||
@ -10,15 +10,6 @@
|
||||
"version" : "1.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "kingfisher",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/onevcat/Kingfisher",
|
||||
"state" : {
|
||||
"branch" : "8.0.0-alpha.1",
|
||||
"revision" : "bb4e6ecf6c7a221dfc51c8e69f04fd3757fc519a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "mockable",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
||||
@ -2,8 +2,6 @@ import UIKit
|
||||
import RealmSwift
|
||||
import PKHUD
|
||||
import AutoCatCore
|
||||
import SwiftLocation
|
||||
import CoreLocation
|
||||
|
||||
enum QuickAction {
|
||||
case none
|
||||
@ -72,11 +70,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
HUD.dimsBackground = true
|
||||
HUD.allowsInteraction = false
|
||||
|
||||
registerServices()
|
||||
setupAppearance()
|
||||
|
||||
//Logging.URLRequests = { _ in false };
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -92,29 +87,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
UINavigationBar.appearance().standardAppearance = navigationBarAppearance
|
||||
UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance
|
||||
}
|
||||
|
||||
func registerServices() {
|
||||
|
||||
let container = ServiceContainer.shared
|
||||
|
||||
let settingsService = SettingsService(defaults: .standard)
|
||||
|
||||
container.register(SettingsServiceProtocol.self, instance: settingsService)
|
||||
container.register(ApiServiceProtocol.self, instance: ApiService())
|
||||
|
||||
let locationService = LocationService(
|
||||
geocoder: CLGeocoder(),
|
||||
locationManager: Location(),
|
||||
settingsService: settingsService
|
||||
)
|
||||
|
||||
container.register(LocationServiceProtocol.self, instance: locationService)
|
||||
|
||||
Task {
|
||||
container.register(StorageServiceProtocol.self,
|
||||
instance: try await StorageService(settingsService: settingsService))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: UISceneSession Lifecycle
|
||||
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
import UIKit
|
||||
import Kingfisher
|
||||
import AutoCatCore
|
||||
|
||||
@MainActor
|
||||
class VehiclePhotoCell: UICollectionViewCell {
|
||||
@IBOutlet weak var photo: UIImageView!
|
||||
@IBOutlet weak var model: UILabel!
|
||||
@IBOutlet weak var date: UILabel!
|
||||
|
||||
let formatter = DateFormatter()
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.layer.cornerRadius = 8
|
||||
self.formatter.timeStyle = .none
|
||||
self.formatter.dateStyle = .medium
|
||||
}
|
||||
}
|
||||
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
self.photo.kf.cancelDownloadTask()
|
||||
}
|
||||
|
||||
func configure(with photoModel: VehiclePhoto) {
|
||||
if let url = URL(string: photoModel.url) {
|
||||
self.photo.kf.setImage(with: url)
|
||||
}
|
||||
|
||||
self.model.text = "\(photoModel.brand ?? "") \(photoModel.model ?? "")"
|
||||
|
||||
let date = Date(timeIntervalSince1970: photoModel.date/1000)
|
||||
self.date.text = formatter.string(from: date)
|
||||
}
|
||||
}
|
||||
@ -23,9 +23,19 @@ class MainTabController: UITabBarController, UITabBarControllerDelegate {
|
||||
traitOverrides.horizontalSizeClass = .compact
|
||||
}
|
||||
|
||||
setupHistoryTab()
|
||||
Task { await addSettings() }
|
||||
}
|
||||
|
||||
func setupHistoryTab() {
|
||||
|
||||
let coordinator = HistoryCoordinator()
|
||||
let controller = coordinator.start()
|
||||
controller.tabBarItem = UITabBarItem(title: NSLocalizedString("History", comment: ""),
|
||||
image: UIImage(systemName: "clock.arrow.circlepath"), tag: 0)
|
||||
viewControllers?[0] = controller
|
||||
}
|
||||
|
||||
func addSettings() async {
|
||||
|
||||
let coordinator = SettingsCoordinator(tabController: self)
|
||||
|
||||
@ -1,280 +0,0 @@
|
||||
import UIKit
|
||||
import Kingfisher
|
||||
import AutoCatCore
|
||||
|
||||
extension VehicleDto {
|
||||
|
||||
@MainActor
|
||||
func drawLine(y: CGFloat, width: CGFloat, margin: CGFloat = 15,context: CGContext) {
|
||||
let lineWidth = 1/UIScreen.main.scale
|
||||
context.move(to: CGPoint(x: margin, y: y + lineWidth/2))
|
||||
context.addLine(to: CGPoint(x: width, y: y + lineWidth/2))
|
||||
context.closePath()
|
||||
context.setLineWidth(lineWidth)
|
||||
context.setStrokeColor(UIColor.opaqueSeparator.cgColor)
|
||||
context.strokePath()
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func drawCell(y: CGFloat, width: CGFloat, height: CGFloat, title: String, value: String, lineMargin: CGFloat = 15, context: CGContext) {
|
||||
let fontSize: CGFloat = 17
|
||||
let font = UIFont.systemFont(ofSize: fontSize)
|
||||
let offest = (height - fontSize)/2
|
||||
let pStyle = NSMutableParagraphStyle()
|
||||
pStyle.alignment = .right
|
||||
let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.label]
|
||||
let valueAttributs: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.secondaryLabel, .paragraphStyle: pStyle]
|
||||
let rect = CGRect(x: 15, y: y + offest, width: width - 30, height: height)
|
||||
UIColor.secondarySystemGroupedBackground.setFill()
|
||||
UIRectFill(CGRect(x: 0, y: y, width: width, height: height))
|
||||
title.draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
|
||||
value.draw(with: rect, options: .usesLineFragmentOrigin, attributes: valueAttributs, context: nil)
|
||||
self.drawLine(y: y + height - 1/UIScreen.main.scale, width: width, margin: lineMargin, context: context)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func drawBigTextCell(y: CGFloat, width: CGFloat, title: String, value: String, lineMargin: CGFloat = 15, context: CGContext) -> CGFloat {
|
||||
let pStyle = NSMutableParagraphStyle()
|
||||
pStyle.alignment = .right
|
||||
let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 17), .foregroundColor: UIColor.label]
|
||||
let valueAttributs: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 15), .foregroundColor: UIColor.secondaryLabel, .paragraphStyle: pStyle]
|
||||
UIColor.secondarySystemGroupedBackground.setFill()
|
||||
|
||||
let text = NSMutableAttributedString(string: title + " - " + value)
|
||||
text.setAttributes(attributes, range: NSRange(location: 0, length: title.count))
|
||||
text.setAttributes(valueAttributs, range: NSRange(location: title.count, length: value.count + 3))
|
||||
let textRect = text.boundingRect(with: CGSize(width: width - 30, height: 1000), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
|
||||
let height = textRect.size.height > 28 ? textRect.size.height + 16 : 44
|
||||
let offset = (height - textRect.size.height)/2
|
||||
let rect = CGRect(x: 15, y: y + offset, width: width - 30, height: height)
|
||||
UIRectFill(CGRect(x: 0, y: y, width: width, height: height))
|
||||
text.draw(with: rect, options: .usesLineFragmentOrigin, context: nil)
|
||||
self.drawLine(y: y + height - 1/UIScreen.main.scale, width: width, margin: lineMargin, context: context)
|
||||
|
||||
return height
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func reportImage(width: CGFloat) -> UIImage {
|
||||
var realHeight: CGFloat = 0
|
||||
let rect = CGRect(origin: .zero, size: CGSize(width: width, height: CGFloat(10000)))
|
||||
let renderer = UIGraphicsImageRenderer(bounds: rect)
|
||||
let image = renderer.image { rendererContext in
|
||||
let cellHeight: CGFloat = 44
|
||||
let ctx = rendererContext.cgContext
|
||||
let centeredStyle = NSMutableParagraphStyle()
|
||||
centeredStyle.alignment = .center
|
||||
let titleAttributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 20), .paragraphStyle: centeredStyle, .foregroundColor: UIColor.label]
|
||||
let headerAttributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 13), .foregroundColor: UIColor.secondaryLabel]
|
||||
|
||||
let w: CGFloat = width
|
||||
var y: CGFloat = 0
|
||||
|
||||
UIColor.systemGroupedBackground.setFill()
|
||||
UIRectFill(rect)
|
||||
|
||||
y += 12
|
||||
"\(self.brand?.name?.original ?? "Unknown model") (\(self.getNumber()))".draw(with: CGRect(x: 0, y: y, width: w, height: 30), options: .usesLineFragmentOrigin, attributes: titleAttributes, context: nil)
|
||||
y += 50
|
||||
"GENERAL".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
||||
y += 24
|
||||
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
||||
y += 1/UIScreen.main.scale
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Year", value: String(self.year), context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Color", value: self.color ?? "<unknown>", context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Category", value: self.category ?? "<unknown>", context: ctx)
|
||||
y += cellHeight
|
||||
var position = "Unknown"
|
||||
if let rightWheel = self.isRightWheel {
|
||||
position = rightWheel ? "Right" : "Left"
|
||||
}
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Steering wheel position", value: position, context: ctx)
|
||||
y += cellHeight
|
||||
var japanese = "<Unknown>"
|
||||
if let isJapanese = self.isJapanese {
|
||||
japanese = isJapanese ? "Yes" : "No"
|
||||
}
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Japanese", value: japanese, lineMargin: 0, context: ctx)
|
||||
y += cellHeight + 32
|
||||
|
||||
"IDENTIFIERS".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
||||
y += 24
|
||||
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
||||
y += 1/UIScreen.main.scale
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Plate number", value: self.getNumber(), context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "VIN", value: self.vin1 ?? "<unknown>", context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "STS", value: self.sts ?? "<unknown>", context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "PTS", value: self.pts ?? "<unknown>", context: ctx)
|
||||
y += cellHeight + 32
|
||||
|
||||
"ENGINE".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
||||
y += 24
|
||||
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
||||
y += 1/UIScreen.main.scale
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Number", value: self.engine?.number ?? "<unknown>", context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Fuel type", value: self.engine?.fuelType ?? "<unknown>", context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Volume (cm³)", value: String(self.engine?.volume ?? 0), context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (HP)", value: String(self.engine?.powerHp ?? 0), context: ctx)
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (kw)", value: String(self.engine?.powerKw ?? 0), context: ctx)
|
||||
y += cellHeight + 32
|
||||
|
||||
"OWNERSHIP PERIODS (\(self.ownershipPeriods.count))".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
||||
y += 24
|
||||
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
||||
y += 1/UIScreen.main.scale
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .long
|
||||
formatter.timeStyle = .none
|
||||
for period in self.ownershipPeriods {
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Owner type", value: period.ownerType, context: ctx)
|
||||
y += cellHeight
|
||||
|
||||
let fromDate = Date(timeIntervalSince1970: TimeInterval(period.from/1000))
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "From", value: formatter.string(from: fromDate), context: ctx)
|
||||
y += cellHeight
|
||||
|
||||
let toDate = Date(timeIntervalSince1970: TimeInterval(period.to/1000))
|
||||
let toString = period.to == 0 ? "now" : formatter.string(from: toDate)
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "To", value: toString, context: ctx)
|
||||
y += cellHeight
|
||||
|
||||
let height = self.drawBigTextCell(y: y, width: w, title: "Last operation", value: period.lastOperation, lineMargin: 0, context: ctx)
|
||||
y += height + 8
|
||||
}
|
||||
|
||||
y += 24
|
||||
|
||||
if !self.events.isEmpty {
|
||||
"LOCATIONS".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
||||
y += 24
|
||||
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
||||
y += 1/UIScreen.main.scale
|
||||
|
||||
for event in self.events {
|
||||
let date = Date(timeIntervalSince1970: event.date)
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Date", value: formatter.string(from: date), context: ctx)
|
||||
y += cellHeight
|
||||
|
||||
if let address = event.address {
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Address", value: address, context: ctx)
|
||||
y += cellHeight
|
||||
}
|
||||
|
||||
let location = String(format: "%.05f, %.05f", event.latitude, event.longitude)
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Location", value: location, context: ctx)
|
||||
y += cellHeight + 8
|
||||
}
|
||||
}
|
||||
|
||||
y += 24
|
||||
|
||||
"PHOTOS (\(self.photos.count))".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
||||
y += 24
|
||||
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
||||
y += 1/UIScreen.main.scale
|
||||
|
||||
// TODO: Fix drawing photos in report image
|
||||
// for photo in self.photos {
|
||||
// let date = Date(timeIntervalSince1970: TimeInterval(photo.date/1000))
|
||||
// var name = "<Unknown model>"
|
||||
// if let brand = photo.brand, let model = photo.model {
|
||||
// name = "\(brand) \(model)"
|
||||
// }
|
||||
//
|
||||
// if let url = URL(string: photo.url) {
|
||||
// if let image = ImageCache.default.retrieveImageInDiskCache(forKey: url.cacheKey) {
|
||||
// let imgHeight = image.size.height*w/image.size.width
|
||||
// let rect = CGRect(x: 0, y: y, width: w, height: imgHeight)
|
||||
// image.draw(in: rect)
|
||||
// y += imgHeight
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// self.drawCell(y: y, width: w, height: cellHeight, title: name, value: formatter.string(from: date), lineMargin: 0, context: ctx)
|
||||
// y += cellHeight
|
||||
//
|
||||
// y += 16
|
||||
// }
|
||||
|
||||
realHeight = y
|
||||
}
|
||||
|
||||
return image.cutHeight(to: realHeight)
|
||||
}
|
||||
|
||||
func reportText() -> String {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .long
|
||||
formatter.timeStyle = .none
|
||||
|
||||
var text = (self.brand?.name?.original ?? "<unknown model>") + "\n"
|
||||
text += "Year: \(self.year)\n"
|
||||
if let color = self.color { text += "Color: \(color)\n" }
|
||||
if let category = self.category { text += "Category: \(category)\n" }
|
||||
var position = "Unknown"
|
||||
if let rightWheel = self.isRightWheel {
|
||||
position = rightWheel ? "Right" : "Left"
|
||||
}
|
||||
var japanese = "<Unknown>"
|
||||
if let isJapanese = self.isJapanese {
|
||||
japanese = isJapanese ? "Yes" : "No"
|
||||
}
|
||||
text += "Steering wheel position: \(position)\n"
|
||||
text += "Japanese: \(japanese)\n"
|
||||
text += "Plate number: \(self.getNumber())\n"
|
||||
if let vin = self.vin1 { text += "VIN: \(vin)\n" }
|
||||
if let sts = self.sts { text += "STS: \(sts)\n" }
|
||||
if let pts = self.pts { text += "PTS: \(pts)\n" }
|
||||
if let engineNumber = self.engine?.number { text += "Engine number: \(engineNumber)\n" }
|
||||
if let fuel = self.engine?.fuelType { text += "Fuel type: \(fuel)\n" }
|
||||
if let volume = self.engine?.volume { text += "Volume (cm³): \(volume)\n" }
|
||||
if let powerHp = self.engine?.powerHp { text += "Power (HP): \(powerHp)\n" }
|
||||
if let powerHp = self.engine?.powerHp { text += "Power (HP): \(powerHp)\n" }
|
||||
|
||||
if self.ownershipPeriods.count > 0 {
|
||||
text += "\n"
|
||||
text += "Ownership periods: \(self.ownershipPeriods.count)\n"
|
||||
text += "\n"
|
||||
for period in self.ownershipPeriods {
|
||||
text += "Owner type: \(period.ownerType)\n"
|
||||
let fromDate = Date(timeIntervalSince1970: TimeInterval(period.from/1000))
|
||||
text += "From: \(formatter.string(from: fromDate))\n"
|
||||
let toDate = Date(timeIntervalSince1970: TimeInterval(period.to/1000))
|
||||
let toString = period.to == 0 ? "now" : formatter.string(from: toDate)
|
||||
text += "To: \(toString)\n"
|
||||
text += "Last operation: \(period.lastOperation)\n"
|
||||
text += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
if !self.events.isEmpty {
|
||||
text += "\n"
|
||||
text += "Locations\n"
|
||||
text += "\n"
|
||||
for event in self.events {
|
||||
let date = Date(timeIntervalSince1970: event.date)
|
||||
text += "Date: \(formatter.string(from: date))\n"
|
||||
|
||||
if let address = event.address {
|
||||
text += "Address: \(address)\n"
|
||||
}
|
||||
|
||||
let location = String(format: "%.05f, %.05f", event.latitude, event.longitude)
|
||||
text += "Location: \(location)\n"
|
||||
text += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
}
|
||||
@ -3,10 +3,10 @@ import os.log
|
||||
import AVFoundation
|
||||
import PKHUD
|
||||
import AutoCatCore
|
||||
import SwiftLocation
|
||||
import CoreLocation
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
@Service var settingsService: SettingsServiceProtocol
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
@ -14,7 +14,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
|
||||
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
|
||||
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
|
||||
guard let windowScene = (scene as? UIWindowScene) else { return }
|
||||
guard let ad = UIApplication.shared.delegate as? AppDelegate else { return }
|
||||
|
||||
if let activity = connectionOptions.userActivities.first {
|
||||
@ -31,9 +30,43 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
Task {
|
||||
try? await registerServices()
|
||||
setupRootController(scene: scene)
|
||||
}
|
||||
}
|
||||
|
||||
func registerServices() async throws {
|
||||
|
||||
let container = ServiceContainer.shared
|
||||
|
||||
let settingsService = SettingsService(defaults: .standard)
|
||||
|
||||
container.register(SettingsServiceProtocol.self, instance: settingsService)
|
||||
container.register(ApiServiceProtocol.self, instance: ApiService())
|
||||
|
||||
let locationService = LocationService(
|
||||
geocoder: CLGeocoder(),
|
||||
locationManager: Location(),
|
||||
settingsService: settingsService
|
||||
)
|
||||
|
||||
container.register(LocationServiceProtocol.self, instance: locationService)
|
||||
|
||||
container.register(StorageServiceProtocol.self,
|
||||
instance: try await StorageService(settingsService: settingsService))
|
||||
}
|
||||
|
||||
func setupRootController(scene: UIScene) {
|
||||
guard let windowScene = (scene as? UIWindowScene) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.window = UIWindow(windowScene: windowScene)
|
||||
let storyboard = UIStoryboard(name: "Main", bundle: nil)
|
||||
|
||||
let settingsService = ServiceContainer.shared.resolve(SettingsServiceProtocol.self)
|
||||
|
||||
if settingsService.user.token.isEmpty {
|
||||
self.window?.rootViewController = storyboard.instantiateViewController(identifier: "AuthController")
|
||||
} else {
|
||||
|
||||
34
AutoCat/Screens/HistoryScreen/HistoryCoordinator.swift
Normal file
34
AutoCat/Screens/HistoryScreen/HistoryCoordinator.swift
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// HistoryCoordinator.swift
|
||||
// AutoCat
|
||||
//
|
||||
// Created by Selim Mustafaev on 15.01.2025.
|
||||
// Copyright © 2025 Selim Mustafaev. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import AutoCatCore
|
||||
|
||||
@MainActor
|
||||
class HistoryCoordinator {
|
||||
|
||||
var navController: UINavigationController?
|
||||
|
||||
func start() -> UIViewController {
|
||||
|
||||
let resolver = ServiceContainer.shared
|
||||
let viewModel = HistoryViewModel(
|
||||
apiService: resolver.resolve(ApiServiceProtocol.self),
|
||||
storageService: resolver.resolve(StorageServiceProtocol.self)
|
||||
)
|
||||
|
||||
let view = HistoryScreen(viewModel: viewModel)
|
||||
let controller = UIHostingController(rootView: view)
|
||||
|
||||
let navController = UINavigationController(rootViewController: controller)
|
||||
self.navController = navController
|
||||
|
||||
return navController
|
||||
}
|
||||
}
|
||||
28
AutoCat/Screens/HistoryScreen/HistoryScreen.swift
Normal file
28
AutoCat/Screens/HistoryScreen/HistoryScreen.swift
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// HistoryScreen.swift
|
||||
// AutoCat
|
||||
//
|
||||
// Created by Selim Mustafaev on 15.01.2025.
|
||||
// Copyright © 2025 Selim Mustafaev. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import AutoCatCore
|
||||
|
||||
struct HistoryScreen: View {
|
||||
|
||||
@State var viewModel: HistoryViewModel
|
||||
|
||||
var body: some View {
|
||||
List(viewModel.vehicles) { vehicle in
|
||||
LicensePlateView(number: PlateNumber(vehicle.getNumber()))
|
||||
.frame(width: 200)
|
||||
}
|
||||
.listStyle(.plain)
|
||||
.navigationTitle(String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""), viewModel.vehicles.count))
|
||||
}
|
||||
}
|
||||
|
||||
//#Preview {
|
||||
// HistoryScreen(viewModel: .init())
|
||||
//}
|
||||
33
AutoCat/Screens/HistoryScreen/HistoryViewModel.swift
Normal file
33
AutoCat/Screens/HistoryScreen/HistoryViewModel.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// HistoryViewModel.swift
|
||||
// AutoCat
|
||||
//
|
||||
// Created by Selim Mustafaev on 15.01.2025.
|
||||
// Copyright © 2025 Selim Mustafaev. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import AutoCatCore
|
||||
|
||||
@MainActor
|
||||
@Observable
|
||||
final class HistoryViewModel {
|
||||
|
||||
let apiService: ApiServiceProtocol
|
||||
let storageService: StorageServiceProtocol
|
||||
|
||||
var vehicles: [VehicleDto] = []
|
||||
|
||||
init(apiService: ApiServiceProtocol, storageService: StorageServiceProtocol) {
|
||||
|
||||
self.apiService = apiService
|
||||
self.storageService = storageService
|
||||
|
||||
Task { await loadVehicles() }
|
||||
}
|
||||
|
||||
func loadVehicles() async {
|
||||
|
||||
vehicles = await storageService.loadVehicles()
|
||||
}
|
||||
}
|
||||
73
AutoCat/SwiftUI/LicensePlateView.swift
Normal file
73
AutoCat/SwiftUI/LicensePlateView.swift
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// LicensePlateView.swift
|
||||
// AutoCat
|
||||
//
|
||||
// Created by Selim Mustafaev on 15.01.2025.
|
||||
// Copyright © 2025 Selim Mustafaev. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import AutoCatCore
|
||||
|
||||
struct LicensePlateView: View {
|
||||
|
||||
private static let aspectRatio: CGFloat = 520.0/112.0
|
||||
private static let fontHeightCoeff: CGFloat = 58.0/76.0
|
||||
private static let borderMultiplier = 0.01
|
||||
private static let numberPartMultiplier = (1 - 3*LicensePlateView.borderMultiplier)*0.73
|
||||
private static let reguinPartMultiplier = (1 - 3*LicensePlateView.borderMultiplier)*0.27
|
||||
private static let outerCornerMultiplier = 0.03
|
||||
private static let innerCornerMultiplier = outerCornerMultiplier - borderMultiplier
|
||||
|
||||
let number: PlateNumber
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: geometry.size.width*LicensePlateView.outerCornerMultiplier)
|
||||
.fill(Color("PlateForeground"))
|
||||
HStack(spacing: 0) {
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: geometry.size.width*LicensePlateView.innerCornerMultiplier)
|
||||
.fill(Color("PlateBackground"))
|
||||
Text(number.mainPart())
|
||||
.font(.custom("RoadNumbers", size: geometry.size.height))
|
||||
.kerning(3)
|
||||
.offset(y: geometry.size.width*0.015)
|
||||
}
|
||||
.frame(width: geometry.size.width*LicensePlateView.numberPartMultiplier)
|
||||
.padding(geometry.size.width*LicensePlateView.borderMultiplier)
|
||||
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: geometry.size.width*LicensePlateView.innerCornerMultiplier)
|
||||
.fill(Color("PlateBackground"))
|
||||
VStack(spacing: 0) {
|
||||
Text(number.region())
|
||||
.font(.custom("RoadNumbers", size: geometry.size.height*0.7))
|
||||
HStack(spacing: 2) {
|
||||
Text("RUS")
|
||||
.font(.system(size: geometry.size.height*0.3))
|
||||
VStack(spacing: 0) {
|
||||
Rectangle().fill(.white)
|
||||
Rectangle().fill(.blue)
|
||||
Rectangle().fill(.red)
|
||||
}
|
||||
.aspectRatio(1.5, contentMode: .fit)
|
||||
.frame(width: geometry.size.width*0.08)
|
||||
}
|
||||
}
|
||||
.offset(y: geometry.size.width*0.015)
|
||||
}
|
||||
.frame(width: geometry.size.width*LicensePlateView.reguinPartMultiplier)
|
||||
.padding(.vertical, geometry.size.width*LicensePlateView.borderMultiplier)
|
||||
.padding(.trailing, geometry.size.width*LicensePlateView.borderMultiplier)
|
||||
}
|
||||
}
|
||||
}
|
||||
.aspectRatio(LicensePlateView.aspectRatio, contentMode: .fit)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
LicensePlateView(number: PlateNumber("А123АА761"))
|
||||
}
|
||||
@ -56,4 +56,9 @@ public actor StorageService: StorageServiceProtocol {
|
||||
throw StorageError.vehicleNotFound
|
||||
}
|
||||
}
|
||||
|
||||
public func loadVehicles() async -> [VehicleDto] {
|
||||
|
||||
realm.objects(Vehicle.self).map(\.shallowDto)
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,11 +11,17 @@ import Mockable
|
||||
@Mockable
|
||||
public protocol StorageServiceProtocol: Sendable {
|
||||
|
||||
// Vehicles
|
||||
func loadVehicles() async -> [VehicleDto]
|
||||
func loadVehicle(number: String) async throws -> VehicleDto
|
||||
func updateVehicleIfExists(dto: VehicleDto) async throws
|
||||
|
||||
// Notes
|
||||
func addNote(text: String, to number: String) async throws -> VehicleDto
|
||||
func deleteNote(id: String, for number: String) async throws -> VehicleDto
|
||||
func editNote(id: String, text: String, for number: String) async throws -> VehicleDto
|
||||
func updateVehicleIfExists(dto: VehicleDto) async throws
|
||||
func loadVehicle(number: String) async throws -> VehicleDto
|
||||
|
||||
// Events
|
||||
func add(event: VehicleEventDto, to number: String) async throws -> VehicleDto
|
||||
func remove(event id: String, from number: String) async throws -> VehicleDto
|
||||
func edit(event: VehicleEventDto, for number: String) async throws -> VehicleDto
|
||||
|
||||
Loading…
Reference in New Issue
Block a user