Replacing ads controller with SwiftUI version

This commit is contained in:
Selim Mustafaev 2024-07-27 12:34:51 +03:00
parent 01bd7b2f87
commit 44c28e912d
16 changed files with 661 additions and 169 deletions

View File

@ -37,7 +37,6 @@
7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */; };
7A27ADF7249FEF690035F39E /* Recorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF6249FEF690035F39E /* Recorder.swift */; };
7A2C96122C3B155B00AE46B5 /* NoteAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2C96112C3B155B00AE46B5 /* NoteAlertModifier.swift */; };
7A2DE69B25869ABD00A113FC /* AdsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2DE69A25869ABD00A113FC /* AdsController.swift */; };
7A2DE69E2589606A00A113FC /* ImageGridRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2DE69D2589606A00A113FC /* ImageGridRow.swift */; };
7A2E6FA72C42B3AD00C40DA7 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; };
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A33381024990DAE00D878F1 /* FiltersController.swift */; };
@ -90,6 +89,9 @@
7A7158042C43EAA200852088 /* OwnersCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158032C43EAA200852088 /* OwnersCoordinator.swift */; };
7A7158072C44085600852088 /* OsagoScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158062C44085600852088 /* OsagoScreen.swift */; };
7A7158092C44087E00852088 /* OsagoCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158082C44087E00852088 /* OsagoCoordinator.swift */; };
7A71580C2C44453200852088 /* AdsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A71580B2C44453200852088 /* AdsScreen.swift */; };
7A71580E2C4445A200852088 /* AdsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A71580D2C4445A200852088 /* AdsCoordinator.swift */; };
7A7158122C444A6400852088 /* AdsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7158112C444A6400852088 /* AdsViewModel.swift */; };
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */; };
7A761C042677F18E0005F28F /* ApiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474323FF06CA00B424AF /* ApiService.swift */; };
7A761C052677F1BC0005F28F /* CocoaError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF824A09CAD0035F39E /* CocoaError.swift */; };
@ -108,6 +110,8 @@
7A8AB76B25A1D95500ECF2C1 /* SourceStatusRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8AB76A25A1D95500ECF2C1 /* SourceStatusRow.swift */; };
7A8C4A5B2C1C55680052DDF3 /* SwiftLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 7A8C4A5A2C1C55680052DDF3 /* SwiftLocation */; };
7A91894F29A2BD8700519C74 /* GestureRecognizers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A91894E29A2BD8700519C74 /* GestureRecognizers.swift */; };
7A961C6C2C4C3C8600CE2211 /* TextRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A961C6B2C4C3C8600CE2211 /* TextRowView.swift */; };
7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A961C6D2C4C3C9E00CE2211 /* LinkRowView.swift */; };
7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */; };
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A96AE2E246B2BCD00297C33 /* WebKit.framework */; };
7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A99406326E4BFAE002E9CB6 /* VehicleNoteCell.swift */; };
@ -116,6 +120,10 @@
7AA7BC3325A5DFB80053A5D5 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D332402A91C00CE01A0 /* Kingfisher */; };
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; };
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABDE1C2532F3EB0041AFC6 /* PKHUD */; };
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFAD22C4D0FD00050410D /* ACImageSliderView.swift */; };
7AAAFADA2C4D1AFE0050410D /* Zoomable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFAD92C4D1AFE0050410D /* Zoomable.swift */; };
7AAAFADC2C4D1E130050410D /* ACImageSliderView+Modifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFADB2C4D1E130050410D /* ACImageSliderView+Modifier.swift */; };
7AAAFADE2C4D23620050410D /* ACImageSliderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAAFADD2C4D23620050410D /* ACImageSliderModel.swift */; };
7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABB1F1267E9CC800D7AB32 /* SwiftDate */; };
7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */; };
7AB5871D2C42C1CF00FA7B66 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7AB5871C2C42C1CF00FA7B66 /* RealmSwift */; };
@ -167,7 +175,6 @@
7AF6D22A2677C3AD0086EA64 /* Exportable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE8424D26109F78002F6B31 /* Exportable.swift */; };
7AFBE8C02C3024E5003C491D /* ACHud.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE8BF2C3024E5003C491D /* ACHud.swift */; };
7AFBE8C42C302561003C491D /* ACHudContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE8C32C302561003C491D /* ACHudContainer.swift */; };
7AFBE8C82C30816E003C491D /* ACProgressHud.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE8C72C30816E003C491D /* ACProgressHud.swift */; };
7AFBE8CA2C3081C7003C491D /* ACProgressHud+Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE8C92C3081C7003C491D /* ACProgressHud+Modifiers.swift */; };
7AFBE8CC2C3085C6003C491D /* ACProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE8CB2C3085C6003C491D /* ACProgressView.swift */; };
7AFBE8CE2C308B53003C491D /* ACMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE8CD2C308B53003C491D /* ACMessageView.swift */; };
@ -264,7 +271,6 @@
7A27ADF824A09CAD0035F39E /* CocoaError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CocoaError.swift; sourceTree = "<group>"; };
7A2C96112C3B155B00AE46B5 /* NoteAlertModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteAlertModifier.swift; sourceTree = "<group>"; };
7A2DE69725868AC800A113FC /* VehicleAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleAd.swift; sourceTree = "<group>"; };
7A2DE69A25869ABD00A113FC /* AdsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsController.swift; sourceTree = "<group>"; };
7A2DE69D2589606A00A113FC /* ImageGridRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGridRow.swift; sourceTree = "<group>"; };
7A2E6FA32C42B3AD00C40DA7 /* AutoCatCoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutoCatCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
7A33381024990DAE00D878F1 /* FiltersController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersController.swift; sourceTree = "<group>"; };
@ -328,6 +334,9 @@
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>"; };
7A7158082C44087E00852088 /* OsagoCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsagoCoordinator.swift; sourceTree = "<group>"; };
7A71580B2C44453200852088 /* AdsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsScreen.swift; sourceTree = "<group>"; };
7A71580D2C4445A200852088 /* AdsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsCoordinator.swift; sourceTree = "<group>"; };
7A7158112C444A6400852088 /* AdsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsViewModel.swift; sourceTree = "<group>"; };
7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehiclePhotoCell.swift; sourceTree = "<group>"; };
7A761C0A267E8FF90005F28F /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; };
7A813DBD2506A57100CC93B9 /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/AuthenticationServices.framework; sourceTree = DEVELOPER_DIR; };
@ -342,12 +351,18 @@
7A8AB76A25A1D95500ECF2C1 /* SourceStatusRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceStatusRow.swift; sourceTree = "<group>"; };
7A91894E29A2BD8700519C74 /* GestureRecognizers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureRecognizers.swift; sourceTree = "<group>"; };
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; };
7A961C6B2C4C3C8600CE2211 /* TextRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRowView.swift; sourceTree = "<group>"; };
7A961C6D2C4C3C9E00CE2211 /* LinkRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkRowView.swift; sourceTree = "<group>"; };
7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleSignInController.swift; sourceTree = "<group>"; };
7A96AE2E246B2BCD00297C33 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
7A96AE30246B2FE400297C33 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
7A96AE32246C095700297C33 /* Base64FS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base64FS.swift; sourceTree = "<group>"; };
7A99406326E4BFAE002E9CB6 /* VehicleNoteCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleNoteCell.swift; sourceTree = "<group>"; };
7A9FEEC72529AB23001CA50E /* RxRealmDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxRealmDataSource.swift; sourceTree = "<group>"; };
7AAAFAD22C4D0FD00050410D /* ACImageSliderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACImageSliderView.swift; sourceTree = "<group>"; };
7AAAFAD92C4D1AFE0050410D /* Zoomable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zoomable.swift; sourceTree = "<group>"; };
7AAAFADB2C4D1E130050410D /* ACImageSliderView+Modifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ACImageSliderView+Modifier.swift"; sourceTree = "<group>"; };
7AAAFADD2C4D23620050410D /* ACImageSliderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACImageSliderModel.swift; sourceTree = "<group>"; };
7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxSectionedDataSource.swift; sourceTree = "<group>"; };
7AAE6AD224CDDF950023860B /* VehicleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleEvent.swift; sourceTree = "<group>"; };
7AB562B9249C9E9B00473D53 /* VehicleRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleRegion.swift; sourceTree = "<group>"; };
@ -383,7 +398,6 @@
7AF6D1F22677C03B0086EA64 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7AFBE8BF2C3024E5003C491D /* ACHud.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACHud.swift; sourceTree = "<group>"; };
7AFBE8C32C302561003C491D /* ACHudContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACHudContainer.swift; sourceTree = "<group>"; };
7AFBE8C72C30816E003C491D /* ACProgressHud.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACProgressHud.swift; sourceTree = "<group>"; };
7AFBE8C92C3081C7003C491D /* ACProgressHud+Modifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ACProgressHud+Modifiers.swift"; sourceTree = "<group>"; };
7AFBE8CB2C3085C6003C491D /* ACProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACProgressView.swift; sourceTree = "<group>"; };
7AFBE8CD2C308B53003C491D /* ACMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACMessageView.swift; sourceTree = "<group>"; };
@ -506,7 +520,6 @@
isa = PBXGroup;
children = (
7A813DC7250B5C6E00CC93B9 /* Location */,
7A2DE69A25869ABD00A113FC /* AdsController.swift */,
7A11471923FE839000B424AF /* AuthController.swift */,
7A530B7924001D3300CBFE6E /* CheckController.swift */,
7A33381024990DAE00D878F1 /* FiltersController.swift */,
@ -580,6 +593,7 @@
7A1441632C297E9800E79018 /* Screens */ = {
isa = PBXGroup;
children = (
7A71580A2C44451B00852088 /* AdsScreen */,
7A7158052C44083F00852088 /* OsagoScreen */,
7A7157FE2C43EA5200852088 /* OwnersScreen */,
7A1441642C297EA800E79018 /* NotesScreen */,
@ -750,6 +764,16 @@
path = OsagoScreen;
sourceTree = "<group>";
};
7A71580A2C44451B00852088 /* AdsScreen */ = {
isa = PBXGroup;
children = (
7A71580B2C44453200852088 /* AdsScreen.swift */,
7A71580D2C4445A200852088 /* AdsCoordinator.swift */,
7A7158112C444A6400852088 /* AdsViewModel.swift */,
);
path = AdsScreen;
sourceTree = "<group>";
};
7A761C06267E8E720005F28F /* ThirdParty */ = {
isa = PBXGroup;
children = (
@ -772,6 +796,16 @@
path = Location;
sourceTree = "<group>";
};
7AAAFAD12C4D0FB00050410D /* ACImageSlider */ = {
isa = PBXGroup;
children = (
7AAAFAD22C4D0FD00050410D /* ACImageSliderView.swift */,
7AAAFADB2C4D1E130050410D /* ACImageSliderView+Modifier.swift */,
7AAAFADD2C4D23620050410D /* ACImageSliderModel.swift */,
);
path = ACImageSlider;
sourceTree = "<group>";
};
7AB587302C42D35900FA7B66 /* StorageService */ = {
isa = PBXGroup;
children = (
@ -870,7 +904,11 @@
7AFBE8C52C30812E003C491D /* SwiftUI */ = {
isa = PBXGroup;
children = (
7AAAFAD12C4D0FB00050410D /* ACImageSlider */,
7AFBE8C62C30814E003C491D /* ACProgressHud */,
7A961C6B2C4C3C8600CE2211 /* TextRowView.swift */,
7A961C6D2C4C3C9E00CE2211 /* LinkRowView.swift */,
7AAAFAD92C4D1AFE0050410D /* Zoomable.swift */,
);
path = SwiftUI;
sourceTree = "<group>";
@ -880,7 +918,6 @@
children = (
7AFBE8BF2C3024E5003C491D /* ACHud.swift */,
7AFBE8C32C302561003C491D /* ACHudContainer.swift */,
7AFBE8C72C30816E003C491D /* ACProgressHud.swift */,
7AFBE8C92C3081C7003C491D /* ACProgressHud+Modifiers.swift */,
7AFBE8CB2C3085C6003C491D /* ACProgressView.swift */,
7AFBE8CD2C308B53003C491D /* ACMessageView.swift */,
@ -1103,24 +1140,24 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7A961C6C2C4C3C8600CE2211 /* TextRowView.swift in Sources */,
7AEFC3BE2529D3CC00BADFB2 /* ConfigurableCell.swift in Sources */,
7A7158092C44087E00852088 /* OsagoCoordinator.swift in Sources */,
7A1441662C297EDE00E79018 /* NotesScreen.swift in Sources */,
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
7A813DC9250B5C9700CC93B9 /* LocationRow.swift in Sources */,
7A3399AB299063370087DF98 /* SearchControllerExt.swift in Sources */,
7A2DE69B25869ABD00A113FC /* AdsController.swift in Sources */,
7A14416E2C297F7C00E79018 /* Coordinator.swift in Sources */,
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */,
7A8AB76B25A1D95500ECF2C1 /* SourceStatusRow.swift in Sources */,
7AFBE8C82C30816E003C491D /* ACProgressHud.swift in Sources */,
7AC3554C29696A1C00889457 /* MainTabController.swift in Sources */,
7A813DC32508EE4F00CC93B9 /* EventCell.swift in Sources */,
7A1441682C297EFD00E79018 /* NotesViewModel.swift in Sources */,
7AFBE8C02C3024E5003C491D /* ACHud.swift in Sources */,
7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */,
7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */,
7AAAFADA2C4D1AFE0050410D /* Zoomable.swift in Sources */,
7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */,
7A761C0B267E8FF90005F28F /* Error.swift in Sources */,
7AC3555029696D5A00889457 /* NewNumberController.swift in Sources */,
@ -1131,16 +1168,20 @@
7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */,
7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */,
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */,
7A961C6E2C4C3C9E00CE2211 /* LinkRowView.swift in Sources */,
7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */,
7A3E30F32C18840600567704 /* ActivityItemSource.swift in Sources */,
7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */,
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */,
7AC3554E29696C4500889457 /* DummyNewController.swift in Sources */,
7A7158122C444A6400852088 /* AdsViewModel.swift in Sources */,
7A659B5B24A3768A0043A0F2 /* Substrings.swift in Sources */,
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */,
7A71580E2C4445A200852088 /* AdsCoordinator.swift in Sources */,
7AFBE8CA2C3081C7003C491D /* ACProgressHud+Modifiers.swift in Sources */,
7A27ADF7249FEF690035F39E /* Recorder.swift in Sources */,
7A7158072C44085600852088 /* OsagoScreen.swift in Sources */,
7AAAFAD32C4D0FD00050410D /* ACImageSliderView.swift in Sources */,
7A3F07AB24360DC800E59687 /* Dated.swift in Sources */,
7A33381124990DAE00D878F1 /* FiltersController.swift in Sources */,
7AC76D7B270083AE0084DB27 /* TextView.swift in Sources */,
@ -1166,17 +1207,20 @@
7A14416C2C297F2100E79018 /* NotesCoordinator.swift in Sources */,
7A813DCB250B5DC900CC93B9 /* LocationPickerController.swift in Sources */,
7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */,
7AAAFADE2C4D23620050410D /* ACImageSliderModel.swift in Sources */,
7A8AB76525A0DB8F00ECF2C1 /* BundleVersion.swift in Sources */,
7AC3555229696E3F00889457 /* UIView+layout.swift in Sources */,
7AC355592969746600889457 /* UIControl.swift in Sources */,
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */,
7AC35554296973E100889457 /* ACButton.swift in Sources */,
7AAAFADC2C4D1E130050410D /* ACImageSliderView+Modifier.swift in Sources */,
7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */,
7AFBE8C42C302561003C491D /* ACHudContainer.swift in Sources */,
7AC3555B296995B200889457 /* UIEdgeInsets.swift in Sources */,
7A7158002C43EA6900852088 /* OwnersScreen.swift in Sources */,
7A1441702C2998B200E79018 /* Formatters.swift in Sources */,
7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */,
7A71580C2C44453200852088 /* AdsScreen.swift in Sources */,
7A91894F29A2BD8700519C74 /* GestureRecognizers.swift in Sources */,
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */,
7AFBE8CC2C3085C6003C491D /* ACProgressView.swift in Sources */,
@ -1457,7 +1501,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 125;
CURRENT_PROJECT_VERSION = 127;
DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
@ -1483,7 +1527,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 125;
CURRENT_PROJECT_VERSION = 127;
DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;

View File

@ -1,114 +0,0 @@
import UIKit
import Eureka
import Kingfisher
import SafariServices
import AutoCatCore
class AdsController: FormViewController, MediaBrowserViewControllerDataSource {
var ads: [VehicleAdDto] = []
private var currentAd: VehicleAdDto?
override func viewDidLoad() {
super.viewDidLoad()
self.title = NSLocalizedString("Ads", comment: "")
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
for ad in ads {
let date = Date(timeIntervalSince1970: ad.date)
let section = Section(formatter.string(from: date))
self.form +++ section
if let price = ad.price {
section <<< LabelRow() { row in
row.title = NSLocalizedString("Price", comment: "")
row.value = price
}
}
if let mileage = ad.mileage, mileage != "0" {
section <<< LabelRow() { row in
row.title = NSLocalizedString("Mileage", comment: "")
row.value = mileage
}
}
if let region = ad.region {
section <<< LabelRow() { row in
row.title = NSLocalizedString("Region", comment: "")
row.value = region
}
}
if let city = ad.city {
section <<< LabelRow() { row in
row.title = NSLocalizedString("City", comment: "")
row.value = city
}
}
// if let description = ad.adDescription, !description.isEmpty {
// section <<< MultilineLabelRow() { row in
// row.title = NSLocalizedString("Description", comment: "")
// row.value = description
// }
// }
//
// if let urlStr = ad.url, let url = URL(string: urlStr) {
// section <<< MultilineLinkRow() { row in
// row.title = NSLocalizedString("Link", comment: "")
// row.value = urlStr
// }
// .onCellSelection { _, _ in
// let safari = SFSafariViewController(url: url)
// self.present(safari, animated: true)
// }
// }
if !ad.photos.isEmpty {
section <<< ImageGridRow() { row in
row.value = ad.photos
}
.onDidSelected { index in
self.currentAd = ad
let mediaBrowser = MediaBrowserViewController(index: index, dataSource: self, delegate: nil)
mediaBrowser.shouldShowTitle = false
self.present(mediaBrowser, animated: true, completion: nil)
}
}
}
}
// MARK: - MediaBrowserViewControllerDataSource
func numberOfItems(in mediaBrowser: MediaBrowserViewController) -> Int {
guard let images = self.currentAd?.photos else { return 0 }
return images.count
}
func mediaBrowser(_ mediaBrowser: MediaBrowserViewController, imageAt index: Int, completion: @escaping MediaBrowserViewControllerDataSource.CompletionBlock) {
guard let images = self.currentAd?.photos, let url = URL(string: images[index]) else {
completion(index, nil, ZoomScale.default, NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Image not found"]))
return
}
KingfisherManager.shared.retrieveImage(with: url) { result in
Task { @MainActor in
switch result {
case .success(let res):
completion(index, res.image, ZoomScale.default, nil)
break
case .failure(let error):
completion(index, nil, ZoomScale.default, error)
break
}
}
}
}
}

View File

@ -129,9 +129,14 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
}
.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
.onCellSelection { _, row in
let controller = AdsController()
controller.ads = self.vehicle?.ads ?? []
self.navigationController?.pushViewController(controller, animated: true)
// let controller = AdsController()
// controller.ads = self.vehicle?.ads ?? []
// self.navigationController?.pushViewController(controller, animated: true)
if let ads = self.vehicle?.ads, let navController = self.navigationController {
let coordinator = AdsCoordinator(navController: navController, ads: ads)
Task { try await coordinator.start() }
}
}
<<< LabelRow("Notes") { row in

View File

@ -0,0 +1,30 @@
//
// AdsCoordinator.swift
// AutoCat
//
// Created by Selim Mustafaev on 14.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import UIKit
import SwiftUI
import AutoCatCore
class AdsCoordinator: Coordinator {
let viewController: UINavigationController?
let ads: [VehicleAdDto]
init(navController: UINavigationController, ads: [VehicleAdDto]) {
self.viewController = navController
self.ads = ads
}
func start() async throws {
let viewModel = await AdsViewModel(ads: ads)
let controller = await UIHostingController(rootView: AdsScreen(viewModel: viewModel))
await viewController?.pushViewController(controller, animated: true)
}
}

View File

@ -0,0 +1,74 @@
//
// AdsScreen.swift
// AutoCat
//
// Created by Selim Mustafaev on 14.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct AdsScreen: View {
@StateObject var viewModel: AdsViewModel
@State var galleryModel: ACImageSliderModel?
var body: some View {
List(viewModel.ads) { ad in
Section(viewModel.dateStringFrom(ad.date)) {
if let price = ad.price {
TextRowView(title: "Price", value: price)
}
if let mileage = ad.mileage {
TextRowView(title: "Mileage", value: mileage)
}
if let region = ad.region {
TextRowView(title: "Region", value: region)
}
if let city = ad.city {
TextRowView(title: "City", value: city)
}
if let description = ad.adDescription, !description.isEmpty {
TextRowView(title: "Description", value: description)
}
if let link = ad.url {
LinkRowView(title: "Link", value: link)
}
imageGrid(links: ad.photos)
}
}
.navigationTitle("Ads")
.imageSlider($galleryModel)
}
func imageGrid(links: [String]) -> some View {
let urls = links.compactMap(URL.init(string:))
let columns = [
GridItem(spacing: 8),
GridItem(spacing: 8),
GridItem(spacing: 8)
]
return LazyVGrid(columns: columns, spacing: 8) {
ForEach(urls, id: \.self) { url in
AsyncImage(url: url) { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
ProgressView()
}
.onTapGesture {
galleryModel = ACImageSliderModel(urls: urls, selected: url)
}
}
}
}
}
#Preview {
AdsScreen(viewModel: AdsViewModel(ads: []))
}

View File

@ -0,0 +1,32 @@
//
// AdsViewModel.swift
// AutoCat
//
// Created by Selim Mustafaev on 14.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import Foundation
import AutoCatCore
@MainActor
class AdsViewModel: ObservableObject {
let ads: [VehicleAdDto]
let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
return formatter
}()
init(ads: [VehicleAdDto]) {
self.ads = ads
}
func dateStringFrom(_ timestamp: TimeInterval) -> String {
let date = Date(timeIntervalSince1970: timestamp)
return formatter.string(from: date)
}
}

View File

@ -0,0 +1,20 @@
//
// ACImageSliderModel.swift
// AutoCat
//
// Created by Selim Mustafaev on 21.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import Foundation
struct ACImageSliderModel {
let urls: [URL]
let selected: URL
}
extension ACImageSliderModel: Identifiable {
var id: URL { selected }
}

View File

@ -0,0 +1,32 @@
//
// ACImageSliderView+Modifier.swift
// AutoCat
//
// Created by Selim Mustafaev on 21.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct ACImageSliderViewModifier: ViewModifier {
@Binding var model: ACImageSliderModel?
func body(content: Content) -> some View {
content
.fullScreenCover(item: $model) { model in
ACImageSliderView(urls: model.urls, selected: model.selected)
}
// .transaction { transaction in
// transaction.disablesAnimations = true
// }
}
}
extension View {
func imageSlider(_ model: Binding<ACImageSliderModel?>) -> some View {
modifier(ACImageSliderViewModifier(model: model))
}
}

View File

@ -0,0 +1,71 @@
//
// ACImageSliderView.swift
// AutoCat
//
// Created by Selim Mustafaev on 21.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct ACImageSliderView: View {
@Environment(\.dismiss) var dismiss
let urls: [URL]
let initialUrl: URL
@State var selection: URL?
init(urls: [URL], selected: URL) {
self.urls = urls
self.initialUrl = selected
}
var body: some View {
ZStack(alignment: .topTrailing) {
ZStack {
TabView(selection: $selection) {
ForEach(urls, id: \.self) { url in
AsyncImage(url: url) { image in
image
.resizable()
.scaledToFit()
.zoomable()
.ignoresSafeArea()
} placeholder: {
ProgressView()
}
.tag(url)
}
}
.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
.onAppear {
selection = initialUrl
}
}
.ignoresSafeArea()
Button {
dismiss()
} label: {
Image(systemName: "xmark.circle.fill")
.resizable()
.tint(.gray)
.frame(width: 32, height: 32)
.padding()
}
}
}
}
#Preview {
let urls = [
"https://s.nomerogram.ru/photo/anc_MawzZ3O_hl7no_eB9gbm0-WKIhAuv-DnTy9ns6ew2phAq9sAY5UP6YIUjNHhQBgSUYaZGDZk47hEbqo4iAM9NfR8.jpg", "https://s.nomerogram.ru/photo/sxIsdctpGDKZBe-MJRBSy2uXMEln04vk_hK12fe04IkOctMRYhnLlO8AjKNzA8FBEf4of-p0ZYn_q4wkBcabiPGFCXPd.jpg", "https://s.nomerogram.ru/photo/eO8K4Q8QkRvT-b9EYXqbAlUNlzLnv6h0l4YfqWcL6wvVpwnC9lKQmHyzwncTh5EXCTXtXKaE0VoiICLDaAZy54HChMbe.jpg", "https://s.nomerogram.ru/photo/rAiWJpaO1jT_cAucLJg6APiR10-YVCWSQQXARLurj_RHuce2A2TNXY8_xt0e6dRBdRlwJEaTS_O2V4KPxWvznHhVTsGx.jpg", "https://s.nomerogram.ru/photo/uD35kAplNFZzNZ8HFXmTI6WWrZs019fcqcAE-WOz1eC954WHD6x_8x2YmoUk3GcyzDxk3XpFkK87wYF8X7ti5quOkt1G.jpg"
]
.compactMap(URL.init(string:))
ACImageSliderView(urls: urls, selected: urls[1])
}

View File

@ -1,37 +0,0 @@
//
// ACProgressHud.swift
// AutoCat
//
// Created by Selim Mustafaev on 29.06.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import SwiftUI
import AutoCatCore
struct ACProgressHud: View {
@State var toast: ACHud?
var body: some View {
VStack(spacing: 16) {
Rectangle()
.fill(.orange)
.frame(width: 200, height: 200)
Button("Show progress") {
toast = .progress
}
Button("Show error") {
toast = .error(ApiError.generic)
}
Rectangle()
.fill(.orange)
.frame(width: 200, height: 200)
}
.hud($toast)
}
}
#Preview {
ACProgressHud()
}

