Adding tests for auth screen.

Removing more old code.
This commit is contained in:
Selim Mustafaev 2025-04-06 16:18:28 +03:00
parent fa80cc5022
commit d94ced5c7e
16 changed files with 361 additions and 322 deletions

View File

@ -12,7 +12,6 @@
7A06E0B02C7065D8005731AC /* SettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0AF2C7065D8005731AC /* SettingsCoordinator.swift */; }; 7A06E0B02C7065D8005731AC /* SettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0AF2C7065D8005731AC /* SettingsCoordinator.swift */; };
7A06E0B32C707E13005731AC /* SettingsServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0B22C707E13005731AC /* SettingsServiceProtocol.swift */; }; 7A06E0B32C707E13005731AC /* SettingsServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0B22C707E13005731AC /* SettingsServiceProtocol.swift */; };
7A06E0B52C707E2B005731AC /* SettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0B42C707E2B005731AC /* SettingsService.swift */; }; 7A06E0B52C707E2B005731AC /* SettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0B42C707E2B005731AC /* SettingsService.swift */; };
7A1022692C55197D00B84627 /* RealmSwift in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 7ADF23052C25B5BF002624FF /* RealmSwift */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
7A10226C2C551EC500B84627 /* LocationEditScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A10226B2C551EC500B84627 /* LocationEditScreen.swift */; }; 7A10226C2C551EC500B84627 /* LocationEditScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A10226B2C551EC500B84627 /* LocationEditScreen.swift */; };
7A10226E2C551EE000B84627 /* LocationEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A10226D2C551EE000B84627 /* LocationEditViewModel.swift */; }; 7A10226E2C551EE000B84627 /* LocationEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A10226D2C551EE000B84627 /* LocationEditViewModel.swift */; };
7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A10226F2C551EFD00B84627 /* LocationEditCoordinator.swift */; }; 7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A10226F2C551EFD00B84627 /* LocationEditCoordinator.swift */; };
@ -27,7 +26,6 @@
7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470923FDE7E600B424AF /* Assets.xcassets */; }; 7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470923FDE7E600B424AF /* Assets.xcassets */; };
7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470B23FDE7E600B424AF /* LaunchScreen.storyboard */; }; 7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470B23FDE7E600B424AF /* LaunchScreen.storyboard */; };
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471523FDEB2A00B424AF /* MainSplitController.swift */; }; 7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471523FDEB2A00B424AF /* MainSplitController.swift */; };
7A11471A23FE839000B424AF /* AuthController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471923FE839000B424AF /* AuthController.swift */; };
7A123C742D9DC40A00781F24 /* RecordScreenOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A123C732D9DC40A00781F24 /* RecordScreenOutput.swift */; }; 7A123C742D9DC40A00781F24 /* RecordScreenOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A123C732D9DC40A00781F24 /* RecordScreenOutput.swift */; };
7A131FD32D37B75500DC7755 /* HistoryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD22D37B75500DC7755 /* HistoryScreen.swift */; }; 7A131FD32D37B75500DC7755 /* HistoryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD22D37B75500DC7755 /* HistoryScreen.swift */; };
7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD42D37B76A00DC7755 /* HistoryViewModel.swift */; }; 7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A131FD42D37B76A00DC7755 /* HistoryViewModel.swift */; };
@ -38,7 +36,6 @@
7A14416E2C297F7C00E79018 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416D2C297F7C00E79018 /* Coordinator.swift */; }; 7A14416E2C297F7C00E79018 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A14416D2C297F7C00E79018 /* Coordinator.swift */; };
7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE492A2E820300626A6E /* UIStackView.swift */; }; 7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE492A2E820300626A6E /* UIStackView.swift */; };
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */; }; 7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */; };
7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80429A41C66007962DA /* RealmSwift */; };
7A1CF81629A42117007962DA /* Realm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1CF81529A42117007962DA /* Realm.swift */; }; 7A1CF81629A42117007962DA /* Realm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1CF81529A42117007962DA /* Realm.swift */; };
7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */; }; 7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */; };
7A1E78F62CE900330004B740 /* ReportScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78F52CE900330004B740 /* ReportScreen.swift */; }; 7A1E78F62CE900330004B740 /* ReportScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1E78F52CE900330004B740 /* ReportScreen.swift */; };
@ -102,7 +99,6 @@
7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD90B24335A6D009DE740 /* FlagLayer.swift */; }; 7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD90B24335A6D009DE740 /* FlagLayer.swift */; };
7A6F096026DBF588003A965D /* VehicleNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6F095F26DBF588003A965D /* VehicleNote.swift */; }; 7A6F096026DBF588003A965D /* VehicleNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6F095F26DBF588003A965D /* VehicleNote.swift */; };
7A7097C22C9EC139007CFDCA /* ServiceContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7097C12C9EC139007CFDCA /* ServiceContainer.swift */; }; 7A7097C22C9EC139007CFDCA /* ServiceContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7097C12C9EC139007CFDCA /* ServiceContainer.swift */; };
7A7097C62C9EC77A007CFDCA /* ServicePropertyWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7097C52C9EC77A007CFDCA /* ServicePropertyWrapper.swift */; };
7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7157FF2C43EA6900852088 /* OwnersScreen.swift */; }; 7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7157FF2C43EA6900852088 /* OwnersScreen.swift */; };
7A7158042C43EAA200852088 /* OwnersCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158032C43EAA200852088 /* OwnersCoordinator.swift */; }; 7A7158042C43EAA200852088 /* OwnersCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158032C43EAA200852088 /* OwnersCoordinator.swift */; };
7A7158072C44085600852088 /* OsagoScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158062C44085600852088 /* OsagoScreen.swift */; }; 7A7158072C44085600852088 /* OsagoScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158062C44085600852088 /* OsagoScreen.swift */; };
@ -117,6 +113,9 @@
7A761C08267E8EA20005F28F /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A43F9F7246C8A6200BA5B49 /* JWT.swift */; }; 7A761C08267E8EA20005F28F /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A43F9F7246C8A6200BA5B49 /* JWT.swift */; };
7A761C09267E8EE40005F28F /* Base64FS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE32246C095700297C33 /* Base64FS.swift */; }; 7A761C09267E8EE40005F28F /* Base64FS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE32246C095700297C33 /* Base64FS.swift */; };
7A761C0B267E8FF90005F28F /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A761C0A267E8FF90005F28F /* Error.swift */; }; 7A761C0B267E8FF90005F28F /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A761C0A267E8FF90005F28F /* Error.swift */; };
7A7AA2C42DA2A3CB00276D83 /* LocationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7AA2C32DA2A3CB00276D83 /* LocationError.swift */; };
7A7AA2C72DA2A45600276D83 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A7AA2C62DA2A45600276D83 /* RealmSwift */; };
7A7AA2C82DA2A45600276D83 /* RealmSwift in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 7A7AA2C62DA2A45600276D83 /* RealmSwift */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */; }; 7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */; };
7A809F392D66755B00CF1B3C /* Error+Canceled.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A809F382D66755B00CF1B3C /* Error+Canceled.swift */; }; 7A809F392D66755B00CF1B3C /* Error+Canceled.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A809F382D66755B00CF1B3C /* Error+Canceled.swift */; };
7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */; }; 7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */; };
@ -185,7 +184,6 @@
7AC8B2762D6A01C700190706 /* UISearchTextField+Dumb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC8B2752D6A01C700190706 /* UISearchTextField+Dumb.swift */; }; 7AC8B2762D6A01C700190706 /* UISearchTextField+Dumb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC8B2752D6A01C700190706 /* UISearchTextField+Dumb.swift */; };
7ACBB91E2CB9B155005A5168 /* Mockable in Frameworks */ = {isa = PBXBuildFile; productRef = 7ACBB91D2CB9B155005A5168 /* Mockable */; }; 7ACBB91E2CB9B155005A5168 /* Mockable in Frameworks */ = {isa = PBXBuildFile; productRef = 7ACBB91D2CB9B155005A5168 /* Mockable */; };
7ACBB9202CB9B16C005A5168 /* Mockable in Frameworks */ = {isa = PBXBuildFile; productRef = 7ACBB91F2CB9B16C005A5168 /* Mockable */; }; 7ACBB9202CB9B16C005A5168 /* Mockable in Frameworks */ = {isa = PBXBuildFile; productRef = 7ACBB91F2CB9B16C005A5168 /* Mockable */; };
7ADF23062C25B5BF002624FF /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7ADF23052C25B5BF002624FF /* RealmSwift */; };
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C92250B954900F237B2 /* Navigation.swift */; }; 7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C92250B954900F237B2 /* Navigation.swift */; };
7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C94250D037700F237B2 /* ShowEventController.swift */; }; 7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C94250D037700F237B2 /* ShowEventController.swift */; };
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C96250F41B000F237B2 /* PNKeyboard.swift */; }; 7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C96250F41B000F237B2 /* PNKeyboard.swift */; };
@ -200,7 +198,6 @@
7AF231992DA27C1B00AE5EB3 /* ACButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF231982DA27C1B00AE5EB3 /* ACButtonView.swift */; }; 7AF231992DA27C1B00AE5EB3 /* ACButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF231982DA27C1B00AE5EB3 /* ACButtonView.swift */; };
7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; }; 7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; };
7AF6D2052677C03B0086EA64 /* AutoCatCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 7AF6D2052677C03B0086EA64 /* AutoCatCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7AF6D2122677C12E0086EA64 /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A000AA124C2EEDE001F5B00 /* Location.swift */; };
7AF6D2132677C15A0086EA64 /* AudioRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A659B5824A2B1BA0043A0F2 /* AudioRecord.swift */; }; 7AF6D2132677C15A0086EA64 /* AudioRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A659B5824A2B1BA0043A0F2 /* AudioRecord.swift */; };
7AF6D2142677C1680086EA64 /* VehicleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAE6AD224CDDF950023860B /* VehicleEvent.swift */; }; 7AF6D2142677C1680086EA64 /* VehicleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAE6AD224CDDF950023860B /* VehicleEvent.swift */; };
7AF6D2172677C1680086EA64 /* VehicleRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB562B9249C9E9B00473D53 /* VehicleRegion.swift */; }; 7AF6D2172677C1680086EA64 /* VehicleRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB562B9249C9E9B00473D53 /* VehicleRegion.swift */; };
@ -257,6 +254,7 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
7A7AA2C82DA2A45600276D83 /* RealmSwift in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -267,7 +265,6 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
7A1022692C55197D00B84627 /* RealmSwift in Embed Frameworks */,
7AF6D2052677C03B0086EA64 /* AutoCatCore.framework in Embed Frameworks */, 7AF6D2052677C03B0086EA64 /* AutoCatCore.framework in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
@ -277,7 +274,6 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
6841A913FABBB0AB20DEF4FC /* PagedResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PagedResponse.swift; sourceTree = "<group>"; }; 6841A913FABBB0AB20DEF4FC /* PagedResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PagedResponse.swift; sourceTree = "<group>"; };
7A000AA124C2EEDE001F5B00 /* Location.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = "<group>"; };
7A0420A925619AEC00034941 /* Osago.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Osago.swift; sourceTree = "<group>"; }; 7A0420A925619AEC00034941 /* Osago.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Osago.swift; sourceTree = "<group>"; };
7A0516192414FF0900FC55AC /* DateSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSection.swift; sourceTree = "<group>"; }; 7A0516192414FF0900FC55AC /* DateSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSection.swift; sourceTree = "<group>"; };
7A06E0AB2C7065AB005731AC /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = "<group>"; }; 7A06E0AB2C7065AB005731AC /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = "<group>"; };
@ -301,7 +297,6 @@
7A11470C23FDE7E600B424AF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 7A11470C23FDE7E600B424AF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
7A11470E23FDE7E600B424AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 7A11470E23FDE7E600B424AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7A11471523FDEB2A00B424AF /* MainSplitController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitController.swift; sourceTree = "<group>"; }; 7A11471523FDEB2A00B424AF /* MainSplitController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitController.swift; sourceTree = "<group>"; };
7A11471923FE839000B424AF /* AuthController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthController.swift; sourceTree = "<group>"; };
7A11474323FF06CA00B424AF /* ApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiService.swift; sourceTree = "<group>"; }; 7A11474323FF06CA00B424AF /* ApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiService.swift; sourceTree = "<group>"; };
7A11474623FF2AA500B424AF /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; }; 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>"; }; 7A11474823FF2B2D00B424AF /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = "<group>"; };
@ -393,7 +388,6 @@
7A6DD90D24337930009DE740 /* PlateNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateNumber.swift; sourceTree = "<group>"; }; 7A6DD90D24337930009DE740 /* PlateNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateNumber.swift; sourceTree = "<group>"; };
7A6F095F26DBF588003A965D /* VehicleNote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleNote.swift; sourceTree = "<group>"; }; 7A6F095F26DBF588003A965D /* VehicleNote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleNote.swift; sourceTree = "<group>"; };
7A7097C12C9EC139007CFDCA /* ServiceContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceContainer.swift; sourceTree = "<group>"; }; 7A7097C12C9EC139007CFDCA /* ServiceContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceContainer.swift; sourceTree = "<group>"; };
7A7097C52C9EC77A007CFDCA /* ServicePropertyWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicePropertyWrapper.swift; sourceTree = "<group>"; };
7A7157FF2C43EA6900852088 /* OwnersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OwnersScreen.swift; sourceTree = "<group>"; }; 7A7157FF2C43EA6900852088 /* OwnersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OwnersScreen.swift; sourceTree = "<group>"; };
7A7158032C43EAA200852088 /* OwnersCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OwnersCoordinator.swift; sourceTree = "<group>"; }; 7A7158032C43EAA200852088 /* OwnersCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OwnersCoordinator.swift; sourceTree = "<group>"; };
7A7158062C44085600852088 /* OsagoScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsagoScreen.swift; sourceTree = "<group>"; }; 7A7158062C44085600852088 /* OsagoScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsagoScreen.swift; sourceTree = "<group>"; };
@ -403,6 +397,7 @@
7A7158112C444A6400852088 /* AdsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsViewModel.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>"; }; 7A71EF562D0A26B200943129 /* EventModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventModel.swift; sourceTree = "<group>"; };
7A761C0A267E8FF90005F28F /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; }; 7A761C0A267E8FF90005F28F /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; };
7A7AA2C32DA2A3CB00276D83 /* LocationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationError.swift; sourceTree = "<group>"; };
7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordView.swift; sourceTree = "<group>"; }; 7A7DADAB2D99738300F52F6C /* AudioRecordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordView.swift; sourceTree = "<group>"; };
7A809F382D66755B00CF1B3C /* Error+Canceled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+Canceled.swift"; sourceTree = "<group>"; }; 7A809F382D66755B00CF1B3C /* Error+Canceled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+Canceled.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; }; 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; };
@ -520,7 +515,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */, 7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */,
7ADF23062C25B5BF002624FF /* RealmSwift in Frameworks */,
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */, 7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */,
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */, 7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */,
7ACBB91E2CB9B155005A5168 /* Mockable in Frameworks */, 7ACBB91E2CB9B155005A5168 /* Mockable in Frameworks */,
@ -551,7 +545,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */, 7A7AA2C72DA2A45600276D83 /* RealmSwift in Frameworks */,
7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */, 7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */,
7AF8606E2CB9B86300954D2F /* Mockable in Frameworks */, 7AF8606E2CB9B86300954D2F /* Mockable in Frameworks */,
7A6C4D9E2C56BCA600982597 /* SwiftLocation in Frameworks */, 7A6C4D9E2C56BCA600982597 /* SwiftLocation in Frameworks */,
@ -655,7 +649,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7A813DC7250B5C6E00CC93B9 /* Location */, 7A813DC7250B5C6E00CC93B9 /* Location */,
7A11471923FE839000B424AF /* AuthController.swift */,
7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */, 7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */,
7A11471523FDEB2A00B424AF /* MainSplitController.swift */, 7A11471523FDEB2A00B424AF /* MainSplitController.swift */,
7AC3554B29696A1C00889457 /* MainTabController.swift */, 7AC3554B29696A1C00889457 /* MainTabController.swift */,
@ -861,6 +854,7 @@
7A60D24E2C5A9DA800D13F7B /* LocationServiceProtocol.swift */, 7A60D24E2C5A9DA800D13F7B /* LocationServiceProtocol.swift */,
7A60D2502C5A9E4200D13F7B /* GeocoderProtocol.swift */, 7A60D2502C5A9E4200D13F7B /* GeocoderProtocol.swift */,
7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */, 7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */,
7A7AA2C32DA2A3CB00276D83 /* LocationError.swift */,
); );
path = LocationService; path = LocationService;
sourceTree = "<group>"; sourceTree = "<group>";
@ -929,7 +923,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7A7097C12C9EC139007CFDCA /* ServiceContainer.swift */, 7A7097C12C9EC139007CFDCA /* ServiceContainer.swift */,
7A7097C52C9EC77A007CFDCA /* ServicePropertyWrapper.swift */,
); );
path = DependencyInjection; path = DependencyInjection;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1155,7 +1148,6 @@
children = ( children = (
7A43F9F7246C8A6200BA5B49 /* JWT.swift */, 7A43F9F7246C8A6200BA5B49 /* JWT.swift */,
7A96AE30246B2FE400297C33 /* Constants.swift */, 7A96AE30246B2FE400297C33 /* Constants.swift */,
7A000AA124C2EEDE001F5B00 /* Location.swift */,
7A64A2232C1A07EA00284124 /* Formatters.swift */, 7A64A2232C1A07EA00284124 /* Formatters.swift */,
7ABDA8082D8710F80083C715 /* AutoCancellable.swift */, 7ABDA8082D8710F80083C715 /* AutoCancellable.swift */,
); );
@ -1245,7 +1237,6 @@
7A813DC02508C4D900CC93B9 /* ExceptionCatcher */, 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */,
7AABDE1C2532F3EB0041AFC6 /* PKHUD */, 7AABDE1C2532F3EB0041AFC6 /* PKHUD */,
7AC355492969652F00889457 /* SwiftEntryKit */, 7AC355492969652F00889457 /* SwiftEntryKit */,
7ADF23052C25B5BF002624FF /* RealmSwift */,
7ACBB91D2CB9B155005A5168 /* Mockable */, 7ACBB91D2CB9B155005A5168 /* Mockable */,
); );
productName = AutoCat; productName = AutoCat;
@ -1318,9 +1309,9 @@
name = AutoCatCore; name = AutoCatCore;
packageProductDependencies = ( packageProductDependencies = (
7AABB1F1267E9CC800D7AB32 /* SwiftDate */, 7AABB1F1267E9CC800D7AB32 /* SwiftDate */,
7A1CF80429A41C66007962DA /* RealmSwift */,
7A6C4D9D2C56BCA600982597 /* SwiftLocation */, 7A6C4D9D2C56BCA600982597 /* SwiftLocation */,
7AF8606D2CB9B86300954D2F /* Mockable */, 7AF8606D2CB9B86300954D2F /* Mockable */,
7A7AA2C62DA2A45600276D83 /* RealmSwift */,
); );
productName = AutoCatCore; productName = AutoCatCore;
productReference = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; productReference = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */;
@ -1482,7 +1473,6 @@
7A2C96122C3B155B00AE46B5 /* NoteAlertModifier.swift in Sources */, 7A2C96122C3B155B00AE46B5 /* NoteAlertModifier.swift in Sources */,
7AE24C5F251F1B4E00758E39 /* Buttons.swift in Sources */, 7AE24C5F251F1B4E00758E39 /* Buttons.swift in Sources */,
7AF231972DA1C30000AE5EB3 /* AuthCoordinator.swift in Sources */, 7AF231972DA1C30000AE5EB3 /* AuthCoordinator.swift in Sources */,
7A11471A23FE839000B424AF /* AuthController.swift in Sources */,
7A5911F22D63268400EC51BA /* SearchCoordinator.swift in Sources */, 7A5911F22D63268400EC51BA /* SearchCoordinator.swift in Sources */,
7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */, 7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */,
7A1090EC24A4E3E100B4F0B2 /* CellProgressView.swift in Sources */, 7A1090EC24A4E3E100B4F0B2 /* CellProgressView.swift in Sources */,
@ -1576,7 +1566,7 @@
7A64A2162C19E4CF00284124 /* VehiclePhotoDto.swift in Sources */, 7A64A2162C19E4CF00284124 /* VehiclePhotoDto.swift in Sources */,
7A6B65B32CFB0DB500AABA6B /* NullifyDate.swift in Sources */, 7A6B65B32CFB0DB500AABA6B /* NullifyDate.swift in Sources */,
7A7097C22C9EC139007CFDCA /* ServiceContainer.swift in Sources */, 7A7097C22C9EC139007CFDCA /* ServiceContainer.swift in Sources */,
7A7097C62C9EC77A007CFDCA /* ServicePropertyWrapper.swift in Sources */, 7A7AA2C42DA2A3CB00276D83 /* LocationError.swift in Sources */,
7A54BFD32D43B95E00176D6D /* DbUpdatePolicy.swift in Sources */, 7A54BFD32D43B95E00176D6D /* DbUpdatePolicy.swift in Sources */,
7A5D84BE2C1AE44700C2209B /* VehiclePhoto.swift in Sources */, 7A5D84BE2C1AE44700C2209B /* VehiclePhoto.swift in Sources */,
7A64A2262C1A32C800284124 /* AudioRecordDto.swift in Sources */, 7A64A2262C1A32C800284124 /* AudioRecordDto.swift in Sources */,
@ -1587,7 +1577,6 @@
7A95197B2D80B41600E69883 /* AudioRecordServiceProtocol.swift in Sources */, 7A95197B2D80B41600E69883 /* AudioRecordServiceProtocol.swift in Sources */,
7AF6D21C2677C1680086EA64 /* DebugInfo.swift in Sources */, 7AF6D21C2677C1680086EA64 /* DebugInfo.swift in Sources */,
7ABDA80D2D8721B10083C715 /* Substrings.swift in Sources */, 7ABDA80D2D8721B10083C715 /* Substrings.swift in Sources */,
7AF6D2122677C12E0086EA64 /* Location.swift in Sources */,
7AF6D2142677C1680086EA64 /* VehicleEvent.swift in Sources */, 7AF6D2142677C1680086EA64 /* VehicleEvent.swift in Sources */,
7A64A2102C19E1EB00284124 /* VehicleBrandDto.swift in Sources */, 7A64A2102C19E1EB00284124 /* VehicleBrandDto.swift in Sources */,
7A599C392C18B22900D47C18 /* FbRefreshTokenModel.swift in Sources */, 7A599C392C18B22900D47C18 /* FbRefreshTokenModel.swift in Sources */,
@ -2161,16 +2150,16 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
7A1CF80429A41C66007962DA /* RealmSwift */ = {
isa = XCSwiftPackageProductDependency;
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
productName = RealmSwift;
};
7A6C4D9D2C56BCA600982597 /* SwiftLocation */ = { 7A6C4D9D2C56BCA600982597 /* SwiftLocation */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7A6C4D9C2C56BCA600982597 /* XCRemoteSwiftPackageReference "SwiftLocation" */; package = 7A6C4D9C2C56BCA600982597 /* XCRemoteSwiftPackageReference "SwiftLocation" */;
productName = SwiftLocation; productName = SwiftLocation;
}; };
7A7AA2C62DA2A45600276D83 /* RealmSwift */ = {
isa = XCSwiftPackageProductDependency;
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
productName = RealmSwift;
};
7A813DC02508C4D900CC93B9 /* ExceptionCatcher */ = { 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */; package = 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */;
@ -2206,11 +2195,6 @@
package = 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */; package = 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */;
productName = Mockable; productName = Mockable;
}; };
7ADF23052C25B5BF002624FF /* RealmSwift */ = {
isa = XCSwiftPackageProductDependency;
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
productName = RealmSwift;
};
7AF8606B2CB9B20C00954D2F /* Mockable */ = { 7AF8606B2CB9B20C00954D2F /* Mockable */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */; package = 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */;

View File

@ -1,5 +1,4 @@
import UIKit import UIKit
import RealmSwift
import PKHUD import PKHUD
import AutoCatCore import AutoCatCore
@ -8,55 +7,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let config = Realm.Configuration(
schemaVersion: 42,
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion <= 31 {
migration.enumerateObjects(ofType: "Vehicle") { old, new in
if let oldDebugInfo = old?["debugInfo"] as? DynamicObject, let newDebugInfo = new?["debugInfo"] as? DynamicObject {
let addStatus = { (providerName: String) -> Void in
if let provider = oldDebugInfo[providerName] as? DynamicObject, let newProvider = newDebugInfo[providerName] as? DynamicObject {
if provider["error"] != nil {
newProvider["status"] = DebugInfoStatus.error.rawValue
} else {
newProvider["status"] = DebugInfoStatus.success.rawValue
}
}
}
addStatus("autocod")
addStatus("vin01vin")
addStatus("vin01base")
addStatus("vin01history")
addStatus("nomerogram")
}
}
}
if oldSchemaVersion <= 34 {
var ids: Set<String> = Set()
migration.enumerateObjects(ofType: "VehicleEvent") { old, new in
guard let oldId = old?["id"] as? String? else { return }
var newId = oldId ?? UUID().uuidString
if ids.contains(newId) {
newId = UUID().uuidString
}
ids.insert(newId)
new?["id"] = newId
}
}
if oldSchemaVersion <= 36 {
migration.enumerateObjects(ofType: "Vehicle") { old, new in
new?["synchronized"] = true
}
}
})
Realm.Configuration.defaultConfiguration = config
HUD.dimsBackground = true HUD.dimsBackground = true
HUD.allowsInteraction = false HUD.allowsInteraction = false

