Adding native macOS run destination

This commit is contained in:
Selim Mustafaev 2025-04-30 16:54:11 +03:00
parent 022bfd3307
commit bbaef15acb
57 changed files with 321 additions and 377 deletions

View File

@ -13,7 +13,6 @@
7A06E0B52C707E2B005731AC /* SettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0B42C707E2B005731AC /* SettingsService.swift */; }; 7A06E0B52C707E2B005731AC /* SettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A06E0B42C707E2B005731AC /* SettingsService.swift */; };
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 */; };
7A1022722C554A1300B84627 /* CustomHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1022712C554A1300B84627 /* CustomHostingController.swift */; };
7A1022772C557EC400B84627 /* LocationPickerScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1022762C557EC400B84627 /* LocationPickerScreen.swift */; }; 7A1022772C557EC400B84627 /* LocationPickerScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1022762C557EC400B84627 /* LocationPickerScreen.swift */; };
7A1022792C557ED600B84627 /* LocationPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1022782C557ED600B84627 /* LocationPickerViewModel.swift */; }; 7A1022792C557ED600B84627 /* LocationPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1022782C557ED600B84627 /* LocationPickerViewModel.swift */; };
7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470923FDE7E600B424AF /* Assets.xcassets */; }; 7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A11470923FDE7E600B424AF /* Assets.xcassets */; };
@ -98,6 +97,9 @@
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 */; };
7A8AB76525A0DB8F00ECF2C1 /* BundleVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */; }; 7A8AB76525A0DB8F00ECF2C1 /* BundleVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */; };
7A912F372D381B7400002938 /* LicensePlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A912F362D381B7400002938 /* LicensePlateView.swift */; }; 7A912F372D381B7400002938 /* LicensePlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A912F362D381B7400002938 /* LicensePlateView.swift */; };
7A91CE952DC2422B00DBA953 /* HideTabBarModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A91CE942DC2422B00DBA953 /* HideTabBarModifier.swift */; };
7A91CE982DC243AD00DBA953 /* TitleModeInlineModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A91CE972DC243AD00DBA953 /* TitleModeInlineModifier.swift */; };
7A91CE9A2DC2470F00DBA953 /* TextFieldDumbModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A91CE992DC2470F00DBA953 /* TextFieldDumbModifier.swift */; };
7A9519792D80B3E800E69883 /* AudioRecordService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9519782D80B3E800E69883 /* AudioRecordService.swift */; }; 7A9519792D80B3E800E69883 /* AudioRecordService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9519782D80B3E800E69883 /* AudioRecordService.swift */; };
7A95197B2D80B41600E69883 /* AudioRecordServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A95197A2D80B41600E69883 /* AudioRecordServiceProtocol.swift */; }; 7A95197B2D80B41600E69883 /* AudioRecordServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A95197A2D80B41600E69883 /* AudioRecordServiceProtocol.swift */; };
7A95197D2D80B43D00E69883 /* AudioRecordError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A95197C2D80B43D00E69883 /* AudioRecordError.swift */; }; 7A95197D2D80B43D00E69883 /* AudioRecordError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A95197C2D80B43D00E69883 /* AudioRecordError.swift */; };
@ -110,11 +112,9 @@
7AA515D02D9ABCC800EB3418 /* RecordPlayerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA515CF2D9ABCC800EB3418 /* RecordPlayerService.swift */; }; 7AA515D02D9ABCC800EB3418 /* RecordPlayerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA515CF2D9ABCC800EB3418 /* RecordPlayerService.swift */; };
7AA515D22D9ABCE600EB3418 /* RecordPlayerServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA515D12D9ABCE600EB3418 /* RecordPlayerServiceProtocol.swift */; }; 7AA515D22D9ABCE600EB3418 /* RecordPlayerServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA515D12D9ABCE600EB3418 /* RecordPlayerServiceProtocol.swift */; };
7AA515DA2D9ADEF000EB3418 /* StorageError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA515D92D9ADEF000EB3418 /* StorageError.swift */; }; 7AA515DA2D9ADEF000EB3418 /* StorageError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA515D92D9ADEF000EB3418 /* StorageError.swift */; };
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; }; 7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFAD22C4D0FD00050410D /* ACImageSliderView.swift */; platformFilter = ios; };
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABDE1C2532F3EB0041AFC6 /* PKHUD */; };
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFAD22C4D0FD00050410D /* ACImageSliderView.swift */; };
7AAAFADA2C4D1AFE0050410D /* Zoomable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFAD92C4D1AFE0050410D /* Zoomable.swift */; }; 7AAAFADA2C4D1AFE0050410D /* Zoomable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFAD92C4D1AFE0050410D /* Zoomable.swift */; };
7AAAFADC2C4D1E130050410D /* ACImageSliderView+Modifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFADB2C4D1E130050410D /* ACImageSliderView+Modifier.swift */; }; 7AAAFADC2C4D1E130050410D /* ACImageSliderView+Modifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFADB2C4D1E130050410D /* ACImageSliderView+Modifier.swift */; platformFilter = ios; };
7AAAFADE2C4D23620050410D /* ACImageSliderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFADD2C4D23620050410D /* ACImageSliderModel.swift */; }; 7AAAFADE2C4D23620050410D /* ACImageSliderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFADD2C4D23620050410D /* ACImageSliderModel.swift */; };
7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABB1F1267E9CC800D7AB32 /* SwiftDate */; }; 7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABB1F1267E9CC800D7AB32 /* SwiftDate */; };
7AABBE3B2CF9F85600346588 /* Binding+Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABBE3A2CF9F85600346588 /* Binding+Map.swift */; }; 7AABBE3B2CF9F85600346588 /* Binding+Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABBE3A2CF9F85600346588 /* Binding+Map.swift */; };
@ -142,7 +142,6 @@
7ABDA80B2D8715DC0083C715 /* VehicleRecordError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABDA80A2D8715DC0083C715 /* VehicleRecordError.swift */; }; 7ABDA80B2D8715DC0083C715 /* VehicleRecordError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABDA80A2D8715DC0083C715 /* VehicleRecordError.swift */; };
7ABDA80D2D8721B10083C715 /* Substrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABDA80C2D8721B10083C715 /* Substrings.swift */; }; 7ABDA80D2D8721B10083C715 /* Substrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABDA80C2D8721B10083C715 /* Substrings.swift */; };
7ABDA80F2D8723F90083C715 /* StorageService+AudioRecords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABDA80E2D8723F90083C715 /* StorageService+AudioRecords.swift */; }; 7ABDA80F2D8723F90083C715 /* StorageService+AudioRecords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABDA80E2D8723F90083C715 /* StorageService+AudioRecords.swift */; };
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7AC355492969652F00889457 /* SwiftEntryKit */; };
7AC44B822DB390B900ADC026 /* MainTabScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC44B812DB390B900ADC026 /* MainTabScreen.swift */; }; 7AC44B822DB390B900ADC026 /* MainTabScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC44B812DB390B900ADC026 /* MainTabScreen.swift */; };
7AC44B8A2DB4395300ADC026 /* SearchSplitScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC44B892DB4395300ADC026 /* SearchSplitScreen.swift */; }; 7AC44B8A2DB4395300ADC026 /* SearchSplitScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC44B892DB4395300ADC026 /* SearchSplitScreen.swift */; };
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 */; };
@ -249,7 +248,6 @@
7A06E0B42C707E2B005731AC /* SettingsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsService.swift; sourceTree = "<group>"; }; 7A06E0B42C707E2B005731AC /* SettingsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsService.swift; sourceTree = "<group>"; };
7A10226B2C551EC500B84627 /* LocationEditScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationEditScreen.swift; sourceTree = "<group>"; }; 7A10226B2C551EC500B84627 /* LocationEditScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationEditScreen.swift; sourceTree = "<group>"; };
7A10226D2C551EE000B84627 /* LocationEditViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationEditViewModel.swift; sourceTree = "<group>"; }; 7A10226D2C551EE000B84627 /* LocationEditViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationEditViewModel.swift; sourceTree = "<group>"; };
7A1022712C554A1300B84627 /* CustomHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomHostingController.swift; sourceTree = "<group>"; };
7A1022762C557EC400B84627 /* LocationPickerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerScreen.swift; sourceTree = "<group>"; }; 7A1022762C557EC400B84627 /* LocationPickerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerScreen.swift; sourceTree = "<group>"; };
7A1022782C557ED600B84627 /* LocationPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewModel.swift; sourceTree = "<group>"; }; 7A1022782C557ED600B84627 /* LocationPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewModel.swift; sourceTree = "<group>"; };
7A1146FD23FDE7E500B424AF /* AutoCat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoCat.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7A1146FD23FDE7E500B424AF /* AutoCat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoCat.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -344,6 +342,9 @@
7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleVersion.swift; sourceTree = "<group>"; }; 7A8AB76425A0DB8F00ECF2C1 /* BundleVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleVersion.swift; sourceTree = "<group>"; };
7A8AB76725A0DC8200ECF2C1 /* DebugInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugInfo.swift; sourceTree = "<group>"; }; 7A8AB76725A0DC8200ECF2C1 /* DebugInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugInfo.swift; sourceTree = "<group>"; };
7A912F362D381B7400002938 /* LicensePlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensePlateView.swift; sourceTree = "<group>"; }; 7A912F362D381B7400002938 /* LicensePlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensePlateView.swift; sourceTree = "<group>"; };
7A91CE942DC2422B00DBA953 /* HideTabBarModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideTabBarModifier.swift; sourceTree = "<group>"; };
7A91CE972DC243AD00DBA953 /* TitleModeInlineModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleModeInlineModifier.swift; sourceTree = "<group>"; };
7A91CE992DC2470F00DBA953 /* TextFieldDumbModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldDumbModifier.swift; sourceTree = "<group>"; };
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; }; 7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; };
7A9519782D80B3E800E69883 /* AudioRecordService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordService.swift; sourceTree = "<group>"; }; 7A9519782D80B3E800E69883 /* AudioRecordService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordService.swift; sourceTree = "<group>"; };
7A95197A2D80B41600E69883 /* AudioRecordServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordServiceProtocol.swift; sourceTree = "<group>"; }; 7A95197A2D80B41600E69883 /* AudioRecordServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordServiceProtocol.swift; sourceTree = "<group>"; };
@ -443,12 +444,9 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */,
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */,
7A386A4B2DAC35F10051676A /* ClusterMap in Frameworks */, 7A386A4B2DAC35F10051676A /* ClusterMap in Frameworks */,
7A7AA2CA2DA2C85100276D83 /* RealmSwift in Frameworks */, 7A7AA2CA2DA2C85100276D83 /* RealmSwift in Frameworks */,
7A386A4D2DAC35F10051676A /* ClusterMapSwiftUI in Frameworks */, 7A386A4D2DAC35F10051676A /* ClusterMapSwiftUI in Frameworks */,
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */,
7ACBB91E2CB9B155005A5168 /* Mockable in Frameworks */, 7ACBB91E2CB9B155005A5168 /* Mockable in Frameworks */,
7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */, 7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */,
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */, 7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */,
@ -851,6 +849,16 @@
path = ThirdParty; path = ThirdParty;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
7A91CE962DC2436D00DBA953 /* Modifiers */ = {
isa = PBXGroup;
children = (
7A91CE942DC2422B00DBA953 /* HideTabBarModifier.swift */,
7A91CE972DC243AD00DBA953 /* TitleModeInlineModifier.swift */,
7A91CE992DC2470F00DBA953 /* TextFieldDumbModifier.swift */,
);
path = Modifiers;
sourceTree = "<group>";
};
7A9519772D80B3B200E69883 /* AudioRecordService */ = { 7A9519772D80B3B200E69883 /* AudioRecordService */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1045,13 +1053,13 @@
7AFBE8C52C30812E003C491D /* SwiftUI */ = { 7AFBE8C52C30812E003C491D /* SwiftUI */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7A91CE962DC2436D00DBA953 /* Modifiers */,
7AD176AE2DC127290023049D /* NumberEditView */, 7AD176AE2DC127290023049D /* NumberEditView */,
7AAAFAD12C4D0FB00050410D /* ACImageSlider */, 7AAAFAD12C4D0FB00050410D /* ACImageSlider */,
7AFBE8C62C30814E003C491D /* ACProgressHud */, 7AFBE8C62C30814E003C491D /* ACProgressHud */,
7A961C6B2C4C3C8600CE2211 /* TextRowView.swift */, 7A961C6B2C4C3C8600CE2211 /* TextRowView.swift */,
7A961C6D2C4C3C9E00CE2211 /* LinkRowView.swift */, 7A961C6D2C4C3C9E00CE2211 /* LinkRowView.swift */,
7AAAFAD92C4D1AFE0050410D /* Zoomable.swift */, 7AAAFAD92C4D1AFE0050410D /* Zoomable.swift */,
7A1022712C554A1300B84627 /* CustomHostingController.swift */,
7A5D7E0B2C71EB25002C17E7 /* ToggleRowView.swift */, 7A5D7E0B2C71EB25002C17E7 /* ToggleRowView.swift */,
7AF8606F2CBAA24500954D2F /* NavigationLink.swift */, 7AF8606F2CBAA24500954D2F /* NavigationLink.swift */,
7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */, 7A2E11282CCE395300E5CA17 /* OptionalDatePicker.swift */,
@ -1106,9 +1114,6 @@
); );
name = AutoCat; name = AutoCat;
packageProductDependencies = ( packageProductDependencies = (
7A813DC02508C4D900CC93B9 /* ExceptionCatcher */,
7AABDE1C2532F3EB0041AFC6 /* PKHUD */,
7AC355492969652F00889457 /* SwiftEntryKit */,
7ACBB91D2CB9B155005A5168 /* Mockable */, 7ACBB91D2CB9B155005A5168 /* Mockable */,
7A7AA2C92DA2C85100276D83 /* RealmSwift */, 7A7AA2C92DA2C85100276D83 /* RealmSwift */,
7A386A4A2DAC35F10051676A /* ClusterMap */, 7A386A4A2DAC35F10051676A /* ClusterMap */,
@ -1229,9 +1234,6 @@
mainGroup = 7A1146F423FDE7E500B424AF; mainGroup = 7A1146F423FDE7E500B424AF;
packageReferences = ( packageReferences = (
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */, 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */,
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */,
7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */,
7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */,
7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */, 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */,
7A6C4D9C2C56BCA600982597 /* XCRemoteSwiftPackageReference "SwiftLocation" */, 7A6C4D9C2C56BCA600982597 /* XCRemoteSwiftPackageReference "SwiftLocation" */,
7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */, 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */,
@ -1316,6 +1318,7 @@
7A6C65222D999325001240C2 /* AudioRecordViewModel.swift in Sources */, 7A6C65222D999325001240C2 /* AudioRecordViewModel.swift in Sources */,
7A06E0AE2C7065C7005731AC /* SettingsViewModel.swift in Sources */, 7A06E0AE2C7065C7005731AC /* SettingsViewModel.swift in Sources */,
7AB4E42C2D397D8E0006D052 /* VehicleCellView.swift in Sources */, 7AB4E42C2D397D8E0006D052 /* VehicleCellView.swift in Sources */,
7A91CE9A2DC2470F00DBA953 /* TextFieldDumbModifier.swift in Sources */,
7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */, 7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */,
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */, 7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */,
7AC44B822DB390B900ADC026 /* MainTabScreen.swift in Sources */, 7AC44B822DB390B900ADC026 /* MainTabScreen.swift in Sources */,
@ -1338,7 +1341,6 @@
7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */, 7A7DADAC2D99738300F52F6C /* AudioRecordView.swift in Sources */,
7AB9FE2A2D08CF35005DE374 /* EventsScreenMode.swift in Sources */, 7AB9FE2A2D08CF35005DE374 /* EventsScreenMode.swift in Sources */,
7AB490292D6B1217002F39C6 /* ACKeyboardView.swift in Sources */, 7AB490292D6B1217002F39C6 /* ACKeyboardView.swift in Sources */,
7A1022722C554A1300B84627 /* CustomHostingController.swift in Sources */,
7A1022792C557ED600B84627 /* LocationPickerViewModel.swift in Sources */, 7A1022792C557ED600B84627 /* LocationPickerViewModel.swift in Sources */,
7AF231932DA1C28100AE5EB3 /* AuthScreen.swift in Sources */, 7AF231932DA1C28100AE5EB3 /* AuthScreen.swift in Sources */,
7A1E78F82CE900440004B740 /* ReportViewModel.swift in Sources */, 7A1E78F82CE900440004B740 /* ReportViewModel.swift in Sources */,
@ -1354,6 +1356,7 @@
7AFBE8C42C302561003C491D /* ACHudContainer.swift in Sources */, 7AFBE8C42C302561003C491D /* ACHudContainer.swift in Sources */,
7A06E0AC2C7065AC005731AC /* SettingsScreen.swift in Sources */, 7A06E0AC2C7065AC005731AC /* SettingsScreen.swift in Sources */,
7AF231992DA27C1B00AE5EB3 /* ACButtonView.swift in Sources */, 7AF231992DA27C1B00AE5EB3 /* ACButtonView.swift in Sources */,
7A91CE952DC2422B00DBA953 /* HideTabBarModifier.swift in Sources */,
7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */, 7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */,
7A4955822D58CCF900912E66 /* HistoryFilter.swift in Sources */, 7A4955822D58CCF900912E66 /* HistoryFilter.swift in Sources */,
7A4322912CB2CC8A00085CF6 /* FiltersScreen.swift in Sources */, 7A4322912CB2CC8A00085CF6 /* FiltersScreen.swift in Sources */,
@ -1366,6 +1369,7 @@
7AB9FE222D08C2A5005DE374 /* EventsScreen.swift in Sources */, 7AB9FE222D08C2A5005DE374 /* EventsScreen.swift in Sources */,
7A5911F02D63266B00EC51BA /* SearchViewModel.swift in Sources */, 7A5911F02D63266B00EC51BA /* SearchViewModel.swift in Sources */,
7A589E0F2D6B6E8E00EF3FBE /* NumberEditView.swift in Sources */, 7A589E0F2D6B6E8E00EF3FBE /* NumberEditView.swift in Sources */,
7A91CE982DC243AD00DBA953 /* TitleModeInlineModifier.swift in Sources */,
7A9519802D80B6C100E69883 /* RecordsScreen.swift in Sources */, 7A9519802D80B6C100E69883 /* RecordsScreen.swift in Sources */,
7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */, 7A131FD52D37B76A00DC7755 /* HistoryViewModel.swift in Sources */,
); );
@ -1659,7 +1663,9 @@
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat; PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES; REGISTER_APP_GROUPS = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 6.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
@ -1686,7 +1692,9 @@
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat; PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES; REGISTER_APP_GROUPS = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 6.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
@ -1821,7 +1829,11 @@
MACOSX_DEPLOYMENT_TARGET = 14.6; MACOSX_DEPLOYMENT_TARGET = 14.6;
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCatCore; PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCatCore;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
REGISTER_APP_GROUPS = YES;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG MOCKING"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG MOCKING";
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
SWIFT_VERSION = 6.0; SWIFT_VERSION = 6.0;
@ -1853,7 +1865,11 @@
MACOSX_DEPLOYMENT_TARGET = 14.6; MACOSX_DEPLOYMENT_TARGET = 14.6;
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCatCore; PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCatCore;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
REGISTER_APP_GROUPS = YES;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
SWIFT_VERSION = 6.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
@ -1945,30 +1961,6 @@
minimumVersion = 6.0.0; minimumVersion = 6.0.0;
}; };
}; };
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sindresorhus/ExceptionCatcher";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.1.0;
};
};
7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/pkluz/PKHUD.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 5.4.0;
};
};
7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/huri000/SwiftEntryKit";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.0.0;
};
};
7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */ = { 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Kolos65/Mockable"; repositoryURL = "https://github.com/Kolos65/Mockable";
@ -2005,31 +1997,16 @@
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */; package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
productName = RealmSwift; productName = RealmSwift;
}; };
7A813DC02508C4D900CC93B9 /* ExceptionCatcher */ = {
isa = XCSwiftPackageProductDependency;
package = 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */;
productName = ExceptionCatcher;
};
7AABB1F1267E9CC800D7AB32 /* SwiftDate */ = { 7AABB1F1267E9CC800D7AB32 /* SwiftDate */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */; package = 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */;
productName = SwiftDate; productName = SwiftDate;
}; };
7AABDE1C2532F3EB0041AFC6 /* PKHUD */ = {
isa = XCSwiftPackageProductDependency;
package = 7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */;
productName = PKHUD;
};
7AB5871C2C42C1CF00FA7B66 /* RealmSwift */ = { 7AB5871C2C42C1CF00FA7B66 /* RealmSwift */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */; package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
productName = RealmSwift; productName = RealmSwift;
}; };
7AC355492969652F00889457 /* SwiftEntryKit */ = {
isa = XCSwiftPackageProductDependency;
package = 7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */;
productName = SwiftEntryKit;
};
7ACBB91D2CB9B155005A5168 /* Mockable */ = { 7ACBB91D2CB9B155005A5168 /* Mockable */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */; package = 7ACBB91C2CB9B155005A5168 /* XCRemoteSwiftPackageReference "Mockable" */;

View File

@ -1,5 +1,5 @@
{ {
"originHash" : "9a7838ec160dde976fc2028176dc43038769553e6d8eb4d7d117f851f899baaf", "originHash" : "b26032c73d0741690e860809b31156025c85a200a7d53a64391683433e6a82a4",
"pins" : [ "pins" : [
{ {
"identity" : "clustermap", "identity" : "clustermap",
@ -10,15 +10,6 @@
"version" : "2.1.1" "version" : "2.1.1"
} }
}, },
{
"identity" : "exceptioncatcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/sindresorhus/ExceptionCatcher",
"state" : {
"revision" : "3787f25119e1406b4c5e47fc654626a9d5d7e111",
"version" : "1.1.0"
}
},
{ {
"identity" : "mockable", "identity" : "mockable",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@ -28,15 +19,6 @@
"version" : "0.3.1" "version" : "0.3.1"
} }
}, },
{
"identity" : "pkhud",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pkluz/PKHUD.git",
"state" : {
"revision" : "8fd26f23057c6bebd6695524b1c3e05e93aba571",
"version" : "5.4.0"
}
},
{ {
"identity" : "realm-core", "identity" : "realm-core",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@ -73,15 +55,6 @@
"version" : "6.3.1" "version" : "6.3.1"
} }
}, },
{
"identity" : "swiftentrykit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/huri000/SwiftEntryKit",
"state" : {
"revision" : "5ad36cccf0c4b9fea32f4e9b17a8e38f07563ef0",
"version" : "2.0.0"
}
},
{ {
"identity" : "swiftlocation", "identity" : "swiftlocation",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",

View File

@ -0,0 +1,34 @@
{
"colors" : [
{
"color" : {
"color-space" : "extended-gray",
"components" : {
"alpha" : "1.000",
"white" : "124"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "extended-gray",
"components" : {
"alpha" : "1.000",
"white" : "81"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,6 +1,6 @@
{ {
"info" : { "info" : {
"version" : 1, "author" : "xcode",
"author" : "xcode" "version" : 1
} }
} }

View File

@ -1,6 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "check-37.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "check-54.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "check-51.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "check-75.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "record-47.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "record-69.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "record-63.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "record-93.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "search-35.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "search-51.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "search-47.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "search-69.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "settings-37.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "settings-54.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "settings-51.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "settings-75.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -37,7 +37,7 @@ struct AutoCatApp: App {
@ViewBuilder @ViewBuilder
var mainScreen: some View { var mainScreen: some View {
if UIDevice.isIPhone { if Device.isIPhone {
MainTabScreen() MainTabScreen()
} else { } else {
MainSplitScreen() MainSplitScreen()

View File

@ -6,12 +6,19 @@
// Copyright © 2025 Selim Mustafaev. All rights reserved. // Copyright © 2025 Selim Mustafaev. All rights reserved.
// //
#if canImport(UIKit)
import UIKit import UIKit
#endif
extension UIDevice { @MainActor
struct Device {
static var isIPhone: Bool { static var isIPhone: Bool {
current.userInterfaceIdiom == .phone #if os(macOS)
false
#else
UIDevice.current.userInterfaceIdiom == .phone
#endif
} }
} }

View File

@ -45,7 +45,9 @@ struct AdsScreen: View {
} }
} }
.navigationTitle("Ads") .navigationTitle("Ads")
#if !os(macOS)
.imageSlider($galleryModel) .imageSlider($galleryModel)
#endif
} }
func imageGrid(links: [String]) -> some View { func imageGrid(links: [String]) -> some View {

View File

@ -28,11 +28,15 @@ struct AuthScreen: View {
VStack(spacing: 16) { VStack(spacing: 16) {
Group { Group {
TextField("Email", text: $viewModel.email, prompt: Text("Email")) TextField("Email", text: $viewModel.email, prompt: Text("Email"))
#if !os(macOS)
.keyboardType(.emailAddress) .keyboardType(.emailAddress)
#endif
SecureField("Password", text: $viewModel.password, prompt: Text("Password")) SecureField("Password", text: $viewModel.password, prompt: Text("Password"))
} }
.disableAutocorrection(true) .disableAutocorrection(true)
#if !os(macOS)
.autocapitalization(.none) .autocapitalization(.none)
#endif
.padding(8) .padding(8)
.background { .background {
RoundedRectangle(cornerRadius: 8) RoundedRectangle(cornerRadius: 8)

View File

@ -10,7 +10,7 @@ import SwiftUI
import AutoCatCore import AutoCatCore
import CoreLocation import CoreLocation
import UniformTypeIdentifiers import UniformTypeIdentifiers
import MobileCoreServices //import MobileCoreServices
import MapKit import MapKit
extension UTType { extension UTType {
@ -42,7 +42,11 @@ class EventsViewModel: ACHudContainer {
var onUpdate: (VehicleDto) -> Void var onUpdate: (VehicleDto) -> Void
var isPasteAvailable: Bool { var isPasteAvailable: Bool {
#if os(macOS)
NSPasteboard.general.data(forType: .init(UTType.vehicleEvent.identifier)) != nil
#else
UIPasteboard.general.data(forPasteboardType: UTType.vehicleEvent.identifier) != nil UIPasteboard.general.data(forPasteboardType: UTType.vehicleEvent.identifier) != nil
#endif
} }
var shouldDisplayEventAuthors: Bool { var shouldDisplayEventAuthors: Bool {
@ -174,14 +178,26 @@ class EventsViewModel: ACHudContainer {
let items = sharedData.compactMapValues { $0 } let items = sharedData.compactMapValues { $0 }
if !items.isEmpty { if !items.isEmpty {
#if os(macOS)
NSPasteboard.general.setData(try? JSONEncoder().encode(eventDto), forType: .init(UTType.vehicleEvent.identifier))
if let urlString = getMapLink(for: event)?.absoluteString {
NSPasteboard.general.setString(urlString, forType: .string)
}
#else
UIPasteboard.general.items = [items] UIPasteboard.general.items = [items]
#endif
} }
} }
func confirmPaste() { func confirmPaste() {
guard let data = UIPasteboard.general.data(forPasteboardType: UTType.vehicleEvent.identifier),
var eventDto = try? JSONDecoder().decode(VehicleEventDto.self, from: data) #if os(macOS)
else { let data = NSPasteboard.general.data(forType: .init(UTType.vehicleEvent.identifier))
#else
let data = UIPasteboard.general.data(forPasteboardType: UTType.vehicleEvent.identifier)
#endif
guard let data, var eventDto = try? JSONDecoder().decode(VehicleEventDto.self, from: data) else {
return return
} }
@ -202,13 +218,22 @@ class EventsViewModel: ACHudContainer {
return return
} }
#if os(macOS)
openInMaps(event)
#else
if UIApplication.shared.canOpenURL(url) { if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url) UIApplication.shared.open(url)
} else { } else {
openInMaps(event)
}
#endif
}
func openInMaps(_ event: EventModel) {
let placemark = MKPlacemark(coordinate: event.coordinate) let placemark = MKPlacemark(coordinate: event.coordinate)
let mapItem = MKMapItem(placemark: placemark) let mapItem = MKMapItem(placemark: placemark)
mapItem.name = event.date mapItem.name = event.date
mapItem.openInMaps() mapItem.openInMaps()
} }
} }
}

View File

@ -51,7 +51,7 @@ struct FiltersScreen: View {
ForEach(viewModel.years, id: \.self) { Text($0.text) } ForEach(viewModel.years, id: \.self) { Text($0.text) }
} }
} }
.pickerStyle(.navigationLink) .pickerStyle(.automatic)
Section { Section {
Picker("Added by", selection: $viewModel.filter.addedBy) { Picker("Added by", selection: $viewModel.filter.addedBy) {
@ -114,9 +114,9 @@ struct FiltersScreen: View {
} }
} }
.navigationTitle("Filters") .navigationTitle("Filters")
.navigationBarTitleDisplayMode(.inline) .titleModeInline()
.toolbar { .toolbar {
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .primaryAction) {
Button("Done") { Button("Done") {
viewModel.applyFilters() viewModel.applyFilters()
dismiss() dismiss()
@ -124,7 +124,7 @@ struct FiltersScreen: View {
} }
if horizontalSizeClass == .regular { if horizontalSizeClass == .regular {
ToolbarItem(placement: .topBarLeading) { ToolbarItem(placement: .cancellationAction) {
Button("Close") { Button("Close") {
dismiss() dismiss()
} }
@ -134,6 +134,6 @@ struct FiltersScreen: View {
.task { .task {
await viewModel.loadData() await viewModel.loadData()
} }
.toolbar(.hidden, for: .tabBar) .hideTabBar()
} }
} }

View File

@ -55,7 +55,9 @@ struct GalleryScreen: View {
} }
} }
} }
#if !os(macOS)
.imageSlider($galleryModel) .imageSlider($galleryModel)
#endif
} }
var columns: [GridItem] { var columns: [GridItem] {

View File

@ -9,9 +9,7 @@
import WebKit import WebKit
import SwiftUI import SwiftUI
struct WebView: UIViewRepresentable { class WebViewCoordinator: NSObject, WKNavigationDelegate {
class Coordinator: NSObject, WKNavigationDelegate {
var decidePolicyClosure: ((WKNavigationAction) async -> WKNavigationActionPolicy)? var decidePolicyClosure: ((WKNavigationAction) async -> WKNavigationActionPolicy)?
@ -24,10 +22,44 @@ struct WebView: UIViewRepresentable {
} }
} }
#if os(macOS)
struct WebView: NSViewRepresentable {
let url: URL let url: URL
let userAgent: String? let userAgent: String?
@State private var delegate = Coordinator() @State private var delegate = WebViewCoordinator()
func makeNSView(context: Context) -> WKWebView {
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
return webView
}
func updateNSView(_ webView: WKWebView, context: Context) {
webView.customUserAgent = userAgent
webView.navigationDelegate = context.coordinator
let request = URLRequest(url: url)
webView.load(request)
}
func makeCoordinator() -> WebViewCoordinator {
delegate
}
}
#else
struct WebView: UIViewRepresentable {
let url: URL
let userAgent: String?
@State private var delegate = WebViewCoordinator()
func makeUIView(context: Context) -> WKWebView { func makeUIView(context: Context) -> WKWebView {
@ -45,11 +77,12 @@ struct WebView: UIViewRepresentable {
webView.load(request) webView.load(request)
} }
func makeCoordinator() -> Coordinator { func makeCoordinator() -> WebViewCoordinator {
delegate delegate
} }
} }
#endif
extension WebView { extension WebView {

View File

@ -26,7 +26,7 @@ struct HistoryScreen: View {
ForEach(viewModel.vehicleSections) { section in ForEach(viewModel.vehicleSections) { section in
Section(header: Text(section.header)) { Section(header: Text(section.header)) {
ForEach(section.elements) { vehicle in ForEach(section.elements) { vehicle in
if UIDevice.isIPhone { if Device.isIPhone {
NavigationLink(value: HistoryRoute.localReport(vehicle)) { NavigationLink(value: HistoryRoute.localReport(vehicle)) {
vehicleCell(vehicle) vehicleCell(vehicle)
} }
@ -42,13 +42,12 @@ struct HistoryScreen: View {
} }
.hud($viewModel.hud) .hud($viewModel.hud)
.listStyle(.plain) .listStyle(.plain)
.navigationBarTitleDisplayMode(.inline) .titleModeInline()
.navigationTitle(String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""), .navigationTitle(String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""),
viewModel.vehiclesCount)) viewModel.vehiclesCount))
.searchable(text: $viewModel.searchText, prompt: "Search plate numbers") .searchable(text: $viewModel.searchText, prompt: "Search plate numbers")
.searchPresentationToolbarBehavior(.avoidHidingContent) .searchPresentationToolbarBehavior(.avoidHidingContent)
.autocorrectionDisabled() .makeTextFieldDumb()
.textInputAutocapitalization(.never)
.toolbar { .toolbar {
ToolbarItem(placement: .primaryAction) { ToolbarItem(placement: .primaryAction) {
Button("", systemImage: "square.and.arrow.up") { Button("", systemImage: "square.and.arrow.up") {

View File

@ -145,7 +145,7 @@ final class HistoryViewModel: ACHudContainer {
if errors.isEmpty { if errors.isEmpty {
hud = nil hud = nil
if !vehicle.unrecognized { if !vehicle.unrecognized {
if UIDevice.isIPhone { if Device.isIPhone {
Router.shared.openLocalReport(vehicle: vehicle) Router.shared.openLocalReport(vehicle: vehicle)
} else { } else {
selectedVehicleId = vehicle.id selectedVehicleId = vehicle.id
@ -204,7 +204,7 @@ final class HistoryViewModel: ACHudContainer {
guard let self else { return } guard let self else { return }
let vehicle = try await apiService.getReport(for: number) let vehicle = try await apiService.getReport(for: number)
if UIDevice.isIPhone { if Device.isIPhone {
Router.shared.openSharedReport(vehicle: vehicle) Router.shared.openSharedReport(vehicle: vehicle)
} else { } else {
vehicleToOpen = vehicle vehicleToOpen = vehicle

View File

@ -112,7 +112,7 @@ struct MainSplitScreen: View {
} }
} }
} }
.toolbar(.visible, for: .navigationBar) //.toolbar(.visible, for: .navigationBar)
} }
@ViewBuilder @ViewBuilder

View File

@ -7,8 +7,6 @@
// //
import SwiftUI import SwiftUI
import UIKit
import SwiftEntryKit
import AutoCatCore import AutoCatCore
struct MainTabScreen: View { struct MainTabScreen: View {

View File

@ -40,7 +40,7 @@ struct MapScreen: View {
} }
.hud($viewModel.hud) .hud($viewModel.hud)
.navigationTitle(viewModel.title) .navigationTitle(viewModel.title)
.navigationBarTitleDisplayMode(.inline) .titleModeInline()
.readSize { newValue in .readSize { newValue in
viewModel.mapSize = newValue viewModel.mapSize = newValue
} }
@ -54,13 +54,13 @@ struct MapScreen: View {
} }
.toolbar { .toolbar {
if horizontalSizeClass == .regular { if horizontalSizeClass == .regular {
ToolbarItem(placement: .topBarLeading) { ToolbarItem(placement: .cancellationAction) {
Button("Close") { Button("Close") {
dismiss() dismiss()
} }
} }
} }
} }
.toolbar(.hidden, for: .tabBar) .hideTabBar()
} }
} }

View File

@ -50,7 +50,7 @@ struct NotesScreen: View {
} }
.listStyle(.inset) .listStyle(.inset)
.navigationTitle("Notes") .navigationTitle("Notes")
.navigationBarTitleDisplayMode(.inline) .titleModeInline()
.toolbar { .toolbar {
ToolbarItem(placement: .primaryAction) { ToolbarItem(placement: .primaryAction) {
Button { Button {

View File

@ -8,9 +8,16 @@
import Foundation import Foundation
import AutoCatCore import AutoCatCore
import UIKit
import UniformTypeIdentifiers import UniformTypeIdentifiers
#if canImport(UIKit)
import UIKit
#endif
#if canImport(AppKit)
import AppKit
#endif
@MainActor @MainActor
@Observable @Observable
class NotesViewModel: ACHudContainer { class NotesViewModel: ACHudContainer {
@ -89,7 +96,11 @@ class NotesViewModel: ACHudContainer {
func copyNote(_ note: VehicleNoteDto) { func copyNote(_ note: VehicleNoteDto) {
#if !os(macOS)
UIPasteboard.general.setValue(note.text, UIPasteboard.general.setValue(note.text,
forPasteboardType: UTType.plainText.identifier) forPasteboardType: UTType.plainText.identifier)
#else
NSPasteboard.general.setString(note.text, forType: .string)
#endif
} }
} }

View File

@ -47,7 +47,7 @@ struct RecordsScreen: View {
.listStyle(.inset) .listStyle(.inset)
.hud($viewModel.hud) .hud($viewModel.hud)
.navigationTitle("Voice records") .navigationTitle("Voice records")
.navigationBarTitleDisplayMode(.inline) .titleModeInline()
.onAppear { .onAppear {
Task { await viewModel.onAppear() } Task { await viewModel.onAppear() }
} }

View File

@ -148,7 +148,7 @@ struct ReportScreen: View {
GalleryScreen(photos: viewModel.vehicle.photos) GalleryScreen(photos: viewModel.vehicle.photos)
} }
} }
.toolbar(.hidden, for: .tabBar) .hideTabBar()
} }
@ViewBuilder @ViewBuilder

View File

@ -35,9 +35,8 @@ struct SearchScreen: View {
.hud($viewModel.hud) .hud($viewModel.hud)
.searchable(text: $viewModel.searchText, prompt: "Search plate numbers") .searchable(text: $viewModel.searchText, prompt: "Search plate numbers")
.searchPresentationToolbarBehavior(.avoidHidingContent) .searchPresentationToolbarBehavior(.avoidHidingContent)
.disableAutocorrection(true) .makeTextFieldDumb()
.autocapitalization(.none) .titleModeInline()
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""), .navigationTitle(String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""),
viewModel.vehiclesCount)) viewModel.vehiclesCount))
.onAppear { .onAppear {
@ -47,7 +46,7 @@ struct SearchScreen: View {
Task { await viewModel.reloadData() } Task { await viewModel.reloadData() }
} }
.toolbar { .toolbar {
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .primaryAction) {
toolbarMenu toolbarMenu
} }
} }
@ -68,7 +67,7 @@ struct SearchScreen: View {
ForEach(viewModel.vehicleSections) { section in ForEach(viewModel.vehicleSections) { section in
Section(header: Text(section.header)) { Section(header: Text(section.header)) {
ForEach(section.elements) { vehicle in ForEach(section.elements) { vehicle in
if UIDevice.isIPhone { if Device.isIPhone {
NavigationLink(value: vehicle) { NavigationLink(value: vehicle) {
vehicleCell(vehicle) vehicleCell(vehicle)
} }

View File

@ -80,7 +80,7 @@ struct SettingsScreen: View {
} }
} }
.navigationTitle("Settings") .navigationTitle("Settings")
.navigationBarTitleDisplayMode(.inline) .titleModeInline()
.confirmationDialog(viewModel.googleUsername ?? "", .confirmationDialog(viewModel.googleUsername ?? "",
isPresented: $googleSheetOpened, isPresented: $googleSheetOpened,
titleVisibility: .visible) { titleVisibility: .visible) {

View File

@ -1,27 +0,0 @@
//
// CustomHostingController.swift
// AutoCat
//
// Created by Selim Mustafaev on 27.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import UIKit
import SwiftUI
final class CustomHostingController<T: View>: UIHostingController<T> {
var continuation: CheckedContinuation<Void, Never>?
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if isMovingFromParent || isBeingDismissed {
continuation?.resume()
}
}
func waitForDisappear() async {
await withCheckedContinuation { continuation = $0 }
}
}

View File

@ -0,0 +1,30 @@
//
// HideTabBarModifier.swift
// AutoCat
//
// Created by Selim Mustafaev on 30.04.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct HideTabBarModifier: ViewModifier {
func body(content: Content) -> some View {
#if os(macOS)
content
#else
content
.toolbar(.hidden, for: .tabBar)
#endif
}
}
extension View {
func hideTabBar() -> some View {
modifier(HideTabBarModifier())
}
}

View File

@ -0,0 +1,32 @@
//
// TextFieldDumbModifier.swift
// AutoCat
//
// Created by Selim Mustafaev on 30.04.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct TextFieldDumbModifier: ViewModifier {
func body(content: Content) -> some View {
#if os(macOS)
content
.disableAutocorrection(true)
#else
content
.disableAutocorrection(true)
.autocapitalization(.none)
#endif
}
}
extension View {
func makeTextFieldDumb() -> some View {
modifier(TextFieldDumbModifier())
}
}

View File

@ -0,0 +1,30 @@
//
// TitleModeInlineModifier.swift
// AutoCat
//
// Created by Selim Mustafaev on 30.04.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct TitleModeInlineModifier: ViewModifier {
func body(content: Content) -> some View {
#if os(macOS)
content
#else
content
.navigationBarTitleDisplayMode(.inline)
#endif
}
}
extension View {
func titleModeInline() -> some View {
modifier(TitleModeInlineModifier())
}
}

View File

@ -19,7 +19,6 @@ struct NumberEditView: View {
VStack(spacing: 16) { VStack(spacing: 16) {
Text("Check number") Text("Check number")
.font(.headline) .font(.headline)
//.padding(.top, 24)
HStack(spacing: 16) { HStack(spacing: 16) {
LicensePlateView(number: number, foreground: .primary) LicensePlateView(number: number, foreground: .primary)

View File

@ -6,7 +6,15 @@
// Copyright © 2025 Selim Mustafaev. All rights reserved. // Copyright © 2025 Selim Mustafaev. All rights reserved.
// //
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if canImport(AppKit)
import AppKit
#endif
#if !os(macOS)
extension UISearchTextField { extension UISearchTextField {
@ -22,3 +30,5 @@ extension UISearchTextField {
} }
} }
} }
#endif

View File

@ -61,9 +61,9 @@ struct VehicleCellView: View {
func getForegroundColor() -> Color { func getForegroundColor() -> Color {
if vehicle.unrecognized { if vehicle.unrecognized {
Color(UIColor.systemRed) .red
} else if vehicle.outdated { } else if vehicle.outdated {
Color(UIColor.systemGray3) Color("PlateForegroundGray")
} else { } else {
Color("PlateForeground") Color("PlateForeground")
} }

View File

@ -66,8 +66,10 @@ extension AudioRecordService: AudioRecordServiceProtocol {
throw AudioRecordError.unknown throw AudioRecordError.unknown
} }
#if !os(macOS)
try AVAudioSession.sharedInstance().setCategory(.playAndRecord) try AVAudioSession.sharedInstance().setCategory(.playAndRecord)
try AVAudioSession.sharedInstance().setActive(true) try AVAudioSession.sharedInstance().setActive(true)
#endif
recorder = try AVAudioRecorder(url: url, settings: audioFileSettings) recorder = try AVAudioRecorder(url: url, settings: audioFileSettings)
recorder?.record() recorder?.record()

View File

@ -33,11 +33,14 @@ public final class RecordPlayerService: NSObject {
activateProgressTimer() activateProgressTimer()
self.onProgress = onProgress self.onProgress = onProgress
#if !os(macOS)
try activateSession() try activateSession()
#endif
player?.play() player?.play()
} }
#if !os(macOS)
func activateSession() throws { func activateSession() throws {
try AVAudioSession.sharedInstance().setCategory( try AVAudioSession.sharedInstance().setCategory(
.playback, .playback,
@ -53,6 +56,7 @@ public final class RecordPlayerService: NSObject {
options: .notifyOthersOnDeactivation options: .notifyOthersOnDeactivation
) )
} }
#endif
func activateProgressTimer() { func activateProgressTimer() {
@ -87,9 +91,13 @@ extension RecordPlayerService: RecordPlayerServiceProtocol {
if player.isPlaying { if player.isPlaying {
player.pause() player.pause()
deactivateProgressTimer() deactivateProgressTimer()
#if !os(macOS)
try deactivateSession() try deactivateSession()
#endif
} else { } else {
#if !os(macOS)
try activateSession() try activateSession()
#endif
activateProgressTimer() activateProgressTimer()
player.play() player.play()
} }
@ -131,6 +139,8 @@ extension RecordPlayerService: AVAudioPlayerDelegate {
record = nil record = nil
deactivateProgressTimer() deactivateProgressTimer()
#if !os(macOS)
try? deactivateSession() try? deactivateSession()
#endif
} }
} }