View File

@ -0,0 +1,60 @@
//
// LinkRowView.swift
// AutoCat
//
// Created by Selim Mustafaev on 20.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct LinkRowView: View {
let title: String
let value: String?
var body: some View {
if #available(iOS 16.0, *) {
ViewThatFits(in: .horizontal) {
SimpleLinkRowView(title: title, value: value)
VStack(alignment: .leading, spacing: 8) {
Text(title)
HStack {
Spacer()
if let url = URL(string: value ?? "") {
Link(url.absoluteString, destination: url)
.multilineTextAlignment(.trailing)
.padding(.leading)
}
}
}
}
} else {
SimpleLinkRowView(title: title, value: value)
}
}
}
struct SimpleLinkRowView: View {
let title: String
let value: String?
var body: some View {
HStack(spacing: 0) {
Text(title)
Spacer()
if let url = URL(string: value ?? "") {
Link(url.absoluteString, destination: url)
}
}
}
}
#Preview {
List {
LinkRowView(title: "Title", value: "https://google.com")
LinkRowView(title: "Title", value: "https://developer.apple.com/documentation/swiftui/viewthatfits")
}
}

View File

@ -0,0 +1,58 @@
//
// TextRowView.swift
// AutoCat
//
// Created by Selim Mustafaev on 20.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct TextRowView: View {
let title: String
let value: String?
var body: some View {
if #available(iOS 16.0, *) {
ViewThatFits(in: .horizontal) {
SimpleTextRowView(title: title, value: value)
VStack(alignment: .leading, spacing: 8) {
Text(title)
HStack {
Spacer()
Text(value ?? "")
.foregroundStyle(.secondary)
.multilineTextAlignment(.trailing)
.padding(.leading)
}
}
}
} else {
SimpleTextRowView(title: title, value: value)
}
}
}
struct SimpleTextRowView: View {
let title: String
let value: String?
var body: some View {
HStack(alignment: .firstTextBaseline, spacing: 0) {
Text(title)
Spacer()
Text(value ?? "")
.foregroundStyle(.secondary)
}
}
}
#Preview {
List {
TextRowView(title: "Title", value: "Value")
TextRowView(title: "Title", value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas cursus posuere varius. Maecenas diam neque, lacinia molestie tristique eget, faucibus egestas nibh.")
TextRowView(title: "Some longer title", value: "Value with long long text")
}
}