View File

@ -1,79 +0,0 @@
import UIKit
import RealmSwift
import AuthenticationServices
import PKHUD
import AutoCatCore
class AuthController: UIViewController {
@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var login: UIButton!
@IBOutlet weak var signup: UIButton!
@Service var settingsService: SettingsServiceProtocol
override func viewDidLoad() {
super.viewDidLoad()
// FIX login/password lengt checking
// let authValid = Observable.combineLatest(self.username.rx.text, self.password.rx.text) { name, pass -> Bool in
// guard let name = name, let pass = pass else { return false }
// return name.count >= 4 && pass.count >= 5
// }
//
// authValid.bind(to: self.login.rx.isEnabled).disposed(by: self.bag)
// authValid.bind(to: self.signup.rx.isEnabled).disposed(by: self.bag)
if settingsService.user.email.count > 0 {
self.username.text = settingsService.user.email
}
}
@IBAction func loginTapped(_ sender: UIButton) {
guard let email = self.username.text, let pass = self.password.text else { return }
Task {
do {
HUD.show(.progress)
let user = try await ApiService.shared.login(email: email, password: pass)
self.goToMainScreen(user: user)
} catch {
HUD.show(error: error)
}
}
}
@IBAction func signupTapped(_ sender: UIButton) {
guard let email = self.username.text, let pass = self.password.text else { return }
Task {
do {
HUD.show(.progress)
let user = try await ApiService.shared.signUp(email: email, password: pass)
self.goToMainScreen(user: user)
} catch {
HUD.show(error: error)
}
}
}
func goToMainScreen(user: AutoCatCore.User) {
guard let realm = try? Realm() else {
HUD.flash(.labeledError(title: nil, subtitle: "Database error"))
return
}
HUD.hide()
if user.email != settingsService.user.email {
try? realm.write {
realm.deleteAll()
}
}
settingsService.user = user
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.view.window?.rootViewController = storyboard.instantiateViewController(identifier: "MainSplitController")
}
}

