diff --git a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj index c11746b..c72671b 100644 --- a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj +++ b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj @@ -9,14 +9,29 @@ /* Begin PBXBuildFile section */ 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E52BE532B700C04508 /* AppDelegate.swift */; }; 1D2C16E82BE532B700C04508 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E72BE532B700C04508 /* SceneDelegate.swift */; }; - 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E92BE532B700C04508 /* ViewController.swift */; }; 1D2C16EF2BE532B800C04508 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1D2C16EE2BE532B800C04508 /* Assets.xcassets */; }; 1D2C16F22BE532B800C04508 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1D2C16F02BE532B800C04508 /* LaunchScreen.storyboard */; }; 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */; }; 1D2C17072BE532B800C04508 /* HomeCafeRecipesUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C17062BE532B800C04508 /* HomeCafeRecipesUITests.swift */; }; 1D2C17092BE532B800C04508 /* HomeCafeRecipesUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C17082BE532B800C04508 /* HomeCafeRecipesUITestsLaunchTests.swift */; }; - 1D2E033E2BE913E500294417 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 1D2E033D2BE913E500294417 /* FirebaseAnalytics */; }; - 1DCB3D302BE9126E0036D305 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1DCB3D2F2BE9126E0036D305 /* GoogleService-Info.plist */; }; + 1D50F0ED2C0D896C005A071B /* FeedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D50F0EC2C0D896C005A071B /* FeedCell.swift */; }; + 1D50F0F12C0D8C88005A071B /* FeedListCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D50F0F02C0D8C88005A071B /* FeedListCollectionView.swift */; }; + 1D6B8D412C0DB82B0039758A /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 1D6B8D402C0DB82B0039758A /* FirebaseAnalytics */; }; + 1D6B8D432C0DB82F0039758A /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 1D6B8D422C0DB82F0039758A /* FirebaseFirestore */; }; + 1D6B8D452C0DB8890039758A /* FirebaseFirestoreSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 1D6B8D442C0DB8890039758A /* FirebaseFirestoreSwift */; }; + 1D6FD14D2C1362CD00F47AFE /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6FD14C2C1362CD00F47AFE /* User.swift */; }; + 1D6FD14F2C13630F00F47AFE /* RecipeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6FD14E2C13630F00F47AFE /* RecipeType.swift */; }; + 1D6FD1512C13633500F47AFE /* Like.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6FD1502C13633500F47AFE /* Like.swift */; }; + 1D6FD1532C13634C00F47AFE /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6FD1522C13634C00F47AFE /* Comment.swift */; }; + 1D8262362C08A227000E981A /* FetchFeedListUsecase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8262352C08A227000E981A /* FetchFeedListUsecase.swift */; }; + 1D8262382C08A233000E981A /* SearchFeedListUsecase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8262372C08A233000E981A /* SearchFeedListUsecase.swift */; }; + 1D82623A2C08A266000E981A /* FeedListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8262392C08A266000E981A /* FeedListViewController.swift */; }; + 1D82623C2C08BB10000E981A /* FeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D82623B2C08BB10000E981A /* FeedListRepository.swift */; }; + 1D82623E2C08BBB2000E981A /* FirebaseRemoteDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D82623D2C08BBB2000E981A /* FirebaseRemoteDataSource.swift */; }; + 1DBBFB752BF510D400524549 /* Recipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBBFB742BF510D400524549 /* Recipe.swift */; }; + 1DE852962BEF83DA0023AA96 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1DE852952BEF83DA0023AA96 /* GoogleService-Info.plist */; }; + 1DEEE4F32C09637C000E1F39 /* FeedListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DEEE4F22C09637C000E1F39 /* FeedListViewModel.swift */; }; + 1DEEE4F72C0AEF93000E1F39 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DEEE4F62C0AEF93000E1F39 /* Observable.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,16 +55,28 @@ 1D2C16E22BE532B700C04508 /* HomeCafeRecipes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HomeCafeRecipes.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1D2C16E52BE532B700C04508 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 1D2C16E72BE532B700C04508 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - 1D2C16E92BE532B700C04508 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 1D2C16EE2BE532B800C04508 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 1D2C16F12BE532B800C04508 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 1D2C16F32BE532B800C04508 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1D2C16F82BE532B800C04508 /* HomeCafeRecipesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HomeCafeRecipesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCafeRecipesTests.swift; sourceTree = ""; }; 1D2C17022BE532B800C04508 /* HomeCafeRecipesUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HomeCafeRecipesUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1D2C17062BE532B800C04508 /* HomeCafeRecipesUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCafeRecipesUITests.swift; sourceTree = ""; }; 1D2C17082BE532B800C04508 /* HomeCafeRecipesUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCafeRecipesUITestsLaunchTests.swift; sourceTree = ""; }; - 1DCB3D2F2BE9126E0036D305 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 1D50F0EC2C0D896C005A071B /* FeedCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedCell.swift; sourceTree = ""; }; + 1D50F0F02C0D8C88005A071B /* FeedListCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListCollectionView.swift; sourceTree = ""; }; + 1D6FD14C2C1362CD00F47AFE /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + 1D6FD14E2C13630F00F47AFE /* RecipeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeType.swift; sourceTree = ""; }; + 1D6FD1502C13633500F47AFE /* Like.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Like.swift; sourceTree = ""; }; + 1D6FD1522C13634C00F47AFE /* Comment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; + 1D8262352C08A227000E981A /* FetchFeedListUsecase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchFeedListUsecase.swift; sourceTree = ""; }; + 1D8262372C08A233000E981A /* SearchFeedListUsecase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchFeedListUsecase.swift; sourceTree = ""; }; + 1D8262392C08A266000E981A /* FeedListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListViewController.swift; sourceTree = ""; }; + 1D82623B2C08BB10000E981A /* FeedListRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListRepository.swift; sourceTree = ""; }; + 1D82623D2C08BBB2000E981A /* FirebaseRemoteDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseRemoteDataSource.swift; sourceTree = ""; }; + 1DBBFB742BF510D400524549 /* Recipe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recipe.swift; sourceTree = ""; }; + 1DE852952BEF83DA0023AA96 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 1DEEE4F22C09637C000E1F39 /* FeedListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FeedListViewModel.swift; path = HomeCafeRecipes/Domain/ViewModel/FeedListViewModel.swift; sourceTree = SOURCE_ROOT; }; + 1DEEE4F62C0AEF93000E1F39 /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,7 +84,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1D2E033E2BE913E500294417 /* FirebaseAnalytics in Frameworks */, + 1D6B8D412C0DB82B0039758A /* FirebaseAnalytics in Frameworks */, + 1D6B8D432C0DB82F0039758A /* FirebaseFirestore in Frameworks */, + 1D6B8D452C0DB8890039758A /* FirebaseFirestoreSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -85,6 +114,7 @@ 1D2C16FB2BE532B800C04508 /* HomeCafeRecipesTests */, 1D2C17052BE532B800C04508 /* HomeCafeRecipesUITests */, 1D2C16E32BE532B700C04508 /* Products */, + 1DE8529C2BEFAB270023AA96 /* Frameworks */, ); sourceTree = ""; }; @@ -101,13 +131,14 @@ 1D2C16E42BE532B700C04508 /* HomeCafeRecipes */ = { isa = PBXGroup; children = ( - 1DCB3D2F2BE9126E0036D305 /* GoogleService-Info.plist */, + 1D82622C2C0857BF000E981A /* Presentation */, + 1D82622D2C0857CE000E981A /* Domain */, + 1D82622E2C0857E1000E981A /* Data */, + 1DE852952BEF83DA0023AA96 /* GoogleService-Info.plist */, 1D2C16E52BE532B700C04508 /* AppDelegate.swift */, 1D2C16E72BE532B700C04508 /* SceneDelegate.swift */, - 1D2C16E92BE532B700C04508 /* ViewController.swift */, 1D2C16EE2BE532B800C04508 /* Assets.xcassets */, 1D2C16F02BE532B800C04508 /* LaunchScreen.storyboard */, - 1D2C16F32BE532B800C04508 /* Info.plist */, ); path = HomeCafeRecipes; sourceTree = ""; @@ -129,6 +160,96 @@ path = HomeCafeRecipesUITests; sourceTree = ""; }; + 1D82622C2C0857BF000E981A /* Presentation */ = { + isa = PBXGroup; + children = ( + 1DE852972BEF83E50023AA96 /* FeedList */, + 1DEEE4F52C0AEF67000E1F39 /* Utils */, + ); + path = Presentation; + sourceTree = ""; + }; + 1D82622D2C0857CE000E981A /* Domain */ = { + isa = PBXGroup; + children = ( + 1DEEE4F42C096389000E1F39 /* ViewModel */, + 1D8262322C08A1D1000E981A /* UseCase */, + 1D8262312C08A1C4000E981A /* Entities */, + ); + path = Domain; + sourceTree = ""; + }; + 1D82622E2C0857E1000E981A /* Data */ = { + isa = PBXGroup; + children = ( + 1D82623B2C08BB10000E981A /* FeedListRepository.swift */, + 1D82623D2C08BBB2000E981A /* FirebaseRemoteDataSource.swift */, + ); + path = Data; + sourceTree = ""; + }; + 1D82622F2C08586F000E981A /* View */ = { + isa = PBXGroup; + children = ( + 1D8262392C08A266000E981A /* FeedListViewController.swift */, + 1D50F0F02C0D8C88005A071B /* FeedListCollectionView.swift */, + 1D50F0EC2C0D896C005A071B /* FeedCell.swift */, + ); + path = View; + sourceTree = ""; + }; + 1D8262312C08A1C4000E981A /* Entities */ = { + isa = PBXGroup; + children = ( + 1DBBFB742BF510D400524549 /* Recipe.swift */, + 1D6FD14C2C1362CD00F47AFE /* User.swift */, + 1D6FD14E2C13630F00F47AFE /* RecipeType.swift */, + 1D6FD1502C13633500F47AFE /* Like.swift */, + 1D6FD1522C13634C00F47AFE /* Comment.swift */, + ); + path = Entities; + sourceTree = ""; + }; + 1D8262322C08A1D1000E981A /* UseCase */ = { + isa = PBXGroup; + children = ( + 1D8262372C08A233000E981A /* SearchFeedListUsecase.swift */, + 1D8262352C08A227000E981A /* FetchFeedListUsecase.swift */, + ); + path = UseCase; + sourceTree = ""; + }; + 1DE852972BEF83E50023AA96 /* FeedList */ = { + isa = PBXGroup; + children = ( + 1D82622F2C08586F000E981A /* View */, + ); + path = FeedList; + sourceTree = ""; + }; + 1DE8529C2BEFAB270023AA96 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + 1DEEE4F42C096389000E1F39 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 1DEEE4F22C09637C000E1F39 /* FeedListViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 1DEEE4F52C0AEF67000E1F39 /* Utils */ = { + isa = PBXGroup; + children = ( + 1DEEE4F62C0AEF93000E1F39 /* Observable.swift */, + ); + path = Utils; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -146,7 +267,9 @@ ); name = HomeCafeRecipes; packageProductDependencies = ( - 1D2E033D2BE913E500294417 /* FirebaseAnalytics */, + 1D6B8D402C0DB82B0039758A /* FirebaseAnalytics */, + 1D6B8D422C0DB82F0039758A /* FirebaseFirestore */, + 1D6B8D442C0DB8890039758A /* FirebaseFirestoreSwift */, ); productName = HomeCafeRecipes; productReference = 1D2C16E22BE532B700C04508 /* HomeCafeRecipes.app */; @@ -240,7 +363,7 @@ buildActionMask = 2147483647; files = ( 1D2C16F22BE532B800C04508 /* LaunchScreen.storyboard in Resources */, - 1DCB3D302BE9126E0036D305 /* GoogleService-Info.plist in Resources */, + 1DE852962BEF83DA0023AA96 /* GoogleService-Info.plist in Resources */, 1D2C16EF2BE532B800C04508 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -266,9 +389,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */, + 1D6FD14D2C1362CD00F47AFE /* User.swift in Sources */, + 1D82623C2C08BB10000E981A /* FeedListRepository.swift in Sources */, + 1DEEE4F32C09637C000E1F39 /* FeedListViewModel.swift in Sources */, + 1D50F0F12C0D8C88005A071B /* FeedListCollectionView.swift in Sources */, + 1D82623E2C08BBB2000E981A /* FirebaseRemoteDataSource.swift in Sources */, + 1D6FD14F2C13630F00F47AFE /* RecipeType.swift in Sources */, 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */, + 1D50F0ED2C0D896C005A071B /* FeedCell.swift in Sources */, 1D2C16E82BE532B700C04508 /* SceneDelegate.swift in Sources */, + 1D6FD1512C13633500F47AFE /* Like.swift in Sources */, + 1D8262382C08A233000E981A /* SearchFeedListUsecase.swift in Sources */, + 1D6FD1532C13634C00F47AFE /* Comment.swift in Sources */, + 1DEEE4F72C0AEF93000E1F39 /* Observable.swift in Sources */, + 1D8262362C08A227000E981A /* FetchFeedListUsecase.swift in Sources */, + 1D82623A2C08A266000E981A /* FeedListViewController.swift in Sources */, + 1DBBFB752BF510D400524549 /* Recipe.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -449,11 +585,13 @@ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = "-Wl,-ld_classic"; PRODUCT_BUNDLE_IDENTIFIER = GeonH0.HomeCafeRecipes; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -476,11 +614,13 @@ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = "-Wl,-ld_classic"; PRODUCT_BUNDLE_IDENTIFIER = GeonH0.HomeCafeRecipes; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -618,11 +758,21 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 1D2E033D2BE913E500294417 /* FirebaseAnalytics */ = { + 1D6B8D402C0DB82B0039758A /* FirebaseAnalytics */ = { isa = XCSwiftPackageProductDependency; package = 1DCB3D312BE913880036D305 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseAnalytics; }; + 1D6B8D422C0DB82F0039758A /* FirebaseFirestore */ = { + isa = XCSwiftPackageProductDependency; + package = 1DCB3D312BE913880036D305 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestore; + }; + 1D6B8D442C0DB8890039758A /* FirebaseFirestoreSwift */ = { + isa = XCSwiftPackageProductDependency; + package = 1DCB3D312BE913880036D305 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestoreSwift; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 1D2C16DA2BE532B700C04508 /* Project object */; diff --git a/HomeCafeRecipes/HomeCafeRecipes/Data/FeedListRepository.swift b/HomeCafeRecipes/HomeCafeRecipes/Data/FeedListRepository.swift new file mode 100644 index 0000000..08fd018 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Data/FeedListRepository.swift @@ -0,0 +1,29 @@ +// +// FeedListRepository.swift +// HomeCafeRecipes +// +// Created by 김건호 on 5/30/24. +// + +import Foundation + +protocol FeedListRepository { + func fetchFeedItems(completion: @escaping (Result<[FeedItem], Error>) -> Void) + func searchFeedItems(title: String, completion: @escaping (Result<[FeedItem], Error>) -> Void) +} + +final class FeedListRepositoryImpl: FeedListRepository { + private let remoteDataSource: FirebaseRemoteDataSource + + init(remoteDataSource: FirebaseRemoteDataSource) { + self.remoteDataSource = remoteDataSource + } + + func fetchFeedItems(completion: @escaping (Result<[FeedItem], Error>) -> Void) { + remoteDataSource.fetchFeedItems(completion: completion) + } + + func searchFeedItems(title : String, completion: @escaping (Result<[FeedItem], Error>) -> Void){ + remoteDataSource.searchFeedItems(title: title, completion: completion) + } +} diff --git a/HomeCafeRecipes/HomeCafeRecipes/Data/FirebaseRemoteDataSource.swift b/HomeCafeRecipes/HomeCafeRecipes/Data/FirebaseRemoteDataSource.swift new file mode 100644 index 0000000..bfcd054 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Data/FirebaseRemoteDataSource.swift @@ -0,0 +1,62 @@ +// +// FirebaseRemoteDataSource.swift +// HomeCafeRecipes +// +// Created by 김건호 on 5/30/24. +// + +import FirebaseFirestore + +class FirebaseRemoteDataSource { + private let firebaseDB = Firestore.firestore() + + func fetchFeedItems(completion: @escaping (Result<[FeedItem], Error>) -> Void) { + firebaseDB.collection("feedItems").getDocuments { (querySnapshot, error) in + if let error = error { + completion(.failure(error)) + return + } + guard let documents = querySnapshot?.documents else { + completion(.success([])) + return + } + let feedItems = self.convertToFeedItems(documents) + completion(.success(feedItems)) + } + } + + func searchFeedItems(title: String, completion: @escaping (Result<[FeedItem], Error>) -> Void) { + firebaseDB.collection("feedItems") + .whereField("title", isGreaterThanOrEqualTo: title) + .whereField("title", isLessThanOrEqualTo: "\(title)\u{f8ff}") + .getDocuments { (querySnapshot, error) in + if let error = error { + completion(.failure(error)) + return + } + guard let documents = querySnapshot?.documents else { + completion(.success([])) + return + } + + let feedItems = self.convertToFeedItems(documents) + completion(.success(feedItems)) + } + } + + private func convertToFeedItems(_ documents: [QueryDocumentSnapshot]) -> [FeedItem] { + return documents.compactMap { doc -> FeedItem? in + let data = doc.data() + guard + let id = data["id"] as? String, + let title = data["title"] as? String, + let imageURLs = data["imageURLs"] as? [String] else { + return nil + } + return FeedItem(id: id, title: title, imageURLs: imageURLs) + } + } + +} + + diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift new file mode 100644 index 0000000..a64ae38 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift @@ -0,0 +1,20 @@ +// +// FeedModel.swift +// HomeCafeRecipes +// +// Created by 김건호 on 5/16/24. +// + +import Foundation + +struct Recipe { + let id: String + let type: RecipeType + let name: String + let description: String + let owner: User + let imageURLs: [String] + let comments: [Comment] + let likes: [Like] + let createdAt: Date +} diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/UseCase/FetchFeedListUsecase.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/UseCase/FetchFeedListUsecase.swift new file mode 100644 index 0000000..88abd4c --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/UseCase/FetchFeedListUsecase.swift @@ -0,0 +1,30 @@ +// +// fetchFeedListUsecase.swift +// HomeCafeRecipes +// +// Created by 김건호 on 5/30/24. +// + + +protocol FetchFeedListUseCase { + func execute(completion: @escaping (Result<[FeedItem], Error>) -> Void) +} + +class DefaultFetchFeedListUseCase: FetchFeedListUseCase { + private let repository: FeedListRepository + + init(repository: FeedListRepository) { + self.repository = repository + } + + func execute(completion: @escaping (Result<[FeedItem], Error>) -> Void) { + repository.fetchFeedItems { result in + switch result { + case .success(let feedItems): + completion(.success(feedItems)) + case .failure(let error): + completion(.failure(error)) + } + } + } +} diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/UseCase/SearchFeedListUsecase.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/UseCase/SearchFeedListUsecase.swift new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/UseCase/SearchFeedListUsecase.swift @@ -0,0 +1,30 @@ +// +// SearchFeedListusecase.swift +// HomeCafeRecipes +// +// Created by 김건호 on 5/30/24. +// + + +protocol SearchFeedListUseCase { + func execute(title: String, completion: @escaping (Result<[FeedItem], Error>) -> Void) +} + +class DefaultSearchFeedListUseCase: SearchFeedListUseCase { + private let repository: FeedListRepository + + init(repository: FeedListRepository) { + self.repository = repository + } + + func execute(title: String, completion: @escaping (Result<[FeedItem], Error>) -> Void) { + repository.searchFeedItems(title: title) { result in + switch result { + case .success(let feedItems): + completion(.success(feedItems)) + case .failure(let error): + completion(.failure(error)) + } + } + } +} diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/FeedListViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/FeedListViewController.swift new file mode 100644 index 0000000..1733d83 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/FeedListViewController.swift @@ -0,0 +1,12 @@ +// +// FeedListViewcontroller.swift +// HomeCafeRecipes +// +// Created by 김건호 on 5/30/24. +// + +import UIKit + +class FeedListViewController : UIViewController { + +} diff --git a/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift b/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift index aa44d9a..c7805f2 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift @@ -18,8 +18,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: windowScene) - let mainViewController = ViewController() - let navigationController = UINavigationController(rootViewController : mainViewController) + let mainViewController = FeedListViewController() + let navigationController = UINavigationController(rootViewController : mainViewController) window?.rootViewController = navigationController window?.makeKeyAndVisible() } diff --git a/HomeCafeRecipes/HomeCafeRecipes/ViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/ViewController.swift deleted file mode 100644 index 97bd64f..0000000 --- a/HomeCafeRecipes/HomeCafeRecipes/ViewController.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// ViewController.swift -// HomeCafeRecipes -// -// Created by 김건호 on 5/3/24. -// - -import UIKit - -class ViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - } - - -} -