View File

@ -0,0 +1,217 @@
//
// Zoomable.swift
// AutoCat
//
// Created by Selim Mustafaev on 21.07.2024.
// Copyright © 2024 Selim Mustafaev. All rights reserved.
//
#if os(iOS)
import SwiftUI
struct ZoomableModifier: ViewModifier {
let minZoomScale: CGFloat
let doubleTapZoomScale: CGFloat
@State private var lastTransform: CGAffineTransform = .identity
@State private var transform: CGAffineTransform = .identity
@State private var contentSize: CGSize = .zero
func body(content: Content) -> some View {
content
.background(alignment: .topLeading) {
GeometryReader { proxy in
Color.clear
.onAppear {
contentSize = proxy.size
}
}
}
.animatableTransformEffect(transform)
.gesture(dragGesture, including: transform == .identity ? .none : .all)
.modify { view in
if #available(iOS 17.0, *) {
view.gesture(magnificationGesture)
} else {
view.gesture(oldMagnificationGesture)
}
}
//.gesture(doubleTapGesture)
}
@available(iOS, introduced: 15.0, deprecated: 17.0)
private var oldMagnificationGesture: some Gesture {
MagnificationGesture()
.onChanged { value in
let zoomFactor = 0.5
let scale = value * zoomFactor
transform = lastTransform.scaledBy(x: scale, y: scale)
}
.onEnded { _ in
onEndGesture()
}
}
@available(iOS 17.0, *)
private var magnificationGesture: some Gesture {
MagnifyGesture(minimumScaleDelta: 0)
.onChanged { value in
let newTransform = CGAffineTransform.anchoredScale(
scale: value.magnification,
anchor: value.startAnchor.scaledBy(contentSize)
)
withAnimation(.interactiveSpring) {
transform = lastTransform.concatenating(newTransform)
}
}
.onEnded { _ in
onEndGesture()
}
}
// private var doubleTapGesture: some Gesture {
// SpatialTapGesture(count: 2)
// .onEnded { value in
// let newTransform: CGAffineTransform =
// if transform.isIdentity {
// .anchoredScale(scale: doubleTapZoomScale, anchor: value.location)
// } else {
// .identity
// }
//
// withAnimation(.linear(duration: 0.15)) {
// transform = newTransform
// lastTransform = newTransform
// }
// }
// }
private var dragGesture: some Gesture {
DragGesture()
.onChanged { value in
withAnimation(.interactiveSpring) {
transform = lastTransform.translatedBy(
x: value.translation.width / transform.scaleX,
y: value.translation.height / transform.scaleY
)
}
}
.onEnded { _ in
onEndGesture()
}
}
private func onEndGesture() {
let newTransform = limitTransform(transform)
withAnimation(.snappy(duration: 0.1)) {
transform = newTransform
lastTransform = newTransform
}
}
private func limitTransform(_ transform: CGAffineTransform) -> CGAffineTransform {
let scaleX = transform.scaleX
let scaleY = transform.scaleY
if scaleX < minZoomScale
|| scaleY < minZoomScale
{
return .identity
}
let maxX = contentSize.width * (scaleX - 1)
let maxY = contentSize.height * (scaleY - 1)
if transform.tx > 0
|| transform.tx < -maxX
|| transform.ty > 0
|| transform.ty < -maxY
{
let tx = min(max(transform.tx, -maxX), 0)
let ty = min(max(transform.ty, -maxY), 0)
var transform = transform
transform.tx = tx
transform.ty = ty
return transform
}
return transform
}
}
public extension View {
@ViewBuilder
func zoomable(
minZoomScale: CGFloat = 1,
doubleTapZoomScale: CGFloat = 3
) -> some View {
modifier(ZoomableModifier(
minZoomScale: minZoomScale,
doubleTapZoomScale: doubleTapZoomScale
))
}
@ViewBuilder
func zoomable(
minZoomScale: CGFloat = 1,
doubleTapZoomScale: CGFloat = 3,
outOfBoundsColor: Color = .clear
) -> some View {
GeometryReader { proxy in
ZStack {
outOfBoundsColor
self.zoomable(
minZoomScale: minZoomScale,
doubleTapZoomScale: doubleTapZoomScale
)
}
}
}
}
private extension View {
@ViewBuilder
func modify(@ViewBuilder _ fn: (Self) -> some View) -> some View {
fn(self)
}
@ViewBuilder
func animatableTransformEffect(_ transform: CGAffineTransform) -> some View {
scaleEffect(
x: transform.scaleX,
y: transform.scaleY,
anchor: .zero
)
.offset(x: transform.tx, y: transform.ty)
}
}
private extension UnitPoint {
func scaledBy(_ size: CGSize) -> CGPoint {
.init(
x: x * size.width,
y: y * size.height
)
}
}
private extension CGAffineTransform {
static func anchoredScale(scale: CGFloat, anchor: CGPoint) -> CGAffineTransform {
CGAffineTransform(translationX: anchor.x, y: anchor.y)
.scaledBy(x: scale, y: scale)
.translatedBy(x: -anchor.x, y: -anchor.y)
}
var scaleX: CGFloat {
sqrt(a * a + c * c)
}
var scaleY: CGFloat {
sqrt(b * b + d * d)
}
}
#endif

View File

@ -8,7 +8,7 @@
import Foundation
public struct VehicleAdDto: Decodable, Sendable {
public struct VehicleAdDto: Decodable, Sendable, Identifiable {
public var id: Int = 0
public var url: String?

View File

@ -18,7 +18,7 @@ extension StorageService {
let note = VehicleNote(text: text)
try realm.write {
try await realm.asyncWrite {
vehicle.notes.append(note)
vehicle.updatedDate = Date().timeIntervalSince1970
}
@ -36,7 +36,7 @@ extension StorageService {
throw StorageError.noteNotFound
}
try realm.write {
try await realm.asyncWrite {
realm.delete(realmNote)
vehicle.updatedDate = Date().timeIntervalSince1970
}
@ -54,7 +54,7 @@ extension StorageService {
throw StorageError.noteNotFound
}
try realm.write {
try await realm.asyncWrite {
note.text = text
vehicle.updatedDate = Date().timeIntervalSince1970

View File

@ -51,7 +51,7 @@ public actor StorageService: StorageServiceProtocol {
return
}
try realm.write {
try await realm.asyncWrite {
realm.add(Vehicle(dto: dto), update: .all)
}
}