View File

@ -19,6 +19,8 @@ class GoogleSignInController: UIViewController, WKNavigationDelegate {
private var codeVerifier: String = "" private var codeVerifier: String = ""
public var completion: (() -> Void)? public var completion: (() -> Void)?
let apiService: ApiServiceProtocol = ServiceContainer.shared.resolve(ApiServiceProtocol.self)
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
self.webView.navigationDelegate = self self.webView.navigationDelegate = self
@ -55,7 +57,7 @@ class GoogleSignInController: UIViewController, WKNavigationDelegate {
Task { @MainActor in Task { @MainActor in
do { do {
let token = try await self.getToken(code: code) let token = try await self.getToken(code: code)
await ApiService.shared.fbVerifyAssertion(provider: "google.com", idToken: token.id_token, accessToken: token.access_token) await apiService.fbVerifyAssertion(provider: "google.com", idToken: token.id_token, accessToken: token.access_token)
self.dismiss(animated: true, completion: self.completion) self.dismiss(animated: true, completion: self.completion)
} catch { } catch {
HUD.flash(.labeledError(title: nil, subtitle: error.localizedDescription)) HUD.flash(.labeledError(title: nil, subtitle: error.localizedDescription))

View File

@ -39,6 +39,8 @@ class GlobalEventsController: UIViewController {
var filter: Filter! var filter: Filter!
let apiService: ApiServiceProtocol = ServiceContainer.shared.resolve(ApiServiceProtocol.self)
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@ -68,7 +70,7 @@ class GlobalEventsController: UIViewController {
func loadEvents() async { func loadEvents() async {
do { do {
HUD.show(.progress) HUD.show(.progress)
let events = try await ApiService.shared.events(with: self.filter) let events = try await apiService.events(with: self.filter)
self.title = String.localizedStringWithFormat(NSLocalizedString("events found", comment: ""), events.count) self.title = String.localizedStringWithFormat(NSLocalizedString("events found", comment: ""), events.count)
let pins = events.map(EventPin.init(event:)) let pins = events.map(EventPin.init(event:))
self.map.removeAnnotations(self.map.annotations) self.map.removeAnnotations(self.map.annotations)

View File

@ -106,7 +106,8 @@ class MainTabController: UITabBarController, UITabBarControllerDelegate {
// User probably just saw a vehicle and is about to start entering plate number // User probably just saw a vehicle and is about to start entering plate number
// Requesting current location ASAP while we still close to initial location // Requesting current location ASAP while we still close to initial location
Task { try? await RxLocationManager.requestCurrentLocation() } let locationService = ServiceContainer.shared.resolve(LocationServiceProtocol.self)
Task { try? await locationService.requestCurrentLocation() }
} }
} }

View File

@ -42,7 +42,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
container.register(SettingsServiceProtocol.self, instance: settingsService) container.register(SettingsServiceProtocol.self, instance: settingsService)
let apiService = ApiService() let apiService = ApiService(settingsService: settingsService)
container.register(ApiServiceProtocol.self, instance: apiService) container.register(ApiServiceProtocol.self, instance: apiService)
let locationService = LocationService( let locationService = LocationService(
@ -158,9 +158,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func openReport(with number: String) async { func openReport(with number: String) async {
guard let rootController = self.window?.rootViewController else { return } guard let rootController = self.window?.rootViewController else { return }
let apiService: ApiServiceProtocol = ServiceContainer.shared.resolve(ApiServiceProtocol.self)
do { do {
HUD.show(.progress) HUD.show(.progress)
let vehicle = try await ApiService.shared.getReport(for: number) let vehicle = try await apiService.getReport(for: number)
Task { Task {
let coordinator = ReportCoordinator(controller: rootController, vehicle: vehicle, isPersistent: false) let coordinator = ReportCoordinator(controller: rootController, vehicle: vehicle, isPersistent: false)

View File

@ -1,24 +0,0 @@
//
// ServicePropertyWrapper.swift
// AutoCatCore
//
// Created by Selim Mustafaev on 21.09.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
@propertyWrapper
@MainActor
public struct Service<Service> {
public var service: Service
public init() {
self.service = try! ServiceContainer.shared.resolve(Service.self)
}
public var wrappedValue: Service {
get { service }
set { service = newValue }
}
}

View File

@ -2,11 +2,11 @@ import Foundation
public actor ApiService: ApiServiceProtocol { public actor ApiService: ApiServiceProtocol {
public static let shared = ApiService() var settingsService: SettingsServiceProtocol
@Service var settingsService: SettingsServiceProtocol public init(settingsService: SettingsServiceProtocol) {
public init() { self.settingsService = settingsService
} }
private let session: URLSession = { private let session: URLSession = {
@ -20,7 +20,7 @@ public actor ApiService: ApiServiceProtocol {
private func createRequest<B,P>(api: String, method: String, body: B? = nil, params: [String:P]? = nil) async -> URLRequest? where B: Encodable, P: LosslessStringConvertible { private func createRequest<B,P>(api: String, method: String, body: B? = nil, params: [String:P]? = nil) async -> URLRequest? where B: Encodable, P: LosslessStringConvertible {
let baseUrl = await settingsService.backend.baseUrl let baseUrl = settingsService.backend.baseUrl
guard var urlComponents = URLComponents(string: baseUrl + api) else { return nil } guard var urlComponents = URLComponents(string: baseUrl + api) else { return nil }
@ -32,7 +32,7 @@ public actor ApiService: ApiServiceProtocol {
request.httpMethod = method request.httpMethod = method
request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept") request.addValue("application/json", forHTTPHeaderField: "Accept")
await request.addValue("Bearer " + settingsService.user.token, forHTTPHeaderField: "Authorization") request.addValue("Bearer " + settingsService.user.token, forHTTPHeaderField: "Authorization")
if let body = body, method.uppercased() != "GET" { if let body = body, method.uppercased() != "GET" {
let encoder = JSONEncoder() let encoder = JSONEncoder()
@ -109,8 +109,8 @@ public actor ApiService: ApiServiceProtocol {
// MARK: - Firebase API // MARK: - Firebase API
public func refreshFbToken() async throws { public func refreshFbToken() async throws {
guard let token = await settingsService.user.firebaseIdToken, guard let token = settingsService.user.firebaseIdToken,
let refreshToken = await settingsService.user.firebaseRefreshToken, let refreshToken = settingsService.user.firebaseRefreshToken,
let jwt = JWT<FirebasePayload>(string: token), jwt.expired else { let jwt = JWT<FirebasePayload>(string: token), jwt.expired else {
return return
} }
@ -237,7 +237,7 @@ public actor ApiService: ApiServiceProtocol {
"forceUpdate": AnyEncodable(force) "forceUpdate": AnyEncodable(force)
] ]
if let token = await settingsService.user.firebaseIdToken { if let token = settingsService.user.firebaseIdToken {
body["googleIdToken"] = AnyEncodable(token) body["googleIdToken"] = AnyEncodable(token)
} }
@ -324,7 +324,7 @@ public actor ApiService: ApiServiceProtocol {
var body = ["number": number] var body = ["number": number]
if let token = await settingsService.user.firebaseIdToken { if let token = settingsService.user.firebaseIdToken {
body["token"] = token body["token"] = token
} }

View File

@ -21,6 +21,7 @@ public protocol ApiServiceProtocol: Sendable {
func add(event: VehicleEventDto, to number: String) async throws -> VehicleDto func add(event: VehicleEventDto, to number: String) async throws -> VehicleDto
func remove(event id: String) async throws -> VehicleDto func remove(event id: String) async throws -> VehicleDto
func edit(event: VehicleEventDto) async throws -> VehicleDto func edit(event: VehicleEventDto) async throws -> VehicleDto
func events(with filter: Filter) async throws -> [VehicleEventDto]
func getBrands() async throws -> [String] func getBrands() async throws -> [String]
func getModels(of brand: String) async throws -> [String] func getModels(of brand: String) async throws -> [String]
@ -32,4 +33,6 @@ public protocol ApiServiceProtocol: Sendable {
func checkVehicleGb(by number: String) async throws -> VehicleDto func checkVehicleGb(by number: String) async throws -> VehicleDto
func getVehicles(with filter: Filter, pageToken: String?, pageSize: Int) async throws -> PagedResponse<VehicleDto> func getVehicles(with filter: Filter, pageToken: String?, pageSize: Int) async throws -> PagedResponse<VehicleDto>
func fbVerifyAssertion(provider: String, idToken: String, accessToken: String?) async
func getReport(for number: String) async throws -> VehicleDto
} }

View File

@ -0,0 +1,24 @@
//
// LocationError.swift
// AutoCatCore
//
// Created by Selim Mustafaev on 06.04.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import Foundation
public enum LocationError: LocalizedError {
case generic
case permission
case reverseGeocode
public var errorDescription: String? {
switch self {
case .generic: "Location error"
case .permission: "Location permission error"
case .reverseGeocode: "Reverse geocode error"
}
}
}

View File

@ -15,11 +15,22 @@ public actor StorageService: StorageServiceProtocol {
var realm: Realm! var realm: Realm!
public init(settingsService: SettingsServiceProtocol, public init(settingsService: SettingsServiceProtocol, isTest: Bool = false) async throws {
config: Realm.Configuration = .defaultConfiguration) async throws {
var realmConfig: Realm.Configuration
if isTest {
realmConfig = .defaultConfiguration
realmConfig.inMemoryIdentifier = UUID().uuidString
} else {
realmConfig = Realm.Configuration(
schemaVersion: 42,
migrationBlock: { migration, oldSchemaVersion in }
)
}
self.settingsService = settingsService self.settingsService = settingsService
realm = try await Realm(configuration: config, actor: self) realm = try await Realm(configuration: realmConfig, actor: self)
} }
public var dbFileURL: URL? { public var dbFileURL: URL? {
@ -28,6 +39,10 @@ public actor StorageService: StorageServiceProtocol {
} }
} }
public var config: Realm.Configuration {
realm.configuration
}
public func deleteAll() async throws { public func deleteAll() async throws {
try await realm.asyncWrite { try await realm.asyncWrite {

View File

@ -1,116 +0,0 @@
import Foundation
import CoreLocation
import SwiftLocation
public enum LocationError: LocalizedError {
case generic
case permission
case reverseGeocode
public var errorDescription: String? {
switch self {
case .generic: "Location error"
case .permission: "Location permission error"
case .reverseGeocode: "Reverse geocode error"
}
}
}
@MainActor
public class RxLocationManager {
private let generalErrors: [CLError.Code] = [.locationUnknown, .denied, .network, .headingFailure, .rangingUnavailable, .rangingFailure]
private let geocodingErrors: [CLError.Code] = [.geocodeCanceled, .geocodeFoundNoResult, .geocodeFoundPartialResult]
private static let locationManager: Location = {
let manger = CLLocationManager()
manger.desiredAccuracy = kCLLocationAccuracyBest
return Location(locationManager: manger)
}()
private static var eventTask: Task<VehicleEventDto,Error>?
public private(set) static var lastEvent: VehicleEventDto?
private static func checkPermissions() async throws {
switch locationManager.authorizationStatus {
case .authorizedWhenInUse, .authorizedAlways:
break
case .notDetermined:
let status = try await locationManager.requestPermission(.always)
if [.authorizedWhenInUse, .authorizedAlways].contains(status) {
return
} else {
throw LocationError.permission
}
case .denied:
throw CLError(.denied)
default:
throw LocationError.permission
}
}
private static func requestLocation() async throws -> VehicleEventDto {
let locationEvent = try await locationManager.requestLocation(timeout: 20)
guard let coordinate = locationEvent.location?.coordinate else {
throw LocationError.generic
}
let settingsService = try ServiceContainer.shared.resolve(SettingsServiceProtocol.self)
let event = VehicleEventDto(lat: coordinate.latitude, lon: coordinate.longitude, addedBy: settingsService.user.email)
self.lastEvent = event
return event
}
@discardableResult
public static func requestCurrentLocation() async throws -> VehicleEventDto {
if let eventTask {
return try await eventTask.value
} else {
try await checkPermissions()
let task = Task {
let location = try await requestLocation()
eventTask = nil
return location
}
eventTask = task
return try await task.value
}
}
public static func locationRequestInProgress() -> Bool {
return self.eventTask != nil
}
public static func getAddressForLocation(latitude: Double, longitude: Double) async throws -> String {
try await withCheckedThrowingContinuation { continuation in
let geocoder = CLGeocoder()
let location = CLLocation(latitude: latitude, longitude: longitude)
geocoder.reverseGeocodeLocation(location) { placemarks, error in
if let error = error {
continuation.resume(throwing: error)
} else if let placemark = placemarks?.first, let name = placemark.name {
continuation.resume(returning: name)
} else {
continuation.resume(throwing: LocationError.reverseGeocode)
}
}
// TODO: Add cancellation after timeout (20 seconds)
//geocoder.cancelGeocode()
}
}
public static func resetLastEvent() {
self.lastEvent = nil
}
public static func getLastEvent() async -> VehicleEventDto? {
lastEvent
}
}

View File

@ -27,12 +27,10 @@ struct StorageServiceTests {
init() async throws { init() async throws {
var config = Realm.Configuration.defaultConfiguration
config.inMemoryIdentifier = UUID().uuidString
self.realmConfig = config
settingsServiceMock = MockSettingsServiceProtocol() settingsServiceMock = MockSettingsServiceProtocol()
self.storageService = try await StorageService(settingsService: settingsServiceMock, config: realmConfig) self.storageService = try await StorageService(settingsService: settingsServiceMock, isTest: true)
realmConfig = await storageService.config
try addTestVehicle(config: realmConfig) try addTestVehicle(config: realmConfig)

View File

@ -421,4 +421,43 @@ struct VehicleServiceTests {
#expect(result.errors.count == 0) #expect(result.errors.count == 0)
#expect(result.vehicle.events.count == 0) #expect(result.vehicle.events.count == 0)
} }
@Test("Check (from audio record)")
func checkFromAudioRecord() async throws {
let vehicle: VehicleDto = .normal
let vehicleWithEvent = vehicle.addEvent(.valid)
given(storageServiceMock)
.loadVehicle(number: .any)
.willReturn(.normal)
given(apiServiceMock)
.checkVehicle(by: .any, notes: .any, events: .value([.valid]), force: .any)
.willReturn(vehicleWithEvent)
given(locationServiceMock)
.resetLastEvent()
.willReturn()
given(storageServiceMock)
.updateVehicle(dto: .any, policy: .any)
.willReturn(true)
let result = try await vehicleService.checkRecord(number: vehicle.number, event: .valid)
verify(apiServiceMock)
.checkVehicle(by: .any, notes: .any, events: .value([.valid]), force: .value(false))
.called(.once)
verify(storageServiceMock)
.updateVehicle(dto: .value(vehicleWithEvent), policy: .value(.always))
.called(.once)
#expect(result.vehicle.number == vehicle.number)
#expect(result.errors.count == 0)
#expect(result.vehicle.events.count == 1)
#expect(result.vehicle.events.first?.latitude == VehicleEventDto.validLatitude)
#expect(result.vehicle.events.first?.longitude == VehicleEventDto.validLongitude)
}
} }

View File

@ -0,0 +1,238 @@
//
// AuthTests.swift
// AutoCatTests
//
// Created by Selim Mustafaev on 06.04.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import Testing
import Mockable
import AutoCatCore
@testable import AutoCat
@MainActor
struct AuthTests {
let apiServiceMock = MockApiServiceProtocol()
let storageServiceMock = MockStorageServiceProtocol()
var settingsServiceMock = MockSettingsServiceProtocol()
var viewModel: AuthViewModel
init() {
viewModel = AuthViewModel(
apiService: apiServiceMock,
storageService: storageServiceMock,
settingsService: settingsServiceMock
)
}
@Test("Initial load")
func initialLoad() async throws {
given(settingsServiceMock)
.user.willReturn(User())
viewModel.onAppear()
#expect(viewModel.email == "")
}
@Test("Initial load (existing user)")
func initialLoadExistingUser() {
given(settingsServiceMock)
.user.willReturn(User(email: "test@example.com", token: "123"))
viewModel.onAppear()
#expect(viewModel.email == "test@example.com")
}
@Test("Login", arguments: [false, true])
func login(sameUser: Bool) async {
let existingUser = User(email: "test@example.com")
let newUser = User(email: "test2@example.com")
given(settingsServiceMock)
.user.willReturn(existingUser)
given(apiServiceMock)
.login(email: .any, password: .any)
.willReturn(sameUser ? existingUser : newUser)
given(storageServiceMock)
.deleteAll()
.willReturn()
await viewModel.login()
verify(settingsServiceMock)
.user()
.getCalled(.once)
verify(settingsServiceMock)
.user()
.setCalled(.once)
verify(apiServiceMock)
.login(email: .any, password: .any)
.called(.once)
verify(storageServiceMock)
.deleteAll()
.called(sameUser ? .never : .once)
#expect(viewModel.hud == nil)
}
@Test("Login (api failed)")
func loginApiFailed() async {
given(apiServiceMock)
.login(email: .any, password: .any)
.willThrow(TestError.generic)
await viewModel.login()
verify(apiServiceMock)
.login(email: .any, password: .any)
.called(.once)
#expect(viewModel.hud == .error(TestError.generic))
}
@Test("Login (DB failed)")
func loginDbFailed() async {
let existingUser = User(email: "test@example.com")
let newUser = User(email: "test2@example.com")
given(settingsServiceMock)
.user.willReturn(existingUser)
given(apiServiceMock)
.login(email: .any, password: .any)
.willReturn(newUser)
given(storageServiceMock)
.deleteAll()
.willThrow(TestError.generic)
await viewModel.login()
verify(settingsServiceMock)
.user()
.getCalled(.once)
verify(settingsServiceMock)
.user()
.setCalled(.never)
verify(apiServiceMock)
.login(email: .any, password: .any)
.called(.once)
verify(storageServiceMock)
.deleteAll()
.called(.once)
#expect(viewModel.hud == .error(TestError.generic))
}
@Test("Signup", arguments: [false, true])
func signup(sameUser: Bool) async {
let existingUser = User(email: "test@example.com")
let newUser = User(email: "test2@example.com")
given(settingsServiceMock)
.user.willReturn(existingUser)
given(apiServiceMock)
.signUp(email: .any, password: .any)
.willReturn(sameUser ? existingUser : newUser)
given(storageServiceMock)
.deleteAll()
.willReturn()
await viewModel.signup()
verify(settingsServiceMock)
.user()
.getCalled(.once)
verify(settingsServiceMock)
.user()
.setCalled(.once)
verify(apiServiceMock)
.signUp(email: .any, password: .any)
.called(.once)
verify(storageServiceMock)
.deleteAll()
.called(sameUser ? .never : .once)
#expect(viewModel.hud == nil)
}
@Test("Signup (api failed)")
func signupApiFailed() async {
given(apiServiceMock)
.signUp(email: .any, password: .any)
.willThrow(TestError.generic)
await viewModel.signup()
verify(apiServiceMock)
.signUp(email: .any, password: .any)
.called(.once)
#expect(viewModel.hud == .error(TestError.generic))
}
@Test("Signup (DB failed)")
func signupDbFailed() async {
let existingUser = User(email: "test@example.com")
let newUser = User(email: "test2@example.com")
given(settingsServiceMock)
.user.willReturn(existingUser)
given(apiServiceMock)
.signUp(email: .any, password: .any)
.willReturn(newUser)
given(storageServiceMock)
.deleteAll()
.willThrow(TestError.generic)
await viewModel.signup()
verify(settingsServiceMock)
.user()
.getCalled(.once)
verify(settingsServiceMock)
.user()
.setCalled(.never)
verify(apiServiceMock)
.signUp(email: .any, password: .any)
.called(.once)
verify(storageServiceMock)
.deleteAll()
.called(.once)
#expect(viewModel.hud == .error(TestError.generic))
}
}