From 18f1a00d82398a5b24f7145abd1cd0e99a9789ca Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Sun, 12 Feb 2023 15:30:42 +0300 Subject: [PATCH] Switching from CoreData to Realm --- AutoCat2.xcodeproj/project.pbxproj | 70 ++++++-- .../xcshareddata/swiftpm/Package.resolved | 18 ++ .../xcschemes/xcschememanagement.plist | 44 ++++- AutoCat2/Cells/VehicleCell.swift | 8 +- AutoCat2/Controllers/HistoryController.swift | 2 +- AutoCat2SUI/AutoCat2SUIApp.swift | 4 - .../Screens/CheckNumber/CheckNumber.swift | 2 +- AutoCat2SUI/Screens/Main/MainView.swift | 102 +---------- AutoCat2SUI/Screens/Sidebar/SidebarView.swift | 74 ++++++++ .../VehicleDetail/VehicleDetailView.swift | 20 ++- .../VehiclesList/VehiclesListView.swift | 36 ++-- AutoCat2SUI/Views/PlaceholderView.swift | 39 +++++ .../Views/PlateView/PlateViewItem.swift | 13 +- .../AutoCat2.xcdatamodeld/.xccurrentversion | 5 +- .../Shared.xcdatamodel/contents | 17 +- AutoCatCore/Extensions/RealmDecoding.swift | 16 ++ AutoCatCore/Models/Filter.swift | 16 +- AutoCatCore/Models/Vehicle.swift | 158 +++++++----------- AutoCatCore/Models/vmodels/DebugInfo.swift | 35 +--- .../Models/vmodels/DebugInfoEntry.swift | 37 +--- AutoCatCore/Models/vmodels/VAd.swift | 46 ++--- AutoCatCore/Models/vmodels/VBrand.swift | 20 +-- AutoCatCore/Models/vmodels/VEngine.swift | 35 +--- AutoCatCore/Models/vmodels/VEvent.swift | 39 +---- AutoCatCore/Models/vmodels/VModel.swift | 22 +-- AutoCatCore/Models/vmodels/VName.swift | 20 +-- AutoCatCore/Models/vmodels/VNote.swift | 32 +--- AutoCatCore/Models/vmodels/VOsago.swift | 50 ++---- .../Models/vmodels/VOwnershipPeriod.swift | 53 ++---- AutoCatCore/Models/vmodels/VPhoto.swift | 32 +--- AutoCatCore/Services/StorageService.swift | 90 ++++------ AutoCatCore/Services/VehicleService.swift | 12 +- 32 files changed, 488 insertions(+), 679 deletions(-) create mode 100644 AutoCat2SUI/Screens/Sidebar/SidebarView.swift create mode 100644 AutoCat2SUI/Views/PlaceholderView.swift create mode 100644 AutoCatCore/Extensions/RealmDecoding.swift diff --git a/AutoCat2.xcodeproj/project.pbxproj b/AutoCat2.xcodeproj/project.pbxproj index 0e18970..9f87424 100644 --- a/AutoCat2.xcodeproj/project.pbxproj +++ b/AutoCat2.xcodeproj/project.pbxproj @@ -49,6 +49,9 @@ 7A36E56027FB5A2F0025AACB /* MockURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A558AAE27FA3CCF001A18EE /* MockURLProtocol.swift */; }; 7A36E56127FB5A330025AACB /* ApiMethodMockProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A558AAF27FA3CCF001A18EE /* ApiMethodMockProtocol.swift */; }; 7A36E56327FB5BEB0025AACB /* TestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A36E56227FB5BEB0025AACB /* TestError.swift */; }; + 7A39D0772998F25600A6F6FC /* PlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A39D0762998F25600A6F6FC /* PlaceholderView.swift */; }; + 7A39D07A2998FF3500A6F6FC /* RealmDecoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A39D0792998FF3500A6F6FC /* RealmDecoding.swift */; }; + 7A39D07D299904B700A6F6FC /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A39D07C299904B700A6F6FC /* SidebarView.swift */; }; 7A48B26727D9442A004D1A4B /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7A48B26627D9442A004D1A4B /* PKHUD */; }; 7A4951B7288D3A6100C644B6 /* AutoCat2SUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4951B6288D3A6100C644B6 /* AutoCat2SUIApp.swift */; }; 7A4951B9288D3A6100C644B6 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4951B8288D3A6100C644B6 /* RootView.swift */; }; @@ -87,9 +90,10 @@ 7A49F51027D406CB00AEAAE0 /* MainSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A49F50927D406CB00AEAAE0 /* MainSettings.swift */; }; 7A49F51127D406CB00AEAAE0 /* PlateNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A49F50A27D406CB00AEAAE0 /* PlateNumber.swift */; }; 7A49F51227D406CB00AEAAE0 /* VName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A49F50B27D406CB00AEAAE0 /* VName.swift */; }; - 7A49F51527D40C6100AEAAE0 /* AutoCat2.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 7A49F51327D40C6100AEAAE0 /* AutoCat2.xcdatamodeld */; }; 7A558AB027FA3CCF001A18EE /* SettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A558AA527FA3CCF001A18EE /* SettingsTests.swift */; }; 7A558AB127FA3CCF001A18EE /* ApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A558AA627FA3CCF001A18EE /* ApiTests.swift */; }; + 7A91E8112986DE9C0008A982 /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = 7A91E8102986DE9C0008A982 /* Realm */; }; + 7A91E8132986DE9C0008A982 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A91E8122986DE9C0008A982 /* RealmSwift */; }; 7A9471BD28C52DD80054CB0A /* PlateViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9471BC28C52DD80054CB0A /* PlateViewItem.swift */; }; 7A9F2AC327E71531006492A9 /* ACTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9F2AC227E71531006492A9 /* ACTabBarController.swift */; }; 7A9FD4072857AF590057ECFA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD4062857AF590057ECFA /* AppDelegate.swift */; }; @@ -246,6 +250,9 @@ 7A2B6CD527FCEC8600519F1E /* XCUIApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIApplication.swift; sourceTree = ""; }; 7A36E55B27FB55570025AACB /* Testing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Testing.swift; sourceTree = ""; }; 7A36E56227FB5BEB0025AACB /* TestError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestError.swift; sourceTree = ""; }; + 7A39D0762998F25600A6F6FC /* PlaceholderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderView.swift; sourceTree = ""; }; + 7A39D0792998FF3500A6F6FC /* RealmDecoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealmDecoding.swift; sourceTree = ""; }; + 7A39D07C299904B700A6F6FC /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = ""; }; 7A4951B4288D3A6100C644B6 /* AutoCat2SUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoCat2SUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7A4951B6288D3A6100C644B6 /* AutoCat2SUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCat2SUIApp.swift; sourceTree = ""; }; 7A4951B8288D3A6100C644B6 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; }; @@ -286,7 +293,6 @@ 7A49F50927D406CB00AEAAE0 /* MainSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainSettings.swift; sourceTree = ""; }; 7A49F50A27D406CB00AEAAE0 /* PlateNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlateNumber.swift; sourceTree = ""; }; 7A49F50B27D406CB00AEAAE0 /* VName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VName.swift; sourceTree = ""; }; - 7A49F51427D40C6100AEAAE0 /* Shared.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Shared.xcdatamodel; sourceTree = ""; }; 7A558AA527FA3CCF001A18EE /* SettingsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTests.swift; sourceTree = ""; }; 7A558AA627FA3CCF001A18EE /* ApiTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiTests.swift; sourceTree = ""; }; 7A558AA927FA3CCF001A18EE /* LoginMethodMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginMethodMock.swift; sourceTree = ""; }; @@ -367,6 +373,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7A91E8132986DE9C0008A982 /* RealmSwift in Frameworks */, + 7A91E8112986DE9C0008A982 /* Realm in Frameworks */, 7A1D80E627F20FCB007BD64F /* DifferenceKit in Frameworks */, 7AE32D6E27F06D2D004EF6E0 /* SwiftDate in Frameworks */, ); @@ -523,6 +531,22 @@ path = Testing; sourceTree = ""; }; + 7A39D0782998FF1800A6F6FC /* Extensions */ = { + isa = PBXGroup; + children = ( + 7A39D0792998FF3500A6F6FC /* RealmDecoding.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 7A39D07B2999049F00A6F6FC /* Sidebar */ = { + isa = PBXGroup; + children = ( + 7A39D07C299904B700A6F6FC /* SidebarView.swift */, + ); + path = Sidebar; + sourceTree = ""; + }; 7A4951B5288D3A6100C644B6 /* AutoCat2SUI */ = { isa = PBXGroup; children = ( @@ -550,6 +574,7 @@ 7A4951C3288D3AF000C644B6 /* Screens */ = { isa = PBXGroup; children = ( + 7A39D07B2999049F00A6F6FC /* Sidebar */, 7AE9F20228CDFCAB00ABF6DF /* VehicleDetail */, 7A163BEF28BBE9DA0005A0A4 /* VehiclesList */, 7AF1D0D628BB5768004E19F7 /* CheckNumber */, @@ -582,6 +607,7 @@ 7A054FD728C4BB700002C386 /* PlateView */, 7A4951B8288D3A6100C644B6 /* RootView.swift */, 7A4951D0288D5C4300C644B6 /* ACProgressView.swift */, + 7A39D0762998F25600A6F6FC /* PlaceholderView.swift */, ); path = Views; sourceTree = ""; @@ -663,9 +689,9 @@ 7A49F4D827D4064500AEAAE0 /* AutoCatCore */ = { isa = PBXGroup; children = ( + 7A39D0782998FF1800A6F6FC /* Extensions */, 7A36E55A27FB54610025AACB /* Testing */, 7AE32D6F27F06D87004EF6E0 /* DataSource */, - 7A49F51327D40C6100AEAAE0 /* AutoCat2.xcdatamodeld */, 7A49F50427D406CB00AEAAE0 /* Models */, 7A49F4FF27D406C300AEAAE0 /* Services */, 7A49F4FC27D406BA00AEAAE0 /* ThirdParty */, @@ -973,6 +999,8 @@ packageProductDependencies = ( 7AE32D6D27F06D2D004EF6E0 /* SwiftDate */, 7A1D80E527F20FCB007BD64F /* DifferenceKit */, + 7A91E8102986DE9C0008A982 /* Realm */, + 7A91E8122986DE9C0008A982 /* RealmSwift */, ); productName = AutoCatCore; productReference = 7A49F4D727D4064500AEAAE0 /* AutoCatCore.framework */; @@ -1070,6 +1098,7 @@ 7AE32D6C27F06D2D004EF6E0 /* XCRemoteSwiftPackageReference "SwiftDate" */, 7A1D80DE27F1F275007BD64F /* XCRemoteSwiftPackageReference "DifferenceKit" */, 7A1D80E427F20FCB007BD64F /* XCRemoteSwiftPackageReference "DifferenceKit" */, + 7A91E80F2986DE9C0008A982 /* XCRemoteSwiftPackageReference "realm-swift" */, ); productRefGroup = 7A49F4A027D4061900AEAAE0 /* Products */; projectDirPath = ""; @@ -1157,6 +1186,7 @@ buildActionMask = 2147483647; files = ( 7A4951D3288D5E2800C644B6 /* AuthVM.swift in Sources */, + 7A39D07D299904B700A6F6FC /* SidebarView.swift in Sources */, 7A054FDA28C4C24B0002C386 /* CenterTextLayer.swift in Sources */, 7A163BF128BBE9ED0005A0A4 /* VehiclesListView.swift in Sources */, 7A054FD928C4BE560002C386 /* PlateView.swift in Sources */, @@ -1164,6 +1194,7 @@ 7A4951C7288D3BDD00C644B6 /* MainView.swift in Sources */, 7AE9F20428CDFCC600ABF6DF /* VehicleDetailView.swift in Sources */, 7AF1D0D828BB577E004E19F7 /* CheckNumber.swift in Sources */, + 7A39D0772998F25600A6F6FC /* PlaceholderView.swift in Sources */, 7A4951B7288D3A6100C644B6 /* AutoCat2SUIApp.swift in Sources */, 7A9471BD28C52DD80054CB0A /* PlateViewItem.swift in Sources */, 7AF1D0DA28BB5BF5004E19F7 /* View.swift in Sources */, @@ -1253,9 +1284,9 @@ 7A49F50F27D406CB00AEAAE0 /* Response.swift in Sources */, 929EDE8127F8A75E00E55F65 /* VPhoto.swift in Sources */, 7A49F4FB27D406B200AEAAE0 /* Api.swift in Sources */, - 7A49F51527D40C6100AEAAE0 /* AutoCat2.xcdatamodeld in Sources */, 929EDE7F27F89C3000E55F65 /* VEngine.swift in Sources */, 929EDE8727F8E11E00E55F65 /* VOsago.swift in Sources */, + 7A39D07A2998FF3500A6F6FC /* RealmDecoding.swift in Sources */, 7A2B6CD427FCE93C00519F1E /* TestSettings.swift in Sources */, 7A49F50E27D406CB00AEAAE0 /* User.swift in Sources */, 7A36E56127FB5A330025AACB /* ApiMethodMockProtocol.swift in Sources */, @@ -1974,6 +2005,14 @@ minimumVersion = 5.0.0; }; }; + 7A91E80F2986DE9C0008A982 /* XCRemoteSwiftPackageReference "realm-swift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/realm/realm-swift.git"; + requirement = { + branch = master; + kind = branch; + }; + }; 7AE32D6C27F06D2D004EF6E0 /* XCRemoteSwiftPackageReference "SwiftDate" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/malcommac/SwiftDate"; @@ -2005,6 +2044,16 @@ package = 7A48B26527D9442A004D1A4B /* XCRemoteSwiftPackageReference "PKHUD" */; productName = PKHUD; }; + 7A91E8102986DE9C0008A982 /* Realm */ = { + isa = XCSwiftPackageProductDependency; + package = 7A91E80F2986DE9C0008A982 /* XCRemoteSwiftPackageReference "realm-swift" */; + productName = Realm; + }; + 7A91E8122986DE9C0008A982 /* RealmSwift */ = { + isa = XCSwiftPackageProductDependency; + package = 7A91E80F2986DE9C0008A982 /* XCRemoteSwiftPackageReference "realm-swift" */; + productName = RealmSwift; + }; 7A9FD4192857AF8D0057ECFA /* DifferenceKit */ = { isa = XCSwiftPackageProductDependency; package = 7A1D80DE27F1F275007BD64F /* XCRemoteSwiftPackageReference "DifferenceKit" */; @@ -2016,19 +2065,6 @@ productName = SwiftDate; }; /* End XCSwiftPackageProductDependency section */ - -/* Begin XCVersionGroup section */ - 7A49F51327D40C6100AEAAE0 /* AutoCat2.xcdatamodeld */ = { - isa = XCVersionGroup; - children = ( - 7A49F51427D40C6100AEAAE0 /* Shared.xcdatamodel */, - ); - currentVersion = 7A49F51427D40C6100AEAAE0 /* Shared.xcdatamodel */; - path = AutoCat2.xcdatamodeld; - sourceTree = ""; - versionGroupType = wrapper.xcdatamodel; - }; -/* End XCVersionGroup section */ }; rootObject = 7A49F49727D4061900AEAAE0 /* Project object */; } diff --git a/AutoCat2.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/AutoCat2.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6a81f52..792e46f 100644 --- a/AutoCat2.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/AutoCat2.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,6 +18,24 @@ "version" : "5.4.0" } }, + { + "identity" : "realm-core", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/realm-core.git", + "state" : { + "revision" : "b77443ca7fa25407869ca537bf3ae912b1427bff", + "version" : "12.13.0" + } + }, + { + "identity" : "realm-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/realm-swift.git", + "state" : { + "branch" : "master", + "revision" : "f5aaf456ea725ac2f352b0b3decc78a7094adbd8" + } + }, { "identity" : "swiftdate", "kind" : "remoteSourceControl", diff --git a/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist b/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist index 27a99e0..5e56cdd 100644 --- a/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist @@ -12,17 +12,17 @@ AutoCat2.xcscheme_^#shared#^_ orderHint - 0 + 2 AutoCat2Mac.xcscheme_^#shared#^_ orderHint - 2 + 3 AutoCat2SUI.xcscheme_^#shared#^_ orderHint - 1 + 0 AutoCat2UITests.testExample.xcscheme @@ -41,14 +41,14 @@ isShown orderHint - 3 + 8 DifferenceKit (Playground) 2.xcscheme isShown orderHint - 4 + 9 DifferenceKit (Playground) 3.xcscheme @@ -76,21 +76,42 @@ isShown orderHint - 2 + 7 + + GettingStarted (Playground) 1.xcscheme + + isShown + + orderHint + 10 + + GettingStarted (Playground) 2.xcscheme + + isShown + + orderHint + 11 + + GettingStarted (Playground).xcscheme + + isShown + + orderHint + 3 SwiftDate (Playground) 1.xcscheme isShown orderHint - 6 + 5 SwiftDate (Playground) 2.xcscheme isShown orderHint - 7 + 6 SwiftDate (Playground) 3.xcscheme @@ -118,11 +139,16 @@ isShown orderHint - 5 + 4 SuppressBuildableAutocreation + 7A4951B3288D3A6100C644B6 + + primary + + 7A49F4D627D4064500AEAAE0 primary diff --git a/AutoCat2/Cells/VehicleCell.swift b/AutoCat2/Cells/VehicleCell.swift index cd13ebd..c41f6c2 100644 --- a/AutoCat2/Cells/VehicleCell.swift +++ b/AutoCat2/Cells/VehicleCell.swift @@ -86,12 +86,8 @@ class VehicleCell: UITableViewCell { extension VehicleCell: ConfigurableCell { - func configure(with vehicle: CDVehicle) { - guard let number = vehicle.number else { - return - } - - plateView.number = PlateNumber(number) + func configure(with vehicle: Vehicle) { + plateView.number = PlateNumber(vehicle.number) nameLabel.text = vehicle.brand?.name?.original ?? "" if vehicle.unrecognized { diff --git a/AutoCat2/Controllers/HistoryController.swift b/AutoCat2/Controllers/HistoryController.swift index 17a3b46..100b349 100644 --- a/AutoCat2/Controllers/HistoryController.swift +++ b/AutoCat2/Controllers/HistoryController.swift @@ -18,7 +18,7 @@ class HistoryController: UIViewController, UITableViewDelegate { return table }() - private var dataSource: CoreDataSource? + private var dataSource: CoreDataSource? override func viewDidLoad() { super.viewDidLoad() diff --git a/AutoCat2SUI/AutoCat2SUIApp.swift b/AutoCat2SUI/AutoCat2SUIApp.swift index e3348eb..c2da455 100644 --- a/AutoCat2SUI/AutoCat2SUIApp.swift +++ b/AutoCat2SUI/AutoCat2SUIApp.swift @@ -14,16 +14,12 @@ struct AutoCat2SUIApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate - let storageService = StorageService.sharedNotWait - var body: some Scene { WindowGroup { if Testing.isUITesting { RootView(settings: getTestSettings()) - .environment(\.managedObjectContext, storageService.context) } else { RootView(settings: getSettings()) - .environment(\.managedObjectContext, storageService.context) } } } diff --git a/AutoCat2SUI/Screens/CheckNumber/CheckNumber.swift b/AutoCat2SUI/Screens/CheckNumber/CheckNumber.swift index 68dd889..cde90f5 100644 --- a/AutoCat2SUI/Screens/CheckNumber/CheckNumber.swift +++ b/AutoCat2SUI/Screens/CheckNumber/CheckNumber.swift @@ -29,7 +29,7 @@ struct CheckNumber: View { } .disabled(showProgress) Button("Check") { - Task.init { + Task { @MainActor in showProgress = true do { try await VehicleService.shared.check(plateNumber: plateNumber.uppercased(), force: false) diff --git a/AutoCat2SUI/Screens/Main/MainView.swift b/AutoCat2SUI/Screens/Main/MainView.swift index c27864a..abd7ea5 100644 --- a/AutoCat2SUI/Screens/Main/MainView.swift +++ b/AutoCat2SUI/Screens/Main/MainView.swift @@ -7,125 +7,33 @@ import SwiftUI import AutoCatCore - -struct SidebarSection: Identifiable { - - let name: String - let filters: [Filter] - let id = UUID() - - func contains(filter id: UUID) -> Bool { - filters.contains { $0.id == id } - } -} +import RealmSwift struct MainView: View { - @FetchRequest(entity: CDVehicle.entity(), sortDescriptors: []) var vehicles: FetchedResults - - @State private var selectedFilterId: UUID? - @State var selectedVehicle: CDVehicle? - @State private var checkSheetPresented = false @State private var searchText = "" - @State var columnVisibility = NavigationSplitViewVisibility.all - - private let sections: [SidebarSection] = [ - SidebarSection(name: "History", filters: [ - .allLocal, - .unrecognized, - .outdated - ]), - SidebarSection(name: "Remote", filters: [ - .allRemote - ]) - ] - - var selectedFilter: Filter? { - guard let filterId = selectedFilterId else { - return nil - } - - return sections.first(where: { $0.contains(filter: filterId) })? - .filters.first(where: { $0.id == filterId }) - } + @State var selectedFilter: Filter? + @State var selectedVehicle: Vehicle? var body: some View { NavigationSplitView(columnVisibility: $columnVisibility) { - List(selection: $selectedFilterId) { - ForEach(sections) { section in - Section(section.name) { - ForEach(section.filters) { filter in - Label(filter.name, systemImage: filter.iconName) - .badge(vehicles.filter(filter.match).count) - } - } - } - } - .navigationSplitViewColumnWidth(180) - .toolbar { - ToolbarItemGroup(placement: .primaryAction) { - Spacer() - Button { - checkSheetPresented = true - } label: { - Image(systemName: "plus") - } - .sheet(isPresented: $checkSheetPresented) { - CheckNumber() - } - - } - } + SidebarView(selectedFilter: $selectedFilter) } content: { if let filter = selectedFilter { - let filtered = vehicles.filter(filter.match) - if filtered.isEmpty { - VStack { - Image(systemName: filter.iconName) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 64) - .foregroundColor(.secondary) - - Text("Nothing here") - .font(.system(size: 18)) - .foregroundColor(.secondary) - } - } else { - VehiclesListView(vehicles: filtered, selection: $selectedVehicle) - .toolbar { - ToolbarItem { - Button(action: {}) { - Image(systemName: "line.3.horizontal.decrease.circle") - } - } - } - .navigationTitle(filter.name) - .navigationSubtitle("\(filtered.count) vehicles") - } + VehiclesListView(filter: filter, selection: $selectedVehicle) } else { EmptyView() } } detail: { if let vehicle = selectedVehicle { VehicleDetailView(vehicle: vehicle) - .toolbar { - ToolbarItem(placement: .automatic) { - Button(action: {}) { - Image(systemName: "square.and.arrow.up") - } - } - } - .navigationTitle(vehicle.brand?.name?.original ?? "") - .navigationSubtitle("\(vehicle.year)") .searchable(text: $searchText, placement: .toolbar) } else { EmptyView() } } .navigationSplitViewStyle(.balanced) - } } diff --git a/AutoCat2SUI/Screens/Sidebar/SidebarView.swift b/AutoCat2SUI/Screens/Sidebar/SidebarView.swift new file mode 100644 index 0000000..709b016 --- /dev/null +++ b/AutoCat2SUI/Screens/Sidebar/SidebarView.swift @@ -0,0 +1,74 @@ +// +// SidebarView.swift +// AutoCat2SUI +// +// Created by Selim Mustafaev on 12.02.2023. +// + +import SwiftUI +import AutoCatCore +import RealmSwift + +struct SidebarSection: Identifiable { + + let name: String + let filters: [Filter] + let id = UUID() + + func contains(filter id: UUID) -> Bool { + filters.contains { $0.id == id } + } +} + +struct SidebarView: View { + + @ObservedResults(Vehicle.self) var vehicles + + @Binding var selectedFilter: Filter? + @State private var checkSheetPresented = false + + private let sections: [SidebarSection] = [ + SidebarSection(name: "History", filters: [ + .allLocal, + .unrecognized, + .outdated + ]), + SidebarSection(name: "Remote", filters: [ + .allRemote + ]) + ] + + var body: some View { + List(selection: $selectedFilter) { + ForEach(sections) { section in + Section(section.name) { + ForEach(section.filters, id: \.self) { filter in + Label(filter.name, systemImage: filter.iconName) + .badge(vehicles.filter(filter.match).count) + } + } + } + } + .navigationSplitViewColumnWidth(180) + .toolbar { + ToolbarItemGroup(placement: .primaryAction) { + Spacer() + Button { + checkSheetPresented = true + } label: { + Image(systemName: "plus") + } + .sheet(isPresented: $checkSheetPresented) { + CheckNumber() + } + + } + } + } +} + +struct SidebarView_Previews: PreviewProvider { + static var previews: some View { + SidebarView(selectedFilter: .constant(nil)) + } +} diff --git a/AutoCat2SUI/Screens/VehicleDetail/VehicleDetailView.swift b/AutoCat2SUI/Screens/VehicleDetail/VehicleDetailView.swift index 4a15417..ec6212c 100644 --- a/AutoCat2SUI/Screens/VehicleDetail/VehicleDetailView.swift +++ b/AutoCat2SUI/Screens/VehicleDetail/VehicleDetailView.swift @@ -26,16 +26,16 @@ struct ReportTextItem: View { struct VehicleDetailView: View { - let vehicle: CDVehicle + let vehicle: Vehicle var body: some View { Form { Section(header: Text("General")) { - ReportTextItem(name: "Year", value: String(vehicle.year)) + ReportTextItem(name: "Year", value: String(vehicle.year ?? 0)) ReportTextItem(name: "Color", value: vehicle.color) ReportTextItem(name: "Category", value: vehicle.category) - ReportTextItem(name: "Steering wheel position", value: vehicle.isRightWheel ? "Right": "Left") - ReportTextItem(name: "Japanese", value: vehicle.isJapanese ? "Yes" : "No") + ReportTextItem(name: "Steering wheel position", value: vehicle.isRightWheel == true ? "Right": "Left") + ReportTextItem(name: "Japanese", value: vehicle.isJapanese == true ? "Yes" : "No") } Section(header: Text("Identifiers")) { ReportTextItem(name: "Plate number", value: vehicle.number) @@ -52,6 +52,15 @@ struct VehicleDetailView: View { } } .formStyle(.grouped) + .toolbar { + ToolbarItem(placement: .automatic) { + Button(action: {}) { + Image(systemName: "square.and.arrow.up") + } + } + } + .navigationTitle(vehicle.brand?.name?.original ?? "") + .navigationSubtitle("\(vehicle.year ?? 0)") } } @@ -64,7 +73,6 @@ struct VehicleDetailView_Previews: PreviewProvider { addedDate: Date().timeIntervalSince1970, updatedDate: Date().timeIntervalSince1970) - return VehicleDetailView(vehicle: CDVehicle(vehicle: test1, - context: NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType))) + return VehicleDetailView(vehicle: test1) } } diff --git a/AutoCat2SUI/Screens/VehiclesList/VehiclesListView.swift b/AutoCat2SUI/Screens/VehiclesList/VehiclesListView.swift index 2028c99..6c779df 100644 --- a/AutoCat2SUI/Screens/VehiclesList/VehiclesListView.swift +++ b/AutoCat2SUI/Screens/VehiclesList/VehiclesListView.swift @@ -7,27 +7,43 @@ import SwiftUI import AutoCatCore +import RealmSwift struct VehiclesListView: View { - var vehicles: [CDVehicle] - @Binding var selection: CDVehicle? + var filter: Filter + @Binding var selection: Vehicle? + + @ObservedResults(Vehicle.self) var vehicles var body: some View { - List(selection: $selection) { - ForEach(vehicles, id: \.self) { vehicle in - PlateViewItem(vehicle: vehicle) + let filtered: [Vehicle] = vehicles.filter(filter.match) + if filtered.isEmpty { + PlaceholderView(imageName: filter.iconName) + } else { + List(selection: $selection) { + ForEach(filtered, id: \.self) { vehicle in + PlateViewItem(vehicle: vehicle) + } } + .toolbar { + ToolbarItem { + Button(action: {}) { + Image(systemName: "line.3.horizontal.decrease.circle") + } + } + } + .navigationTitle(filter.name) + .navigationSubtitle("\(filtered.count) vehicles") } } } struct VehiclesListView_Previews: PreviewProvider { - - @State var selection: CDVehicle? - + + @State var selection: Vehicle? + static var previews: some View { - VehiclesListView(vehicles: [ - ], selection: .constant(nil)) + VehiclesListView(filter: .allLocal, selection: .constant(nil)) } } diff --git a/AutoCat2SUI/Views/PlaceholderView.swift b/AutoCat2SUI/Views/PlaceholderView.swift new file mode 100644 index 0000000..0f266aa --- /dev/null +++ b/AutoCat2SUI/Views/PlaceholderView.swift @@ -0,0 +1,39 @@ +// +// PlaceholderView.swift +// AutoCat2SUI +// +// Created by Selim Mustafaev on 12.02.2023. +// + +import SwiftUI + +struct PlaceholderView: View { + + let imageName: String + let text: String + + var body: some View { + VStack { + Image(systemName: imageName) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 64) + .foregroundColor(.secondary) + + Text(text) + .font(.system(size: 18)) + .foregroundColor(.secondary) + } + } + + init(imageName: String, text: String = "Nothing here") { + self.imageName = imageName + self.text = text + } +} + +struct PlaceholderView_Previews: PreviewProvider { + static var previews: some View { + PlaceholderView(imageName: "eye", text: "Nothing here") + } +} diff --git a/AutoCat2SUI/Views/PlateView/PlateViewItem.swift b/AutoCat2SUI/Views/PlateView/PlateViewItem.swift index 41c581f..d3e5a66 100644 --- a/AutoCat2SUI/Views/PlateView/PlateViewItem.swift +++ b/AutoCat2SUI/Views/PlateView/PlateViewItem.swift @@ -10,21 +10,21 @@ import AutoCatCore struct PlateViewItem: View { - let vehicle: CDVehicle + let vehicle: Vehicle var body: some View { VStack(alignment: .leading, spacing: 4) { Text(vehicle.brand?.name?.original ?? "") HStack { - PlateNumberView(number: PlateNumber(vehicle.number ?? ""), + PlateNumberView(number: PlateNumber(vehicle.number), unrecognized: vehicle.unrecognized, outdated: vehicle.outdated, fontSize: 30) VStack { - if let upDate = vehicle.updatedDate { - - } +// if let upDate = vehicle.updatedDate { +// +// } } } } @@ -41,7 +41,6 @@ struct PlateViewItem_Previews: PreviewProvider { addedDate: Date().timeIntervalSince1970, updatedDate: Date().timeIntervalSince1970) - return PlateViewItem(vehicle: CDVehicle(vehicle: test1, - context: NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType))) + return PlateViewItem(vehicle: test1) } } diff --git a/AutoCatCore/AutoCat2.xcdatamodeld/.xccurrentversion b/AutoCatCore/AutoCat2.xcdatamodeld/.xccurrentversion index 775cb51..0c67376 100644 --- a/AutoCatCore/AutoCat2.xcdatamodeld/.xccurrentversion +++ b/AutoCatCore/AutoCat2.xcdatamodeld/.xccurrentversion @@ -1,8 +1,5 @@ - - _XCCurrentVersionName - Shared.xcdatamodel - + diff --git a/AutoCatCore/AutoCat2.xcdatamodeld/Shared.xcdatamodel/contents b/AutoCatCore/AutoCat2.xcdatamodeld/Shared.xcdatamodel/contents index 17290ec..4c763ed 100644 --- a/AutoCatCore/AutoCat2.xcdatamodeld/Shared.xcdatamodel/contents +++ b/AutoCatCore/AutoCat2.xcdatamodeld/Shared.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -131,19 +131,4 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/AutoCatCore/Extensions/RealmDecoding.swift b/AutoCatCore/Extensions/RealmDecoding.swift new file mode 100644 index 0000000..6ab4acf --- /dev/null +++ b/AutoCatCore/Extensions/RealmDecoding.swift @@ -0,0 +1,16 @@ +// +// RealmDecoding.swift +// AutoCatCore +// +// Created by Selim Mustafaev on 12.02.2023. +// + +import RealmSwift + +extension KeyedDecodingContainer { + + func decode(_ type: Persisted>.Type, forKey key: Key) throws -> Persisted> { + // Use decode if present, falling back to an empty list + try decodeIfPresent(type, forKey: key) ?? Persisted>(wrappedValue: List()) + } +} diff --git a/AutoCatCore/Models/Filter.swift b/AutoCatCore/Models/Filter.swift index 2edd785..e9f0c5e 100644 --- a/AutoCatCore/Models/Filter.swift +++ b/AutoCatCore/Models/Filter.swift @@ -26,7 +26,7 @@ public enum DataSource: CaseIterable, Identifiable { } } -public struct Filter: Hashable, Identifiable { +public final class Filter: Hashable, Identifiable { public let id = UUID() public let name: String @@ -49,9 +49,19 @@ public struct Filter: Hashable, Identifiable { self.outdated = outdated } - public func match(vehicle: CDVehicle) -> Bool { + public func match(vehicle: Vehicle) -> Bool { return unrecognized == vehicle.unrecognized - && outdated == vehicle.outdated + && outdated == vehicle.outdated + } + + public static func == (lhs: Filter, rhs: Filter) -> Bool { + lhs.dataSource == rhs.dataSource + && lhs.unrecognized == rhs.unrecognized + && lhs.outdated == rhs.outdated + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(id) } } diff --git a/AutoCatCore/Models/Vehicle.swift b/AutoCatCore/Models/Vehicle.swift index 0575e5b..255ab97 100644 --- a/AutoCatCore/Models/Vehicle.swift +++ b/AutoCatCore/Models/Vehicle.swift @@ -1,109 +1,46 @@ -import Foundation -import CoreData +import RealmSwift import DifferenceKit -public struct Vehicle: Decodable { +public final class Vehicle: Object, Decodable { - public var number: String - public var currentNumber: String? - public var brand: VBrand? - public var model: VModel? - public var addedDate: TimeInterval - public var updatedDate: TimeInterval - public var color: String? - public var year: Int64? - public var category: String? - public var vin1: String? - public var vin2: String? - public var sts: String? - public var pts: String? - public var isRightWheel: Bool? - public var isJapanese: Bool? - public var addedBy: String? - public var engine: VEngine? - public var photos: [VPhoto]? - public var ownershipPeriods: [VOwnershipPeriod]? - public var events: [VEvent]? - public var osagoContracts: [VOsago]? - public var ads: [VAd]? - public var notes: [VNote]? - public var debugInfo: DebugInfo? + @Persisted(primaryKey: true) public var number: String + @Persisted public var currentNumber: String? + @Persisted public var brand: VBrand? + @Persisted public var model: VModel? + @Persisted public var addedDate: TimeInterval + @Persisted public var updatedDate: TimeInterval + @Persisted public var color: String? + @Persisted public var year: Int64? + @Persisted public var category: String? + @Persisted public var vin1: String? + @Persisted public var vin2: String? + @Persisted public var sts: String? + @Persisted public var pts: String? + @Persisted public var isRightWheel: Bool? + @Persisted public var isJapanese: Bool? + @Persisted public var addedBy: String? + @Persisted public var engine: VEngine? + @Persisted public var photos: List + @Persisted public var ownershipPeriods: List + @Persisted public var events: List + @Persisted public var osagoContracts: List + @Persisted public var ads: List + @Persisted public var notes: List + @Persisted public var debugInfo: DebugInfo? - public init(number: String, brandName: String, addedDate: TimeInterval, updatedDate: TimeInterval) { + public convenience init(number: String, brandName: String, addedDate: TimeInterval, updatedDate: TimeInterval) { + self.init() self.number = number self.currentNumber = number self.addedDate = addedDate self.updatedDate = updatedDate - self.brand = VBrand(name: VName(original: brandName)) - } -} - -extension CDVehicle: Dated { - - public var updatedAt: Date { - Date(timeIntervalSince1970: updatedDate) - } - - public var addedAt: Date { - Date(timeIntervalSince1970: addedDate) - } -} - -extension CDVehicle: Differentiable { - - public var differenceIdentifier: String { number! } - - public func isContentEqual(to source: CDVehicle) -> Bool { - return number == source.number && - addedDate == source.addedDate && - updatedDate == source.updatedDate - } -} - -extension CDVehicle { - - public convenience init(vehicle: Vehicle, context: NSManagedObjectContext) { + let name = VName() + name.original = brandName - self.init(context: context) - self.number = vehicle.number - self.currentNumber = vehicle.currentNumber - self.addedDate = vehicle.addedDate/1000 - self.updatedDate = vehicle.updatedDate/1000 - self.color = vehicle.color - self.brand = CDVBrand(vbrand: vehicle.brand, context: context) - self.model = CDVModel(model: vehicle.model, context: context) - self.year = vehicle.year ?? 0 - self.category = category - self.vin1 = vehicle.vin1 - self.vin2 = vehicle.vin2 - self.sts = vehicle.sts - self.pts = vehicle.pts - self.isRightWheel = vehicle.isRightWheel ?? false - self.isJapanese = vehicle.isJapanese ?? false - self.addedBy = vehicle.addedBy - self.synchronized = true - self.engine = CDVEngine(model: vehicle.engine, context: context) - - let photos = vehicle.photos?.map { CDVPhoto(model: $0, context: context) } ?? [] - self.photos = NSSet(array: photos) - - let ownershipPeriods = vehicle.ownershipPeriods?.map { CDVOwnershipPeriod(model: $0, context: context) } ?? [] - self.ownershipPeriods = NSSet(array: ownershipPeriods) - - let events = vehicle.events?.map { CDVEvent(model: $0, context: context) } ?? [] - self.events = NSSet(array: events) - - let osagoContracts = vehicle.osagoContracts?.map { CDVOsago(model: $0, context: context) } ?? [] - self.osagoContracts = NSSet(array: osagoContracts) - - let ads = vehicle.ads?.map { CDVAd(model: $0, context: context) } ?? [] - self.ads = NSSet(array: ads) - - let notes = vehicle.notes?.map { CDVNote(model: $0, context: context) } ?? [] - self.notes = NSSet(array: notes) - - self.debugInfo = CDDebugInfo(model: vehicle.debugInfo, context: context) + let brand = VBrand() + brand.name = name + self.brand = brand } public var unrecognized: Bool { @@ -117,5 +54,32 @@ extension CDVehicle { return false } } - } + +extension Vehicle: Dated { + + public var updatedAt: Date { + Date(timeIntervalSince1970: updatedDate) + } + + public var addedAt: Date { + Date(timeIntervalSince1970: addedDate) + } +} + +extension Vehicle: Differentiable { + + public var differenceIdentifier: String { number } + + public func isContentEqual(to source: Vehicle) -> Bool { + return number == source.number && + addedDate == source.addedDate && + updatedDate == source.updatedDate + } +} + +extension Vehicle: Identifiable { + + public var id: String { number } +} + diff --git a/AutoCatCore/Models/vmodels/DebugInfo.swift b/AutoCatCore/Models/vmodels/DebugInfo.swift index 2b0ec32..ca84271 100644 --- a/AutoCatCore/Models/vmodels/DebugInfo.swift +++ b/AutoCatCore/Models/vmodels/DebugInfo.swift @@ -1,31 +1,10 @@ -// -// DebugInfo.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 03.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct DebugInfo: Decodable { +public final class DebugInfo: Object, Decodable { - let autocod: DebugInfoEntry? - let vin01vin: DebugInfoEntry? - let vin01base: DebugInfoEntry? - let vin01history: DebugInfoEntry? - let nomerogram: DebugInfoEntry? -} - -extension CDDebugInfo { - - convenience init(model: DebugInfo?, context: NSManagedObjectContext) { - self.init(context: context) - - self.autocod = CDDebugInfoEntry(model: model?.autocod, context: context) - self.vin01vin = CDDebugInfoEntry(model: model?.vin01vin, context: context) - self.vin01base = CDDebugInfoEntry(model: model?.vin01base, context: context) - self.vin01history = CDDebugInfoEntry(model: model?.vin01history, context: context) - self.nomerogram = CDDebugInfoEntry(model: model?.nomerogram, context: context) - } + @Persisted var autocod: DebugInfoEntry? + @Persisted var vin01vin: DebugInfoEntry? + @Persisted var vin01base: DebugInfoEntry? + @Persisted var vin01history: DebugInfoEntry? + @Persisted var nomerogram: DebugInfoEntry? } diff --git a/AutoCatCore/Models/vmodels/DebugInfoEntry.swift b/AutoCatCore/Models/vmodels/DebugInfoEntry.swift index 0d4ca5e..5a7dcf2 100644 --- a/AutoCatCore/Models/vmodels/DebugInfoEntry.swift +++ b/AutoCatCore/Models/vmodels/DebugInfoEntry.swift @@ -1,38 +1,15 @@ -// -// DebugInfoEntry.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 03.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public enum DebugInfoStatus: Int64 { +public enum DebugInfoStatus: Int64, Decodable, PersistableEnum { + case success = 0 case error = 1 case warning = 2 } -public struct DebugInfoEntry: Decodable { +public final class DebugInfoEntry: Object, Decodable { - let fields: Int64 - let error: String? - let status: Int64 -} - -extension CDDebugInfoEntry { - - convenience init(model: DebugInfoEntry?, context: NSManagedObjectContext) { - self.init(context: context) - - self.fields = model?.fields ?? 0 - self.error = model?.error - self.status = model?.status ?? 0 - } - - public var statusEnum: DebugInfoStatus { - get { DebugInfoStatus(rawValue: self.status)! } - set { self.status = newValue.rawValue } - } + @Persisted var fields: Int64 + @Persisted var error: String? + @Persisted var status: DebugInfoStatus? } diff --git a/AutoCatCore/Models/vmodels/VAd.swift b/AutoCatCore/Models/vmodels/VAd.swift index 1b14678..0cc3598 100644 --- a/AutoCatCore/Models/vmodels/VAd.swift +++ b/AutoCatCore/Models/vmodels/VAd.swift @@ -1,39 +1,15 @@ -// -// VAd.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 02.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VAd: Decodable { +public final class VAd: Object, Decodable { - let id: Int64 - let url: String? - let price: String? - let date: Double - let mileage: String? - let region: String? - let city: String? - let adDescription: String? - let photos: [String] + @Persisted var id: Int64 + @Persisted var url: String? + @Persisted var price: String? + @Persisted var date: Double + @Persisted var mileage: String? + @Persisted var region: String? + @Persisted var city: String? + @Persisted var adDescription: String? + @Persisted var photos: List } -extension CDVAd { - - convenience init(model: VAd?, context: NSManagedObjectContext) { - self.init(context: context) - - self.id = model?.id ?? 0 - self.url = model?.url - self.price = model?.price - self.date = model?.date ?? 0 - self.mileage = model?.mileage - self.region = model?.region - self.city = model?.city - self.adDescription = model?.adDescription - self.photos = model?.photos - } -} diff --git a/AutoCatCore/Models/vmodels/VBrand.swift b/AutoCatCore/Models/vmodels/VBrand.swift index b61304b..445371b 100644 --- a/AutoCatCore/Models/vmodels/VBrand.swift +++ b/AutoCatCore/Models/vmodels/VBrand.swift @@ -1,19 +1,7 @@ -import Foundation -import CoreData +import RealmSwift -public struct VBrand: Decodable { - - public var logo: String? - public var name: VName? -} - -extension CDVBrand { - - convenience init(vbrand: VBrand?, context: NSManagedObjectContext) { - - self.init(context: context) - self.logo = vbrand?.logo - self.name = CDVName(vname: vbrand?.name, context: context) - } +public final class VBrand: Object, Decodable { + @Persisted public var logo: String? + @Persisted public var name: VName? } diff --git a/AutoCatCore/Models/vmodels/VEngine.swift b/AutoCatCore/Models/vmodels/VEngine.swift index 126d023..c7bf168 100644 --- a/AutoCatCore/Models/vmodels/VEngine.swift +++ b/AutoCatCore/Models/vmodels/VEngine.swift @@ -1,31 +1,10 @@ -// -// VEngine.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 02.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VEngine: Decodable { +public final class VEngine: Object, Decodable { - let number: String? - let volume: Int64? - let powerHp: Float? - let powerKw: Float? - let fuelType: String? -} - -extension CDVEngine { - - convenience init(model: VEngine?, context: NSManagedObjectContext) { - self.init(context: context) - - self.number = model?.number - self.volume = model?.volume ?? 0 - self.powerHp = model?.powerHp ?? 0 - self.powerKw = model?.powerKw ?? 0 - self.fuelType = model?.fuelType - } + @Persisted public var number: String? + @Persisted public var volume: Int64? + @Persisted public var powerHp: Float? + @Persisted public var powerKw: Float? + @Persisted public var fuelType: String? } diff --git a/AutoCatCore/Models/vmodels/VEvent.swift b/AutoCatCore/Models/vmodels/VEvent.swift index 9f25507..79e2c25 100644 --- a/AutoCatCore/Models/vmodels/VEvent.swift +++ b/AutoCatCore/Models/vmodels/VEvent.swift @@ -1,35 +1,10 @@ -// -// VEvent.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 02.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VEvent: Decodable { +public final class VEvent: Object, Decodable { - let id: String - let date: Double - let latitude: Double - let longitude: Double - let speed: Double - let direction: Double - let address: String? -} - -extension CDVEvent { - - convenience init(model: VEvent?, context: NSManagedObjectContext) { - self.init(context: context) - - self.id = model?.id - self.date = model?.date ?? 0 - self.latitude = model?.latitude ?? 0 - self.longitude = model?.longitude ?? 0 - self.speed = model?.speed ?? 0 - self.direction = model?.direction ?? 0 - self.address = model?.address - } + @Persisted var id: String + @Persisted var date: Double + @Persisted var latitude: Double + @Persisted var longitude: Double + @Persisted var address: String? } diff --git a/AutoCatCore/Models/vmodels/VModel.swift b/AutoCatCore/Models/vmodels/VModel.swift index de61d59..b9875e5 100644 --- a/AutoCatCore/Models/vmodels/VModel.swift +++ b/AutoCatCore/Models/vmodels/VModel.swift @@ -1,22 +1,6 @@ -// -// VModel.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 29.03.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VModel: Decodable { +public final class VModel: Object, Decodable { - let name: VName? -} - -extension CDVModel { - - convenience init(model: VModel?, context: NSManagedObjectContext) { - self.init(context: context) - self.name = CDVName(vname: model?.name, context: context) - } + @Persisted var name: VName? } diff --git a/AutoCatCore/Models/vmodels/VName.swift b/AutoCatCore/Models/vmodels/VName.swift index f9859d9..932788d 100644 --- a/AutoCatCore/Models/vmodels/VName.swift +++ b/AutoCatCore/Models/vmodels/VName.swift @@ -1,19 +1,7 @@ -import Foundation -import CoreData +import RealmSwift -public struct VName: Decodable { - - public var normalized: String? - public var original: String? -} - -extension CDVName { - - convenience init(vname: VName?, context: NSManagedObjectContext) { - - self.init(context: context) - self.normalized = vname?.normalized - self.original = vname?.original - } +public final class VName: Object, Decodable { + @Persisted public var normalized: String? + @Persisted public var original: String? } diff --git a/AutoCatCore/Models/vmodels/VNote.swift b/AutoCatCore/Models/vmodels/VNote.swift index 40d01fa..0a93910 100644 --- a/AutoCatCore/Models/vmodels/VNote.swift +++ b/AutoCatCore/Models/vmodels/VNote.swift @@ -1,29 +1,9 @@ -// -// VNote.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 02.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VNote: Decodable { +public final class VNote: Object, Decodable { - let id: String? - let user: String? - let date: Double - let text: String? -} - -extension CDVNote { - - convenience init(model: VNote?, context: NSManagedObjectContext) { - self.init(context: context) - - self.id = model?.id - self.user = model?.user - self.date = model?.date ?? 0 - self.text = model?.text - } + @Persisted var id: String? + @Persisted var user: String? + @Persisted var date: Double + @Persisted var text: String? } diff --git a/AutoCatCore/Models/vmodels/VOsago.swift b/AutoCatCore/Models/vmodels/VOsago.swift index 20c17e9..c419d64 100644 --- a/AutoCatCore/Models/vmodels/VOsago.swift +++ b/AutoCatCore/Models/vmodels/VOsago.swift @@ -1,41 +1,15 @@ -// -// VOsago.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 02.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VOsago: Decodable { +public final class VOsago: Object, Decodable { - let date: Double - let number: String? - let vin: String? - let plateNumber: String? - let name: String? - let status: String? - let restrictions: String? - let insurant: String? - let owner: String? - let usageRegion: String? -} - -extension CDVOsago { - - convenience init(model: VOsago?, context: NSManagedObjectContext) { - self.init(context: context) - - self.date = model?.date ?? 0 - self.number = model?.number - self.vin = model?.vin - self.plateNumber = model?.plateNumber - self.name = model?.name - self.status = model?.status - self.restrictions = model?.restrictions - self.insurant = model?.insurant - self.owner = model?.owner - self.usageRegion = model?.usageRegion - } + @Persisted var date: Double + @Persisted var number: String? + @Persisted var vin: String? + @Persisted var plateNumber: String? + @Persisted var name: String? + @Persisted var status: String? + @Persisted var restrictions: String? + @Persisted var insurant: String? + @Persisted var owner: String? + @Persisted var usageRegion: String? } diff --git a/AutoCatCore/Models/vmodels/VOwnershipPeriod.swift b/AutoCatCore/Models/vmodels/VOwnershipPeriod.swift index d0788a3..5bb1dfc 100644 --- a/AutoCatCore/Models/vmodels/VOwnershipPeriod.swift +++ b/AutoCatCore/Models/vmodels/VOwnershipPeriod.swift @@ -1,43 +1,16 @@ -// -// VOwnershipPeriod.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 02.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VOwnershipPeriod: Decodable { +public final class VOwnershipPeriod: Object, Decodable { - let lastOperation: String? - let ownerType: String? - let from: Int64? - let to: Int64? - let region: String? - let registrationRegion: String? - let locality: String? - let code: String? - let street: String? - let building: String? - let inn: String? -} - -extension CDVOwnershipPeriod { - - convenience init(model: VOwnershipPeriod?, context: NSManagedObjectContext) { - self.init(context: context) - - self.lastOperation = model?.lastOperation - self.ownerType = model?.ownerType - self.from = model?.from ?? 0 - self.to = model?.to ?? 0 - self.region = model?.region - self.registrationRegion = model?.registrationRegion - self.locality = model?.locality - self.code = model?.locality - self.street = model?.street - self.building = model?.building - self.inn = model?.inn - } + @Persisted var lastOperation: String? + @Persisted var ownerType: String? + @Persisted var from: Int64? + @Persisted var to: Int64? + @Persisted var region: String? + @Persisted var registrationRegion: String? + @Persisted var locality: String? + @Persisted var code: String? + @Persisted var street: String? + @Persisted var building: String? + @Persisted var inn: String? } diff --git a/AutoCatCore/Models/vmodels/VPhoto.swift b/AutoCatCore/Models/vmodels/VPhoto.swift index f79537b..e3abd58 100644 --- a/AutoCatCore/Models/vmodels/VPhoto.swift +++ b/AutoCatCore/Models/vmodels/VPhoto.swift @@ -1,29 +1,9 @@ -// -// VPhoto.swift -// AutoCatCore -// -// Created by Selim Mustafaev on 02.04.2022. -// +import RealmSwift -import Foundation -import CoreData - -public struct VPhoto: Decodable { +public final class VPhoto: Object, Decodable { - let brand: String? - let model: String? - let date: Double - let url: String? -} - -extension CDVPhoto { - - convenience init(model: VPhoto?, context: NSManagedObjectContext) { - self.init(context: context) - - self.brand = model?.brand - self.model = model?.model - self.date = model?.date ?? 0 - self.url = model?.url - } + @Persisted var brand: String? + @Persisted var model: String? + @Persisted var date: Double + @Persisted var url: String? } diff --git a/AutoCatCore/Services/StorageService.swift b/AutoCatCore/Services/StorageService.swift index 7b0f029..1713db5 100644 --- a/AutoCatCore/Services/StorageService.swift +++ b/AutoCatCore/Services/StorageService.swift @@ -1,91 +1,57 @@ import Foundation -import CoreData +import RealmSwift protocol StorageServiceProtocol { - var context: NSManagedObjectContext { get } - func store(vehicle: Vehicle) throws -> CDVehicle + func store(vehicle: Vehicle) throws } public class StorageService: StorageServiceProtocol { + public enum StorageError: String, LocalizedError { + + case openDatabaseError = "Ошибка открытия БД" + + public var errorDescription: String? { + rawValue + } + } + private static var instance: StorageService? - private let container: NSPersistentCloudKitContainer + private let realm: Realm public static var shared: StorageService { - get async throws { + get throws { if let instance = StorageService.instance { return instance } else { - let service = StorageService(inMemory: Testing.isUITesting) - try await service.loadPersistentStores() - StorageService.instance = service - return service - } - } - } - - public static var sharedNotWait: StorageService { - if let instance = StorageService.instance { - return instance - } else { - let service = StorageService(inMemory: Testing.isUITesting) - Task { - try? await service.loadPersistentStores() - } - StorageService.instance = service - return service - } - } - - init(inMemory: Bool = false) { - - let bundle = Bundle(for: Self.self) - let url = bundle.url(forResource: "AutoCat2", withExtension: "momd") - let mom = NSManagedObjectModel(contentsOf: url!) - - container = NSPersistentCloudKitContainer(name: "AutoCat2", managedObjectModel: mom!) - if inMemory { - container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") - } - } - - private func loadPersistentStores() async throws { - try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - container.loadPersistentStores(completionHandler: { (storeDescription, error) in - if let error = error as NSError? { - continuation.resume(throwing: error) + if let service = StorageService(inMemory: Testing.isUITesting) { + StorageService.instance = service + return service } else { - continuation.resume(returning: ()) + throw StorageError.openDatabaseError } - }) + } } } - private func save() throws { - guard context.hasChanges else { - return + init?(inMemory: Bool = false) { + let config = Realm.Configuration(inMemoryIdentifier: inMemory ? "memory" : nil) + + guard let realm = try? Realm(configuration: config) else { + return nil } - do { - try context.save() - } catch { - context.rollback() - throw error - } + self.realm = realm } // MARK: - StorageServiceProtocol - public var context: NSManagedObjectContext { - container.viewContext - } - - public func store(vehicle: Vehicle) throws -> CDVehicle { + public func store(vehicle: Vehicle) throws { - let cdVehicle = CDVehicle(vehicle: vehicle, context: context) - try save() - return cdVehicle + try realm.write { + realm.add(vehicle, update: .all) + } } } diff --git a/AutoCatCore/Services/VehicleService.swift b/AutoCatCore/Services/VehicleService.swift index 9c46535..fe555d6 100644 --- a/AutoCatCore/Services/VehicleService.swift +++ b/AutoCatCore/Services/VehicleService.swift @@ -2,7 +2,7 @@ import Foundation protocol VehicleServiceProtocol { - func check(plateNumber: String, force: Bool) async throws -> CDVehicle + func check(plateNumber: String, force: Bool) async throws -> Vehicle } public class VehicleService: VehicleServiceProtocol { @@ -11,8 +11,8 @@ public class VehicleService: VehicleServiceProtocol { private let storage: StorageServiceProtocol public static var shared: VehicleService { - get async throws { - let storageService = try await StorageService.shared + get throws { + let storageService = try StorageService.shared return VehicleService(api: Api.shared, storage: storageService) } } @@ -25,11 +25,13 @@ public class VehicleService: VehicleServiceProtocol { // MARK: - VehicleServiceProtocol + @MainActor @discardableResult - public func check(plateNumber: String, force: Bool) async throws -> CDVehicle { + public func check(plateNumber: String, force: Bool) async throws -> Vehicle { let vehicle = try await api.check(plateNumber: plateNumber, force: force) - return try storage.store(vehicle: vehicle) + try storage.store(vehicle: vehicle) + return vehicle } }