From c20fc551f960f30c58f330a9cb2862d114fcedf0 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 14 Jul 2024 14:11:20 +0900 Subject: [PATCH 01/51] =?UTF-8?q?Feat:=20AddRecipeViewController=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes.xcodeproj/project.pbxproj | 470 ++++++++---------- .../AddRecipeViewController.swift | 211 ++++++++ 2 files changed, 415 insertions(+), 266 deletions(-) create mode 100644 HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj index 2eefc42..a03b736 100644 --- a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj +++ b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj @@ -21,63 +21,67 @@ 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 */; }; + 1D2C6F652C2446D8004BB54E /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */; }; + 1D2C6F6C2C27051D004BB54E /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */; }; + 1D39720D2C438D8300495014 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39720C2C438D8300495014 /* DateFormatter+Extensions.swift */; }; + 1D39720F2C438E1F00495014 /* RecipeListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39720E2C438E1F00495014 /* RecipeListMapper.swift */; }; + 1D3972112C438E6A00495014 /* RecipeListItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972102C438E6A00495014 /* RecipeListItemViewModel.swift */; }; + 1D3972142C438E9C00495014 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972122C438E9C00495014 /* User.swift */; }; + 1D3972152C438E9C00495014 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972132C438E9C00495014 /* Comment.swift */; }; + 1D3972172C438EAC00495014 /* UserDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972162C438EAC00495014 /* UserDTO.swift */; }; + 1D39721D2C438EDD00495014 /* SelectImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972192C438EDD00495014 /* SelectImageCell.swift */; }; + 1D39721E2C438EDD00495014 /* AddRecipeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */; }; + 1D39721F2C438EDD00495014 /* RecipeUploadImgaeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */; }; + 1D3972202C438EDD00495014 /* AddRecipeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721C2C438EDD00495014 /* AddRecipeView.swift */; }; + 1D3972252C438EF500495014 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972222C438EF500495014 /* AddRecipeRouter.swift */; }; + 1D3972262C438EF500495014 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972232C438EF500495014 /* RecipeListRouter.swift */; }; + 1D3972272C438EF500495014 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972242C438EF500495014 /* Router.swift */; }; + 1D3972292C438F1C00495014 /* AddRecipeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972282C438F1C00495014 /* AddRecipeInteractor.swift */; }; + 1D39722B2C438FD300495014 /* SaveRecipeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39722A2C438FD300495014 /* SaveRecipeUseCase.swift */; }; + 1D39722D2C43904800495014 /* AddRecipeRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39722C2C43904800495014 /* AddRecipeRepository.swift */; }; + 1D39722F2C43906300495014 /* RecipePostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39722E2C43906300495014 /* RecipePostService.swift */; }; + 1D3972312C43907300495014 /* RecipeUploadDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972302C43907300495014 /* RecipeUploadDTO.swift */; }; + 1D3972332C43907B00495014 /* ErrorResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972322C43907B00495014 /* ErrorResponseDTO.swift */; }; + 1D3972352C4390E200495014 /* RecipeUploadResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972342C4390E200495014 /* RecipeUploadResponseDTO.swift */; }; + 1D439E9C2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */; }; + 1D439E9E2C2C598A008530A5 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */; }; + 1D439EA22C2C6997008530A5 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */; }; 1D4741D12C1B4F8D009381CE /* RecipeImageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */; }; 1D4741D22C1B4F8D009381CE /* RecipeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */; }; 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */; }; 1D4741D42C1B4F8D009381CE /* NetworkResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */; }; - - 1DDE911D2C36717B0078DFD3 /* String+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE911B2C36717B0078DFD3 /* String+Validation.swift */; }; - 1DDE911E2C36717B0078DFD3 /* UIImageViewImageLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE911C2C36717B0078DFD3 /* UIImageViewImageLoading.swift */; }; - 1DDE91212C3671840078DFD3 /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91202C3671840078DFD3 /* Fonts.swift */; }; - 1DDE91232C3671920078DFD3 /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91222C3671910078DFD3 /* CustomNavigationBar.swift */; }; - 1DDE91252C3671B20078DFD3 /* RecipeListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91242C3671B20078DFD3 /* RecipeListMapper.swift */; }; - 1DDE91282C3671DB0078DFD3 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91272C3671DB0078DFD3 /* DateFormatter+Extensions.swift */; }; - 1DDE912B2C3671EC0078DFD3 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91292C3671EC0078DFD3 /* User.swift */; }; - 1DDE912C2C3671EC0078DFD3 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE912A2C3671EC0078DFD3 /* Comment.swift */; }; - 1DDE912E2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE912D2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift */; }; - 1DDE91302C36720A0078DFD3 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE912F2C36720A0078DFD3 /* RecipeDetailInteractor.swift */; }; - 1DDE91332C3672170078DFD3 /* RecipeDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91322C3672170078DFD3 /* RecipeDetailCoordinator.swift */; }; - 1DDE91352C3672230078DFD3 /* RecipeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91342C3672230078DFD3 /* RecipeDetailViewModel.swift */; }; - 1DDE91382C36722A0078DFD3 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91362C36722A0078DFD3 /* RecipeDetailViewController.swift */; }; - 1DDE91392C36722A0078DFD3 /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91372C36722A0078DFD3 /* RecipeDetailView.swift */; }; - 1DDE913B2C3672410078DFD3 /* UserDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE913A2C3672410078DFD3 /* UserDTO.swift */; }; - 1DDE913D2C3672490078DFD3 /* RecipeDetailFetchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE913C2C3672490078DFD3 /* RecipeDetailFetchService.swift */; }; - 1DDE913F2C3672720078DFD3 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE913E2C3672720078DFD3 /* RecipeDetailRepository.swift */; }; - 1DDE91412C3672850078DFD3 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91402C3672850078DFD3 /* RecipeDetailDTO.swift */; }; - - 1D60CC452C3F932D00D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */; }; - 1D60CC462C3F932D00D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */; }; - 1D7368B72C3442C8000EF904 /* String+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368B52C3442C8000EF904 /* String+Validation.swift */; }; - 1D7368B82C3442C8000EF904 /* UIImageViewImageLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368B62C3442C8000EF904 /* UIImageViewImageLoading.swift */; }; - 1D7368BA2C3442DE000EF904 /* RecipeListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368B92C3442DE000EF904 /* RecipeListMapper.swift */; }; - 1D7368C72C344378000EF904 /* UserDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368C62C344378000EF904 /* UserDTO.swift */; }; - 1D7368CA2C3443A1000EF904 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368C82C3443A1000EF904 /* Comment.swift */; }; - 1D7368CB2C3443A1000EF904 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368C92C3443A1000EF904 /* User.swift */; }; - 1D7368CE2C344403000EF904 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368CD2C344403000EF904 /* DateFormatter+Extensions.swift */; }; - 1D7368D22C34FADD000EF904 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D12C34FADD000EF904 /* FetchRecipeDetailUseCase.swift */; }; - 1D7368D42C34FAE8000EF904 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D32C34FAE8000EF904 /* RecipeDetailInteractor.swift */; }; - 1D7368D82C34FB07000EF904 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D72C34FB07000EF904 /* RecipeDetailDTO.swift */; }; - 1D7368DA2C34FB14000EF904 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D92C34FB14000EF904 /* RecipeDetailRepository.swift */; }; - 1D7368DC2C34FB32000EF904 /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368DB2C34FB32000EF904 /* CustomNavigationBar.swift */; }; - 1D7368E22C34FB38000EF904 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368DF2C34FB38000EF904 /* RecipeDetailViewController.swift */; }; - 1D7368E32C34FB38000EF904 /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E02C34FB38000EF904 /* RecipeDetailView.swift */; }; - 1D7368E42C34FB38000EF904 /* RecipeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E12C34FB38000EF904 /* RecipeDetailViewModel.swift */; }; - 1D7368E72C34FB66000EF904 /* RecipeDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E62C34FB66000EF904 /* RecipeDetailCoordinator.swift */; }; - 1D7368EA2C34FBF7000EF904 /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E92C34FBF7000EF904 /* MainTabBarController.swift */; }; - 1D95A0A42C37B0E200F09077 /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A32C37B0E200F09077 /* Fonts.swift */; }; - 1D95A0A82C37C7D400F09077 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A72C37C7D400F09077 /* RecipeDetailError.swift */; }; - + 1D4741D72C1B4FF4009381CE /* RecipeListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */; }; + 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */; }; + 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */; }; + 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */; }; + 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */; }; + 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */; }; + 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283A12C15E94300C5A870 /* Recipe.swift */; }; + 1D6958DC2C3D5E20008604B3 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */; }; + 1D6958DE2C3D5E2C008604B3 /* RecipeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283A32C15EA8100C5A870 /* RecipeType.swift */; }; + 1D6958DF2C3D5E35008604B3 /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB02C1B42200031804A /* NetworkService.swift */; }; + 1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */; }; + 1D6958E12C3D5E44008604B3 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */; }; + 1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */; }; + 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */; }; + 1D73686E2C305757000EF904 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */; }; + 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */; }; + 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */; }; + 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */; }; 1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */; }; 1DE19EA72C1B420A0031804A /* FeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */; }; 1DE19EA82C1B420A0031804A /* SearchFeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */; }; 1DE19EB12C1B42200031804A /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB02C1B42200031804A /* NetworkService.swift */; }; - 1DE19EC22C1B422F0031804A /* RecipeListItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBA2C1B422F0031804A /* RecipeListItemViewModel.swift */; }; + 1DE19EBF2C1B422F0031804A /* RecipeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB42C1B422F0031804A /* RecipeDetailViewModel.swift */; }; + 1DE19EC02C1B422F0031804A /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB62C1B422F0031804A /* RecipeDetailView.swift */; }; 1DE19EC32C1B422F0031804A /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBB2C1B422F0031804A /* SearchBar.swift */; }; 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBC2C1B422F0031804A /* RecipeListViewController.swift */; }; 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBD2C1B422F0031804A /* RecipeListView.swift */; }; 1DE19EC62C1B422F0031804A /* RecipeListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBE2C1B422F0031804A /* RecipeListCell.swift */; }; 1DE19EC82C1B4C2D0031804A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 1DE19EC72C1B4C2D0031804A /* Kingfisher */; }; - 1DF829B12C299F1F00C337FC /* RecipeListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B02C299F1F00C337FC /* RecipeListInteractor.swift */; }; + 1DF829B42C2A7A7D00C337FC /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B32C2A7A7D00C337FC /* Fonts.swift */; }; + 1DF829B72C2A7CDC00C337FC /* UIImageViewImageLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B62C2A7CDC00C337FC /* UIImageViewImageLoading.swift */; }; + 1DF829B92C2A818D00C337FC /* String+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B82C2A818D00C337FC /* String+Validation.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -114,61 +118,55 @@ 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 = ""; }; + 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; + 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; + 1D39720C2C438D8300495014 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; + 1D39720E2C438E1F00495014 /* RecipeListMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListMapper.swift; sourceTree = ""; }; + 1D3972102C438E6A00495014 /* RecipeListItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RecipeListItemViewModel.swift; path = View/RecipeListItemViewModel.swift; sourceTree = ""; }; + 1D3972122C438E9C00495014 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + 1D3972132C438E9C00495014 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; + 1D3972162C438EAC00495014 /* UserDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDTO.swift; sourceTree = ""; }; + 1D3972192C438EDD00495014 /* SelectImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectImageCell.swift; sourceTree = ""; }; + 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeViewController.swift; sourceTree = ""; }; + 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeUploadImgaeCell.swift; sourceTree = ""; }; + 1D39721C2C438EDD00495014 /* AddRecipeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeView.swift; sourceTree = ""; }; + 1D3972222C438EF500495014 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; + 1D3972232C438EF500495014 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; + 1D3972242C438EF500495014 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; + 1D3972282C438F1C00495014 /* AddRecipeInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeInteractor.swift; sourceTree = ""; }; + 1D39722A2C438FD300495014 /* SaveRecipeUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SaveRecipeUseCase.swift; sourceTree = ""; }; + 1D39722C2C43904800495014 /* AddRecipeRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRepository.swift; sourceTree = ""; }; + 1D39722E2C43906300495014 /* RecipePostService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipePostService.swift; sourceTree = ""; }; + 1D3972302C43907300495014 /* RecipeUploadDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeUploadDTO.swift; sourceTree = ""; }; + 1D3972322C43907B00495014 /* ErrorResponseDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorResponseDTO.swift; sourceTree = ""; }; + 1D3972342C4390E200495014 /* RecipeUploadResponseDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeUploadResponseDTO.swift; sourceTree = ""; }; + 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCase.swift; sourceTree = ""; }; + 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailRepository.swift; sourceTree = ""; }; + 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailInteractor.swift; sourceTree = ""; }; 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeImageDTO.swift; sourceTree = ""; }; 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDTO.swift; sourceTree = ""; }; 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipePageDTO.swift; sourceTree = ""; }; 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkResponseDTO.swift; sourceTree = ""; }; - - 1DDE911B2C36717B0078DFD3 /* String+Validation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Validation.swift"; sourceTree = ""; }; - 1DDE911C2C36717B0078DFD3 /* UIImageViewImageLoading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageViewImageLoading.swift; sourceTree = ""; }; - 1DDE91202C3671840078DFD3 /* Fonts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; - 1DDE91222C3671910078DFD3 /* CustomNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; - 1DDE91242C3671B20078DFD3 /* RecipeListMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListMapper.swift; sourceTree = ""; }; - 1DDE91272C3671DB0078DFD3 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; - 1DDE91292C3671EC0078DFD3 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; - 1DDE912A2C3671EC0078DFD3 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; - 1DDE912D2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCase.swift; sourceTree = ""; }; - 1DDE912F2C36720A0078DFD3 /* RecipeDetailInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailInteractor.swift; sourceTree = ""; }; - 1DDE91322C3672170078DFD3 /* RecipeDetailCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailCoordinator.swift; sourceTree = ""; }; - 1DDE91342C3672230078DFD3 /* RecipeDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewModel.swift; sourceTree = ""; }; - 1DDE91362C36722A0078DFD3 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; - 1DDE91372C36722A0078DFD3 /* RecipeDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailView.swift; sourceTree = ""; }; - 1DDE913A2C3672410078DFD3 /* UserDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDTO.swift; sourceTree = ""; }; - 1DDE913C2C3672490078DFD3 /* RecipeDetailFetchService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailFetchService.swift; sourceTree = ""; }; - 1DDE913E2C3672720078DFD3 /* RecipeDetailRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailRepository.swift; sourceTree = ""; }; - 1DDE91402C3672850078DFD3 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; - - 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIConfig.swift; sourceTree = ""; }; - 1D7368B52C3442C8000EF904 /* String+Validation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Validation.swift"; sourceTree = ""; }; - 1D7368B62C3442C8000EF904 /* UIImageViewImageLoading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageViewImageLoading.swift; sourceTree = ""; }; - 1D7368B92C3442DE000EF904 /* RecipeListMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListMapper.swift; sourceTree = ""; }; - 1D7368C62C344378000EF904 /* UserDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDTO.swift; sourceTree = ""; }; - 1D7368C82C3443A1000EF904 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; - 1D7368C92C3443A1000EF904 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; - 1D7368CD2C344403000EF904 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; - 1D7368D12C34FADD000EF904 /* FetchRecipeDetailUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCase.swift; sourceTree = ""; }; - 1D7368D32C34FAE8000EF904 /* RecipeDetailInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailInteractor.swift; sourceTree = ""; }; - 1D7368D72C34FB07000EF904 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; - 1D7368D92C34FB14000EF904 /* RecipeDetailRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailRepository.swift; sourceTree = ""; }; - 1D7368DB2C34FB32000EF904 /* CustomNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; - 1D7368DF2C34FB38000EF904 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; - 1D7368E02C34FB38000EF904 /* RecipeDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailView.swift; sourceTree = ""; }; - 1D7368E12C34FB38000EF904 /* RecipeDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewModel.swift; sourceTree = ""; }; - 1D7368E62C34FB66000EF904 /* RecipeDetailCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailCoordinator.swift; sourceTree = ""; }; - 1D7368E92C34FBF7000EF904 /* MainTabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; - 1D95A0A32C37B0E200F09077 /* Fonts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; - 1D95A0A72C37C7D400F09077 /* RecipeDetailError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailError.swift; sourceTree = ""; }; - + 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListInteractor.swift; sourceTree = ""; }; + 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIConfig.swift; sourceTree = ""; }; + 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDeatilInteractorTests.swift; sourceTree = ""; }; + 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; + 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailError.swift; sourceTree = ""; }; + 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRecipeTests.swift; sourceTree = ""; }; + 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedListRepository.swift; sourceTree = ""; }; 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchFeedListRepository.swift; sourceTree = ""; }; 1DE19EB02C1B42200031804A /* NetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; - 1DE19EBA2C1B422F0031804A /* RecipeListItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListItemViewModel.swift; sourceTree = ""; }; + 1DE19EB42C1B422F0031804A /* RecipeDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewModel.swift; sourceTree = ""; }; + 1DE19EB62C1B422F0031804A /* RecipeDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailView.swift; sourceTree = ""; }; 1DE19EBB2C1B422F0031804A /* SearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = ""; }; 1DE19EBC2C1B422F0031804A /* RecipeListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListViewController.swift; sourceTree = ""; }; 1DE19EBD2C1B422F0031804A /* RecipeListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListView.swift; sourceTree = ""; }; 1DE19EBE2C1B422F0031804A /* RecipeListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListCell.swift; sourceTree = ""; }; - 1DF829B02C299F1F00C337FC /* RecipeListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListInteractor.swift; sourceTree = ""; }; + 1DF829B32C2A7A7D00C337FC /* Fonts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; + 1DF829B62C2A7CDC00C337FC /* UIImageViewImageLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageViewImageLoading.swift; sourceTree = ""; }; + 1DF829B82C2A818D00C337FC /* String+Validation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Validation.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -204,14 +202,11 @@ 1D12839F2C15E7A700C5A870 /* Entities */ = { isa = PBXGroup; children = ( - - 1DDE912A2C3671EC0078DFD3 /* Comment.swift */, - 1DDE91292C3671EC0078DFD3 /* User.swift */, - 1D95A0A72C37C7D400F09077 /* RecipeDetailError.swift */, + 1D3972132C438E9C00495014 /* Comment.swift */, + 1D3972122C438E9C00495014 /* User.swift */, 1D1283A12C15E94300C5A870 /* Recipe.swift */, - 1D7368C82C3443A1000EF904 /* Comment.swift */, - 1D7368C92C3443A1000EF904 /* User.swift */, 1D1283A32C15EA8100C5A870 /* RecipeType.swift */, + 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */, ); path = Entities; sourceTree = ""; @@ -220,9 +215,9 @@ isa = PBXGroup; children = ( 1D1283A92C15EBCF00C5A870 /* SearchFeedUseCase.swift */, - 1DDE912D2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift */, - 1D7368D12C34FADD000EF904 /* FetchRecipeDetailUseCase.swift */, + 1D39722A2C438FD300495014 /* SaveRecipeUseCase.swift */, 1D1283AB2C15EBE600C5A870 /* FetchFeedListUseCase.swift */, + 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */, ); path = UseCases; sourceTree = ""; @@ -248,9 +243,9 @@ children = ( 1D4741CB2C1B4F8D009381CE /* DTO */, 1D1283C92C16D9C600C5A870 /* RecipeFetchService.swift */, - 1DDE913C2C3672490078DFD3 /* RecipeDetailFetchService.swift */, 1DE19EB02C1B42200031804A /* NetworkService.swift */, - 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */, + 1D39722E2C43906300495014 /* RecipePostService.swift */, + 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */, ); path = Network; sourceTree = ""; @@ -280,15 +275,10 @@ 1D2C16E42BE532B700C04508 /* HomeCafeRecipes */ = { isa = PBXGroup; children = ( - 1DDE91312C3672170078DFD3 /* Coordinators */, - 1DDE91262C3671DB0078DFD3 /* Utilities */, - 1DDE911F2C3671840078DFD3 /* Resources */, - 1DDE911A2C36717B0078DFD3 /* Extensions */, - - 1D95A0A22C37B0E200F09077 /* Resources */, - 1D7368E52C34FB66000EF904 /* Coordinators */, - 1D7368CC2C344403000EF904 /* Utilities */, - 1D7368B42C3442C8000EF904 /* Extensions */, + 1D3972212C438EF500495014 /* Router */, + 1D39720B2C438D8300495014 /* Utilities */, + 1DF829B52C2A7C8600C337FC /* Extensions */, + 1DF829B22C2A7A0B00C337FC /* Resources */, 1DE19EB22C1B422F0031804A /* Presentation */, 1D1283AD2C16974B00C5A870 /* Data */, 1D740B402C15E6680001B704 /* Domain */, @@ -306,6 +296,8 @@ isa = PBXGroup; children = ( 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */, + 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */, + 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */, ); path = HomeCafeRecipesTests; sourceTree = ""; @@ -319,147 +311,94 @@ path = HomeCafeRecipesUITests; sourceTree = ""; }; - 1D4741CB2C1B4F8D009381CE /* DTO */ = { - isa = PBXGroup; - children = ( - 1D7368C62C344378000EF904 /* UserDTO.swift */, - 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */, - 1DDE91402C3672850078DFD3 /* RecipeDetailDTO.swift */, - 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */, - 1DDE913A2C3672410078DFD3 /* UserDTO.swift */, - 1D7368D72C34FB07000EF904 /* RecipeDetailDTO.swift */, - 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */, - 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */, - ); - path = DTO; - sourceTree = ""; - }; - 1D7368B42C3442C8000EF904 /* Extensions */ = { + 1D2C6F612C2446AF004BB54E /* Tabbar */ = { isa = PBXGroup; children = ( - 1D7368B52C3442C8000EF904 /* String+Validation.swift */, - 1D7368B62C3442C8000EF904 /* UIImageViewImageLoading.swift */, + 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */, ); - path = Extensions; + path = Tabbar; sourceTree = ""; }; - 1D7368CC2C344403000EF904 /* Utilities */ = { + 1D39720B2C438D8300495014 /* Utilities */ = { isa = PBXGroup; children = ( - 1D7368CD2C344403000EF904 /* DateFormatter+Extensions.swift */, + 1D39720C2C438D8300495014 /* DateFormatter+Extensions.swift */, ); path = Utilities; sourceTree = ""; }; - 1D7368DD2C34FB38000EF904 /* Feed */ = { - isa = PBXGroup; - children = ( - 1D7368DE2C34FB38000EF904 /* View */, - 1D7368E12C34FB38000EF904 /* RecipeDetailViewModel.swift */, - ); - path = Feed; - sourceTree = ""; - }; - 1D7368DE2C34FB38000EF904 /* View */ = { + 1D3972182C438EDD00495014 /* UploadRecipe */ = { isa = PBXGroup; children = ( - 1D7368DF2C34FB38000EF904 /* RecipeDetailViewController.swift */, - 1D7368E02C34FB38000EF904 /* RecipeDetailView.swift */, + 1D3972192C438EDD00495014 /* SelectImageCell.swift */, + 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */, + 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */, + 1D39721C2C438EDD00495014 /* AddRecipeView.swift */, ); - path = View; + path = UploadRecipe; sourceTree = ""; }; - 1D7368E52C34FB66000EF904 /* Coordinators */ = { + 1D3972212C438EF500495014 /* Router */ = { isa = PBXGroup; children = ( - 1D7368E62C34FB66000EF904 /* RecipeDetailCoordinator.swift */, + 1D3972222C438EF500495014 /* AddRecipeRouter.swift */, + 1D3972232C438EF500495014 /* RecipeListRouter.swift */, + 1D3972242C438EF500495014 /* Router.swift */, ); - path = Coordinators; + path = Router; sourceTree = ""; }; - 1D7368E82C34FBF7000EF904 /* Tabbar */ = { + 1D4741CB2C1B4F8D009381CE /* DTO */ = { isa = PBXGroup; children = ( - 1D7368E92C34FBF7000EF904 /* MainTabBarController.swift */, + 1D3972162C438EAC00495014 /* UserDTO.swift */, + 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */, + 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */, + 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */, + 1D3972302C43907300495014 /* RecipeUploadDTO.swift */, + 1D3972342C4390E200495014 /* RecipeUploadResponseDTO.swift */, + 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */, + 1D3972322C43907B00495014 /* ErrorResponseDTO.swift */, + 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */, ); - path = Tabbar; + path = DTO; sourceTree = ""; }; 1D740B402C15E6680001B704 /* Domain */ = { isa = PBXGroup; children = ( - 1DF829AF2C299F1F00C337FC /* Interactor */, + 1DE19EA12C1B41FE0031804A /* Interactor */, 1D1283A02C15E92C00C5A870 /* UseCases */, 1D12839F2C15E7A700C5A870 /* Entities */, ); path = Domain; sourceTree = ""; }; - - 1DDE911A2C36717B0078DFD3 /* Extensions */ = { - isa = PBXGroup; - children = ( - 1DDE911B2C36717B0078DFD3 /* String+Validation.swift */, - 1DDE911C2C36717B0078DFD3 /* UIImageViewImageLoading.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 1DDE911F2C3671840078DFD3 /* Resources */ = { - isa = PBXGroup; - children = ( - 1DDE91202C3671840078DFD3 /* Fonts.swift */, - - 1D95A0A22C37B0E200F09077 /* Resources */ = { - isa = PBXGroup; - children = ( - 1D95A0A32C37B0E200F09077 /* Fonts.swift */, - - ); - path = Resources; - sourceTree = ""; - }; - - 1DDE91262C3671DB0078DFD3 /* Utilities */ = { - isa = PBXGroup; - children = ( - 1DDE91272C3671DB0078DFD3 /* DateFormatter+Extensions.swift */, - ); - path = Utilities; - sourceTree = ""; - }; - 1DDE91312C3672170078DFD3 /* Coordinators */ = { + 1DDFFD822C1C09AB0083B077 /* Mapper */ = { isa = PBXGroup; children = ( - 1DDE91322C3672170078DFD3 /* RecipeDetailCoordinator.swift */, + 1D39720E2C438E1F00495014 /* RecipeListMapper.swift */, ); - path = Coordinators; + path = Mapper; sourceTree = ""; }; - 1DDFFD822C1C09AB0083B077 /* Mapper */ = { - isa = PBXGroup; - children = ( - 1DDE91242C3671B20078DFD3 /* RecipeListMapper.swift */, - - 1DDFFD822C1C09AB0083B077 /* Mapper */ = { + 1DE19EA12C1B41FE0031804A /* Interactor */ = { isa = PBXGroup; children = ( - 1D7368B92C3442DE000EF904 /* RecipeListMapper.swift */, - + 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */, + 1D3972282C438F1C00495014 /* AddRecipeInteractor.swift */, + 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */, ); - path = Mapper; + path = Interactor; sourceTree = ""; }; 1DE19EA42C1B420A0031804A /* Repositories */ = { isa = PBXGroup; children = ( + 1D39722C2C43904800495014 /* AddRecipeRepository.swift */, 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */, - - 1DDE913E2C3672720078DFD3 /* RecipeDetailRepository.swift */, - - 1D7368D92C34FB14000EF904 /* RecipeDetailRepository.swift */, - 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */, + 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */, ); path = Repositories; sourceTree = ""; @@ -467,22 +406,20 @@ 1DE19EB22C1B422F0031804A /* Presentation */ = { isa = PBXGroup; children = ( - 1DDE91222C3671910078DFD3 /* CustomNavigationBar.swift */, - 1D7368E82C34FBF7000EF904 /* Tabbar */, - 1D7368DD2C34FB38000EF904 /* Feed */, - 1D7368DB2C34FB32000EF904 /* CustomNavigationBar.swift */, - + 1D3972182C438EDD00495014 /* UploadRecipe */, + 1D2C6F612C2446AF004BB54E /* Tabbar */, 1DDFFD822C1C09AB0083B077 /* Mapper */, + 1DE19EB32C1B422F0031804A /* Feed */, 1DE19EB72C1B422F0031804A /* FeedList */, + 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */, ); path = Presentation; sourceTree = ""; }; - 1DE19EB32C1B422F0031804A /* Feed */ = { isa = PBXGroup; children = ( - 1DDE91342C3672230078DFD3 /* RecipeDetailViewModel.swift */, + 1DE19EB42C1B422F0031804A /* RecipeDetailViewModel.swift */, 1DE19EB52C1B422F0031804A /* View */, ); path = Feed; @@ -491,16 +428,16 @@ 1DE19EB52C1B422F0031804A /* View */ = { isa = PBXGroup; children = ( - 1DDE91372C36722A0078DFD3 /* RecipeDetailView.swift */, - 1DDE91362C36722A0078DFD3 /* RecipeDetailViewController.swift */, + 1DE19EB62C1B422F0031804A /* RecipeDetailView.swift */, + 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */, ); path = View; sourceTree = ""; }; - 1DE19EB72C1B422F0031804A /* FeedList */ = { isa = PBXGroup; children = ( + 1D3972102C438E6A00495014 /* RecipeListItemViewModel.swift */, 1DE19EB92C1B422F0031804A /* View */, ); path = FeedList; @@ -509,7 +446,6 @@ 1DE19EB92C1B422F0031804A /* View */ = { isa = PBXGroup; children = ( - 1DE19EBA2C1B422F0031804A /* RecipeListItemViewModel.swift */, 1DE19EBB2C1B422F0031804A /* SearchBar.swift */, 1DE19EBC2C1B422F0031804A /* RecipeListViewController.swift */, 1DE19EBD2C1B422F0031804A /* RecipeListView.swift */, @@ -518,14 +454,21 @@ path = View; sourceTree = ""; }; - 1DF829AF2C299F1F00C337FC /* Interactor */ = { + 1DF829B22C2A7A0B00C337FC /* Resources */ = { isa = PBXGroup; children = ( - 1DDE912F2C36720A0078DFD3 /* RecipeDetailInteractor.swift */, - 1D7368D32C34FAE8000EF904 /* RecipeDetailInteractor.swift */, - 1DF829B02C299F1F00C337FC /* RecipeListInteractor.swift */, + 1DF829B32C2A7A7D00C337FC /* Fonts.swift */, ); - path = Interactor; + path = Resources; + sourceTree = ""; + }; + 1DF829B52C2A7C8600C337FC /* Extensions */ = { + isa = PBXGroup; + children = ( + 1DF829B62C2A7CDC00C337FC /* UIImageViewImageLoading.swift */, + 1DF829B82C2A818D00C337FC /* String+Validation.swift */, + ); + path = Extensions; sourceTree = ""; }; /* End PBXGroup section */ @@ -669,77 +612,60 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1DF829B12C299F1F00C337FC /* RecipeListInteractor.swift in Sources */, + 1D39722B2C438FD300495014 /* SaveRecipeUseCase.swift in Sources */, + 1D3972292C438F1C00495014 /* AddRecipeInteractor.swift in Sources */, + 1D439E9E2C2C598A008530A5 /* RecipeDetailRepository.swift in Sources */, + 1D2C6F6C2C27051D004BB54E /* CustomNavigationBar.swift in Sources */, + 1D3972202C438EDD00495014 /* AddRecipeView.swift in Sources */, 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */, - 1D7368EA2C34FBF7000EF904 /* MainTabBarController.swift in Sources */, - 1D60CC452C3F932D00D08FA3 /* APIConfig.swift in Sources */, - 1D7368D42C34FAE8000EF904 /* RecipeDetailInteractor.swift in Sources */, 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */, - - 1DDE911E2C36717B0078DFD3 /* UIImageViewImageLoading.swift in Sources */, - 1DDE912B2C3671EC0078DFD3 /* User.swift in Sources */, - 1DDE91352C3672230078DFD3 /* RecipeDetailViewModel.swift in Sources */, - 1DDE913B2C3672410078DFD3 /* UserDTO.swift in Sources */, 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, - 1DDE91392C36722A0078DFD3 /* RecipeDetailView.swift in Sources */, - - 1D7368CB2C3443A1000EF904 /* User.swift in Sources */, - 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, - 1D7368CE2C344403000EF904 /* DateFormatter+Extensions.swift in Sources */, - 1D7368E32C34FB38000EF904 /* RecipeDetailView.swift in Sources */, - + 1D2C6F652C2446D8004BB54E /* MainTabBarController.swift in Sources */, + 1D39721D2C438EDD00495014 /* SelectImageCell.swift in Sources */, + 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */, 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */, - 1DDE91282C3671DB0078DFD3 /* DateFormatter+Extensions.swift in Sources */, - 1DDE91332C3672170078DFD3 /* RecipeDetailCoordinator.swift in Sources */, - 1DDE91382C36722A0078DFD3 /* RecipeDetailViewController.swift in Sources */, 1DE19EB12C1B42200031804A /* NetworkService.swift in Sources */, - - 1DDE913F2C3672720078DFD3 /* RecipeDetailRepository.swift in Sources */, - 1D1283AC2C15EBE600C5A870 /* FetchFeedListUseCase.swift in Sources */, - 1DDE91252C3671B20078DFD3 /* RecipeListMapper.swift in Sources */, - + 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */, 1D1283AC2C15EBE600C5A870 /* FetchFeedListUseCase.swift in Sources */, - 1D7368E22C34FB38000EF904 /* RecipeDetailViewController.swift in Sources */, - + 1DF829B72C2A7CDC00C337FC /* UIImageViewImageLoading.swift in Sources */, + 1D39722F2C43906300495014 /* RecipePostService.swift in Sources */, + 1D3972252C438EF500495014 /* AddRecipeRouter.swift in Sources */, + 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */, 1D1283A42C15EA8100C5A870 /* RecipeType.swift in Sources */, - 1D7368D82C34FB07000EF904 /* RecipeDetailDTO.swift in Sources */, - 1D7368DA2C34FB14000EF904 /* RecipeDetailRepository.swift in Sources */, + 1D3972312C43907300495014 /* RecipeUploadDTO.swift in Sources */, + 1DF829B42C2A7A7D00C337FC /* Fonts.swift in Sources */, 1D4741D22C1B4F8D009381CE /* RecipeDTO.swift in Sources */, + 1DE19EC02C1B422F0031804A /* RecipeDetailView.swift in Sources */, 1D1283AA2C15EBCF00C5A870 /* SearchFeedUseCase.swift in Sources */, + 1D39722D2C43904800495014 /* AddRecipeRepository.swift in Sources */, + 1D3972142C438E9C00495014 /* User.swift in Sources */, + 1D3972332C43907B00495014 /* ErrorResponseDTO.swift in Sources */, 1DE19EA82C1B420A0031804A /* SearchFeedListRepository.swift in Sources */, - - 1D95A0A42C37B0E200F09077 /* Fonts.swift in Sources */, - - 1DE19EC22C1B422F0031804A /* RecipeListItemViewModel.swift in Sources */, - 1D7368C72C344378000EF904 /* UserDTO.swift in Sources */, 1DE19EC32C1B422F0031804A /* SearchBar.swift in Sources */, + 1D439EA22C2C6997008530A5 /* RecipeDetailInteractor.swift in Sources */, + 1D73686E2C305757000EF904 /* RecipeDetailDTO.swift in Sources */, + 1D4741D72C1B4FF4009381CE /* RecipeListInteractor.swift in Sources */, 1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */, - 1DDE91232C3671920078DFD3 /* CustomNavigationBar.swift in Sources */, 1D4741D12C1B4F8D009381CE /* RecipeImageDTO.swift in Sources */, - 1DDE91412C3672850078DFD3 /* RecipeDetailDTO.swift in Sources */, 1DE19EA72C1B420A0031804A /* FeedListRepository.swift in Sources */, + 1D3972112C438E6A00495014 /* RecipeListItemViewModel.swift in Sources */, + 1D3972352C4390E200495014 /* RecipeUploadResponseDTO.swift in Sources */, 1DE19EC62C1B422F0031804A /* RecipeListCell.swift in Sources */, - - 1DDE91212C3671840078DFD3 /* Fonts.swift in Sources */, - 1DDE913D2C3672490078DFD3 /* RecipeDetailFetchService.swift in Sources */, - 1DDE91302C36720A0078DFD3 /* RecipeDetailInteractor.swift in Sources */, - 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */, - 1DDE912C2C3671EC0078DFD3 /* Comment.swift in Sources */, - 1DDE911D2C36717B0078DFD3 /* String+Validation.swift in Sources */, - 1D7368E72C34FB66000EF904 /* RecipeDetailCoordinator.swift in Sources */, - 1D7368D22C34FADD000EF904 /* FetchRecipeDetailUseCase.swift in Sources */, + 1D3972272C438EF500495014 /* Router.swift in Sources */, + 1DF829B92C2A818D00C337FC /* String+Validation.swift in Sources */, 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */, - 1D95A0A82C37C7D400F09077 /* RecipeDetailError.swift in Sources */, + 1DE19EBF2C1B422F0031804A /* RecipeDetailViewModel.swift in Sources */, + 1D39720F2C438E1F00495014 /* RecipeListMapper.swift in Sources */, + 1D3972262C438EF500495014 /* RecipeListRouter.swift in Sources */, 1D1283A22C15E94300C5A870 /* Recipe.swift in Sources */, - 1D7368BA2C3442DE000EF904 /* RecipeListMapper.swift in Sources */, - 1D7368CA2C3443A1000EF904 /* Comment.swift in Sources */, + 1D3972152C438E9C00495014 /* Comment.swift in Sources */, + 1D39721E2C438EDD00495014 /* AddRecipeViewController.swift in Sources */, + 1D39721F2C438EDD00495014 /* RecipeUploadImgaeCell.swift in Sources */, 1D1283CA2C16D9C600C5A870 /* RecipeFetchService.swift in Sources */, - 1DDE912E2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift in Sources */, - 1D7368E42C34FB38000EF904 /* RecipeDetailViewModel.swift in Sources */, - 1D7368B82C3442C8000EF904 /* UIImageViewImageLoading.swift in Sources */, 1D4741D42C1B4F8D009381CE /* NetworkResponseDTO.swift in Sources */, - 1D7368B72C3442C8000EF904 /* String+Validation.swift in Sources */, - 1D7368DC2C34FB32000EF904 /* CustomNavigationBar.swift in Sources */, + 1D39720D2C438D8300495014 /* DateFormatter+Extensions.swift in Sources */, + 1D3972172C438EAC00495014 /* UserDTO.swift in Sources */, + 1D439E9C2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -747,8 +673,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1D60CC462C3F932D00D08FA3 /* APIConfig.swift in Sources */, + 1D6958DF2C3D5E35008604B3 /* NetworkService.swift in Sources */, + 1D6958DC2C3D5E20008604B3 /* RecipeDetailRepository.swift in Sources */, + 1D6958E12C3D5E44008604B3 /* RecipeDetailDTO.swift in Sources */, + 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */, + 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */, + 1D6958DE2C3D5E2C008604B3 /* RecipeType.swift in Sources */, + 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */, 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */, + 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */, + 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */, + 1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */, + 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */, + 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */, + 1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift new file mode 100644 index 0000000..2666e5c --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -0,0 +1,211 @@ +// +// AddRecipeViewController.swift +// HomeCafeRecipes +// +// Created by 김건호 on 6/20/24. +// + +import UIKit +import PhotosUI + +import RxSwift + +final class AddRecipeViewController: UIViewController { + + private let contentView = AddRecipeView() + private let recipeType: RecipeType + private let addRecipeInteractor: AddRecipeInteractor + private let disposeBag = DisposeBag() + + init(recipeType: RecipeType, addRecipeInteractor: AddRecipeInteractor) { + self.recipeType = recipeType + self.addRecipeInteractor = addRecipeInteractor + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = contentView + } + + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + contentView.delegate = self + contentView.submitButton.addTarget(self, action: #selector(saveRecipe), for: .touchUpInside) + setupNavigationBar() + } + + private func setupUI() { + view.backgroundColor = .white + NSLayoutConstraint.activate([ + contentView.topAnchor.constraint(equalTo: view.topAnchor), + contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } + + private func setupNavigationBar() { + switch recipeType { + case .coffee: + contentView.customNavigationBar.setTitle("커피 레시피 작성") + case .dessert: + contentView.customNavigationBar.setTitle("디저트 레시피 작성") + } + contentView.customNavigationBar.backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside) + } + + @objc private func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + @objc private func saveRecipe() { + guard !contentView.images.isEmpty else { + showAlert(title: "이미지 없음", message: "최소 한 장의 이미지를 추가해 주세요.") + return + } + guard let title = contentView.titleTextField.text, let description = contentView.descriptionTextView.text else { + showAlert(title: "입력 오류", message: "제목과 설명을 모두 입력해 주세요.") + return + } + + guard !title.isBlank else { + showAlert(title: "제목 없음", message: "제목을 입력해 주세요.") + return + } + + guard description.count > 10 else { + showAlert(title: "설명 부족", message: "설명을 10자 이상 입력해 주세요.") + return + } + + saveRecipeToServer(title: title, description: description, images: contentView.images) + } + + private func saveRecipeToServer(title: String, description: String, images: [UIImage]) { + + // MARK: 임시 userID 설정 + let userId = 6 + let recipeType = recipeType.rawValue + + addRecipeInteractor.saveRecipe(userId: userId, recipeType: recipeType, title: title, description: description, images: images) + .subscribe(onSuccess: { recipe in + DispatchQueue.main.async { + self.showSuccessAlert(title: "업로드 성공", message: "레시피가 성공적으로 업로드되었습니다.", success: true) + } }, onFailure: { error in + DispatchQueue.main.async { + self.showSuccessAlert(title: "업로드 실패", message: "레시피 업로드에 실패했습니다.", success: false) + } + }) + .disposed(by: disposeBag) + } + + private func showSuccessAlert(title: String, message: String, success: Bool) { + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in + if success { + self.navigationController?.popViewController(animated: true) + } + } + alert.addAction(confirmAction) + present(alert, animated: true, completion: nil) + } + + private func showAlert(title: String, message: String) { + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "확인", style: .default, handler: nil)) + present(alert, animated: true, completion: nil) + } + + private func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) { + let status = PHPhotoLibrary.authorizationStatus() + switch status { + case .authorized: + completion(true) + case .denied, .restricted: + completion(false) + case .notDetermined: + PHPhotoLibrary.requestAuthorization { status in + DispatchQueue.main.async { + completion(status == .authorized) + } + } + @unknown default: + completion(false) + } + } +} + +// MARK: AddRecipeViewDelegate + +extension AddRecipeViewController: AddRecipeViewDelegate { + func selectImageButtonTapped() { + checkPhotoLibraryPermission { granted in + if granted { + var config = PHPickerConfiguration() + config.selectionLimit = 5 - self.contentView.images.count + config.filter = .images + + let picker = PHPickerViewController(configuration: config) + picker.delegate = self + self.present(picker, animated: true, completion: nil) + } else { + let alert = UIAlertController(title: "권한 필요", message: "사진 라이브러리에 접근하려면 권한이 필요합니다.", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "설정", style: .default) { _ in + if let appSettings = URL(string: UIApplication.openSettingsURLString) { + UIApplication.shared.open(appSettings, options: [:], completionHandler: nil) + } + }) + alert.addAction(UIAlertAction(title: "취소", style: .cancel, handler: nil)) + self.present(alert, animated: true, completion: nil) + } + } + } + + func didTapDeleteButton(at index: Int) { + contentView.images.remove(at: index) + } +} + +// MARK: PHPickerViewControllerDelegate + +extension AddRecipeViewController: PHPickerViewControllerDelegate { + func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { + picker.dismiss(animated: true, completion: nil) + + let dispatchGroup = DispatchGroup() + var newImages: [UIImage] = [] + + for result in results { + dispatchGroup.enter() + if result.itemProvider.canLoadObject(ofClass: UIImage.self) { + result.itemProvider.loadObject(ofClass: UIImage.self) { (object, error) in + if let image = object as? UIImage { + newImages.append(image) + } + dispatchGroup.leave() + } + } else { + dispatchGroup.leave() + } + } + + dispatchGroup.notify(queue: .main) { + self.contentView.images.append(contentsOf: newImages) + } + } +} + +// MARK: ImageCollectionViewCellDelegate + +extension AddRecipeViewController: ImageCollectionViewCellDelegate { + func didTapDeleteButton(in cell: RecipeUploadImgaeCell) { + if let indexPath = contentView.collectionView.indexPath(for: cell) { + contentView.images.remove(at: indexPath.item - 1) + } + } +} From 69339672659ba731ad9c91dd00aba9790ccc903d Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 14 Jul 2024 14:12:12 +0900 Subject: [PATCH 02/51] =?UTF-8?q?Feat:=20SelectImageCell=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/SelectImageCell.swift | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/SelectImageCell.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/SelectImageCell.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/SelectImageCell.swift new file mode 100644 index 0000000..09ed425 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/SelectImageCell.swift @@ -0,0 +1,42 @@ +// +// SelectImageCell.swift +// HomeCafeRecipes +// +// Created by 김건호 on 6/24/24. +// + +import UIKit + +final class SelectImageCell: UICollectionViewCell { + + let selectImageButton = UIButton(type: .system) + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + contentView.addSubview(selectImageButton) + + selectImageButton.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + selectImageButton.topAnchor.constraint(equalTo: contentView.topAnchor), + selectImageButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + selectImageButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + selectImageButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) + ]) + + selectImageButton.setImage(UIImage(systemName: "camera"), for: .normal) + selectImageButton.tintColor = .gray + selectImageButton.layer.borderColor = UIColor.gray.cgColor + selectImageButton.layer.borderWidth = 1 + selectImageButton.layer.cornerRadius = 10 + } +} + From 9b07f3b820774ef90fefc3cd39f6701f90388772 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 14 Jul 2024 14:13:28 +0900 Subject: [PATCH 03/51] =?UTF-8?q?Feat:=20RecipeUploadImgaeCell=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/RecipeUploadImgaeCell.swift | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift new file mode 100644 index 0000000..2eb5000 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift @@ -0,0 +1,100 @@ +// +// RecipeUploadImgaeCell.swift +// HomeCafeRecipes +// +// Created by 김건호 on 6/23/24. +// + +import UIKit + +protocol ImageCollectionViewCellDelegate: AnyObject { + func didTapDeleteButton(in cell: RecipeUploadImgaeCell) +} + +final class RecipeUploadImgaeCell: UICollectionViewCell { + + private let imageView = UIImageView() + private let representativeLabel = UILabel() + private let deleteButton = UIButton(type: .system) + + weak var delegate: ImageCollectionViewCellDelegate? + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + setupImageView() + setupLabel() + setupDeleteButton() + addSubviews() + setupConstraints() + } + + private func setupImageView() { + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.layer.cornerRadius = 10 + } + + private func setupLabel() { + representativeLabel.font = .systemFont(ofSize: 12, weight: .bold) + representativeLabel.textColor = .white + representativeLabel.backgroundColor = .gray + representativeLabel.text = "대표 사진" + representativeLabel.textAlignment = .center + representativeLabel.isHidden = true + representativeLabel.layer.cornerRadius = 10 + representativeLabel.clipsToBounds = true + } + + private func setupDeleteButton() { + deleteButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) + deleteButton.tintColor = .white + deleteButton.addTarget(self, action: #selector(deleteImage), for: .touchUpInside) + } + + private func addSubviews() { + contentView.addSubview(imageView) + contentView.addSubview(representativeLabel) + contentView.addSubview(deleteButton) + } + + private func setupConstraints() { + imageView.translatesAutoresizingMaskIntoConstraints = false + representativeLabel.translatesAutoresizingMaskIntoConstraints = false + deleteButton.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + imageView.topAnchor.constraint(equalTo: contentView.topAnchor), + imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + + representativeLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + representativeLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + representativeLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + representativeLabel.heightAnchor.constraint(equalToConstant: 20), + + deleteButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5), + deleteButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5), + deleteButton.widthAnchor.constraint(equalToConstant: 20), + deleteButton.heightAnchor.constraint(equalToConstant: 20) + ]) + + } + + func configure(with image: UIImage, isRepresentative: Bool) { + imageView.image = image + representativeLabel.isHidden = !isRepresentative + } + + @objc private func deleteImage() { + delegate?.didTapDeleteButton(in: self) + } +} From ff8582118cadb906a3c7a69baba4cdf82776a954 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 14 Jul 2024 17:27:39 +0900 Subject: [PATCH 04/51] =?UTF-8?q?Feat:=20AddRecipeView=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeView.swift | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift new file mode 100644 index 0000000..c3e75e5 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -0,0 +1,212 @@ +// +// AddRecipeView.swift +// HomeCafeRecipes +// +// Created by 김건호 on 6/22/24. +// + +import UIKit + +protocol AddRecipeViewDelegate: AnyObject { + func selectImageButtonTapped() + func didTapDeleteButton(at index: Int) +} + +final class AddRecipeView: UIView { + + private let imageCounterLabel = UILabel() + private let titleLabel = UILabel() + private let descriptionLabel = UILabel() + let collectionView: UICollectionView + let titleTextField = UITextField() + let descriptionTextView = UITextView() + let submitButton = UIButton(type: .system) + let customNavigationBar = CustomNavigationBar() + + weak var delegate: AddRecipeViewDelegate? + + var images: [UIImage] = [] { + didSet { + collectionView.reloadData() + imageCounterLabel.text = "\(images.count)/5" + } + } + + override init(frame: CGRect) { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumLineSpacing = 10 + layout.itemSize = CGSize(width: 100, height: 100) + collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.backgroundColor = .clear + + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + backgroundColor = .white + + setupLabel() + setupCollectionView() + setupImageCounterLabel() + setupTitleTextField() + setupDescriptionTextView() + setupSubmitButton() + setupCustomNavigationBar() + addSubviews() + setupConstraints() + } + + private func setupLabel() { + titleLabel.text = "제목" + descriptionLabel.text = "내용" + } + + private func setupCollectionView() { + collectionView.dataSource = self + collectionView.delegate = self + collectionView.register(RecipeUploadImgaeCell.self, forCellWithReuseIdentifier: "ImageCell") + collectionView.register(SelectImageCell.self, forCellWithReuseIdentifier: "SelectImageCell") + } + private func setupImageCounterLabel() { + imageCounterLabel.font = Fonts.bodyFont + imageCounterLabel.textColor = .gray + imageCounterLabel.text = "0/5" + } + + private func setupTitleTextField() { + titleTextField.placeholder = "제목을 입력하세요" + titleTextField.borderStyle = .roundedRect + } + + private func setupDescriptionTextView() { + descriptionTextView.layer.borderColor = UIColor.lightGray.cgColor + descriptionTextView.layer.borderWidth = 1 + descriptionTextView.layer.cornerRadius = 5 + descriptionTextView.font = Fonts.titleFont + } + + private func setupSubmitButton() { + submitButton.setTitle("레시피 등록", for: .normal) + submitButton.setTitleColor(.white, for: .normal) + submitButton.backgroundColor = .blue + submitButton.layer.cornerRadius = 5 + } + + private func setupCustomNavigationBar() { + customNavigationBar.translatesAutoresizingMaskIntoConstraints = false + } + + private func addSubviews() { + addSubview(customNavigationBar) + addSubview(titleLabel) + addSubview(descriptionLabel) + addSubview(collectionView) + addSubview(imageCounterLabel) + addSubview(titleTextField) + addSubview(descriptionTextView) + addSubview(submitButton) + } + + private func setupConstraints() { + customNavigationBar.translatesAutoresizingMaskIntoConstraints = false + titleLabel.translatesAutoresizingMaskIntoConstraints = false + descriptionLabel.translatesAutoresizingMaskIntoConstraints = false + collectionView.translatesAutoresizingMaskIntoConstraints = false + imageCounterLabel.translatesAutoresizingMaskIntoConstraints = false + titleTextField.translatesAutoresizingMaskIntoConstraints = false + descriptionTextView.translatesAutoresizingMaskIntoConstraints = false + submitButton.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + customNavigationBar.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor), + customNavigationBar.leadingAnchor.constraint(equalTo: leadingAnchor), + customNavigationBar.trailingAnchor.constraint(equalTo: trailingAnchor), + customNavigationBar.heightAnchor.constraint(equalToConstant: 44), + + collectionView.topAnchor.constraint(equalTo: customNavigationBar.bottomAnchor, constant: 20), + collectionView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + collectionView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + collectionView.heightAnchor.constraint(equalToConstant: 120), + + imageCounterLabel.topAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 10), + imageCounterLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + + titleLabel.topAnchor.constraint(equalTo: imageCounterLabel.bottomAnchor, constant: 40), + titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + + titleTextField.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15), + titleTextField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + titleTextField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + titleTextField.heightAnchor.constraint(equalToConstant: 40), + + descriptionLabel.topAnchor.constraint(equalTo: titleTextField.bottomAnchor, constant: 20), + descriptionLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + descriptionLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + + descriptionTextView.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 15), + descriptionTextView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + descriptionTextView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + descriptionTextView.heightAnchor.constraint(equalToConstant: 200), + + submitButton.topAnchor.constraint(equalTo: descriptionTextView.bottomAnchor, constant: 20), + submitButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + submitButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + submitButton.heightAnchor.constraint(equalToConstant: 50) + ]) + } +} + +// MARK: UICollectionViewDataSource + +extension AddRecipeView: UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return images.count + 1 + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if indexPath.item == 0 { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SelectImageCell", for: indexPath) as! SelectImageCell + cell.selectImageButton.addTarget(self, action: #selector(selectImageButtonTapped), for: .touchUpInside) + return cell + } else { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! RecipeUploadImgaeCell + let image = images[indexPath.item - 1] + cell.configure(with: image, isRepresentative: indexPath.item == 1) + cell.delegate = self + return cell + } + } +} + +// MARK: UICollectionViewDelegate + +extension AddRecipeView: UICollectionViewDelegate { + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + if indexPath.item == 0 { + selectImageButtonTapped() + } + } +} + +extension AddRecipeView { + @objc private func selectImageButtonTapped() { + delegate?.selectImageButtonTapped() + } +} + +// MARK: ImageCollectionViewCellDelegate + +extension AddRecipeView: ImageCollectionViewCellDelegate { + func didTapDeleteButton(in cell: RecipeUploadImgaeCell) { + if let indexPath = collectionView.indexPath(for: cell) { + delegate?.didTapDeleteButton(at: indexPath.item - 1) + } + } +} From f37a122949f1477d9a1ca259dd24267d0aae766d Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 15 Jul 2024 00:55:32 +0900 Subject: [PATCH 05/51] =?UTF-8?q?Fix:=20RecipeListInteractor=EC=9D=98=20ou?= =?UTF-8?q?put=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes.xcodeproj/project.pbxproj | 435 +++++++----------- .../Interactor/RecipeListInteractor.swift | 55 +-- .../View/RecipeListViewController.swift | 26 +- 3 files changed, 200 insertions(+), 316 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj index 2eefc42..8d2bc08 100644 --- a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj +++ b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj @@ -21,63 +21,57 @@ 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 */; }; + 1D2C6F652C2446D8004BB54E /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */; }; + 1D2C6F6C2C27051D004BB54E /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */; }; + 1D3972522C44167A00495014 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39724F2C44167A00495014 /* AddRecipeRouter.swift */; }; + 1D3972532C44167A00495014 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972502C44167A00495014 /* RecipeListRouter.swift */; }; + 1D3972542C44167A00495014 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972512C44167A00495014 /* Router.swift */; }; + 1D3972572C44168E00495014 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972562C44168E00495014 /* DateFormatter+Extensions.swift */; }; + 1D39725A2C4416A300495014 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972582C4416A300495014 /* User.swift */; }; + 1D39725B2C4416A300495014 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972592C4416A300495014 /* Comment.swift */; }; + 1D39725F2C4416CE00495014 /* RecipeListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39725D2C4416CE00495014 /* RecipeListMapper.swift */; }; + 1D3972622C4416E400495014 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972612C4416E400495014 /* UIView+Extensions.swift */; }; + 1D3972642C4416F500495014 /* UserDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972632C4416F400495014 /* UserDTO.swift */; }; + 1D3972662C44171100495014 /* RecipeListItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972652C44171100495014 /* RecipeListItemViewModel.swift */; }; + 1D439E9C2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */; }; + 1D439E9E2C2C598A008530A5 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */; }; + 1D439EA22C2C6997008530A5 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */; }; 1D4741D12C1B4F8D009381CE /* RecipeImageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */; }; 1D4741D22C1B4F8D009381CE /* RecipeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */; }; 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */; }; 1D4741D42C1B4F8D009381CE /* NetworkResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */; }; - - 1DDE911D2C36717B0078DFD3 /* String+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE911B2C36717B0078DFD3 /* String+Validation.swift */; }; - 1DDE911E2C36717B0078DFD3 /* UIImageViewImageLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE911C2C36717B0078DFD3 /* UIImageViewImageLoading.swift */; }; - 1DDE91212C3671840078DFD3 /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91202C3671840078DFD3 /* Fonts.swift */; }; - 1DDE91232C3671920078DFD3 /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91222C3671910078DFD3 /* CustomNavigationBar.swift */; }; - 1DDE91252C3671B20078DFD3 /* RecipeListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91242C3671B20078DFD3 /* RecipeListMapper.swift */; }; - 1DDE91282C3671DB0078DFD3 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91272C3671DB0078DFD3 /* DateFormatter+Extensions.swift */; }; - 1DDE912B2C3671EC0078DFD3 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91292C3671EC0078DFD3 /* User.swift */; }; - 1DDE912C2C3671EC0078DFD3 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE912A2C3671EC0078DFD3 /* Comment.swift */; }; - 1DDE912E2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE912D2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift */; }; - 1DDE91302C36720A0078DFD3 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE912F2C36720A0078DFD3 /* RecipeDetailInteractor.swift */; }; - 1DDE91332C3672170078DFD3 /* RecipeDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91322C3672170078DFD3 /* RecipeDetailCoordinator.swift */; }; - 1DDE91352C3672230078DFD3 /* RecipeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91342C3672230078DFD3 /* RecipeDetailViewModel.swift */; }; - 1DDE91382C36722A0078DFD3 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91362C36722A0078DFD3 /* RecipeDetailViewController.swift */; }; - 1DDE91392C36722A0078DFD3 /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91372C36722A0078DFD3 /* RecipeDetailView.swift */; }; - 1DDE913B2C3672410078DFD3 /* UserDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE913A2C3672410078DFD3 /* UserDTO.swift */; }; - 1DDE913D2C3672490078DFD3 /* RecipeDetailFetchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE913C2C3672490078DFD3 /* RecipeDetailFetchService.swift */; }; - 1DDE913F2C3672720078DFD3 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE913E2C3672720078DFD3 /* RecipeDetailRepository.swift */; }; - 1DDE91412C3672850078DFD3 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE91402C3672850078DFD3 /* RecipeDetailDTO.swift */; }; - - 1D60CC452C3F932D00D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */; }; - 1D60CC462C3F932D00D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */; }; - 1D7368B72C3442C8000EF904 /* String+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368B52C3442C8000EF904 /* String+Validation.swift */; }; - 1D7368B82C3442C8000EF904 /* UIImageViewImageLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368B62C3442C8000EF904 /* UIImageViewImageLoading.swift */; }; - 1D7368BA2C3442DE000EF904 /* RecipeListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368B92C3442DE000EF904 /* RecipeListMapper.swift */; }; - 1D7368C72C344378000EF904 /* UserDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368C62C344378000EF904 /* UserDTO.swift */; }; - 1D7368CA2C3443A1000EF904 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368C82C3443A1000EF904 /* Comment.swift */; }; - 1D7368CB2C3443A1000EF904 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368C92C3443A1000EF904 /* User.swift */; }; - 1D7368CE2C344403000EF904 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368CD2C344403000EF904 /* DateFormatter+Extensions.swift */; }; - 1D7368D22C34FADD000EF904 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D12C34FADD000EF904 /* FetchRecipeDetailUseCase.swift */; }; - 1D7368D42C34FAE8000EF904 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D32C34FAE8000EF904 /* RecipeDetailInteractor.swift */; }; - 1D7368D82C34FB07000EF904 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D72C34FB07000EF904 /* RecipeDetailDTO.swift */; }; - 1D7368DA2C34FB14000EF904 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368D92C34FB14000EF904 /* RecipeDetailRepository.swift */; }; - 1D7368DC2C34FB32000EF904 /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368DB2C34FB32000EF904 /* CustomNavigationBar.swift */; }; - 1D7368E22C34FB38000EF904 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368DF2C34FB38000EF904 /* RecipeDetailViewController.swift */; }; - 1D7368E32C34FB38000EF904 /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E02C34FB38000EF904 /* RecipeDetailView.swift */; }; - 1D7368E42C34FB38000EF904 /* RecipeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E12C34FB38000EF904 /* RecipeDetailViewModel.swift */; }; - 1D7368E72C34FB66000EF904 /* RecipeDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E62C34FB66000EF904 /* RecipeDetailCoordinator.swift */; }; - 1D7368EA2C34FBF7000EF904 /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7368E92C34FBF7000EF904 /* MainTabBarController.swift */; }; - 1D95A0A42C37B0E200F09077 /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A32C37B0E200F09077 /* Fonts.swift */; }; - 1D95A0A82C37C7D400F09077 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A72C37C7D400F09077 /* RecipeDetailError.swift */; }; - + 1D4741D72C1B4FF4009381CE /* RecipeListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */; }; + 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */; }; + 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */; }; + 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */; }; + 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */; }; + 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */; }; + 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283A12C15E94300C5A870 /* Recipe.swift */; }; + 1D6958DC2C3D5E20008604B3 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */; }; + 1D6958DE2C3D5E2C008604B3 /* RecipeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283A32C15EA8100C5A870 /* RecipeType.swift */; }; + 1D6958DF2C3D5E35008604B3 /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB02C1B42200031804A /* NetworkService.swift */; }; + 1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */; }; + 1D6958E12C3D5E44008604B3 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */; }; + 1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */; }; + 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */; }; + 1D73686E2C305757000EF904 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */; }; + 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */; }; + 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */; }; + 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */; }; 1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */; }; 1DE19EA72C1B420A0031804A /* FeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */; }; 1DE19EA82C1B420A0031804A /* SearchFeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */; }; 1DE19EB12C1B42200031804A /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB02C1B42200031804A /* NetworkService.swift */; }; - 1DE19EC22C1B422F0031804A /* RecipeListItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBA2C1B422F0031804A /* RecipeListItemViewModel.swift */; }; + 1DE19EBF2C1B422F0031804A /* RecipeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB42C1B422F0031804A /* RecipeDetailViewModel.swift */; }; + 1DE19EC02C1B422F0031804A /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB62C1B422F0031804A /* RecipeDetailView.swift */; }; 1DE19EC32C1B422F0031804A /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBB2C1B422F0031804A /* SearchBar.swift */; }; 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBC2C1B422F0031804A /* RecipeListViewController.swift */; }; 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBD2C1B422F0031804A /* RecipeListView.swift */; }; 1DE19EC62C1B422F0031804A /* RecipeListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBE2C1B422F0031804A /* RecipeListCell.swift */; }; 1DE19EC82C1B4C2D0031804A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 1DE19EC72C1B4C2D0031804A /* Kingfisher */; }; - 1DF829B12C299F1F00C337FC /* RecipeListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B02C299F1F00C337FC /* RecipeListInteractor.swift */; }; + 1DF829B42C2A7A7D00C337FC /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B32C2A7A7D00C337FC /* Fonts.swift */; }; + 1DF829B72C2A7CDC00C337FC /* UIImageViewImageLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B62C2A7CDC00C337FC /* UIImageViewImageLoading.swift */; }; + 1DF829B92C2A818D00C337FC /* String+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B82C2A818D00C337FC /* String+Validation.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -114,61 +108,45 @@ 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 = ""; }; + 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; + 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; + 1D39724F2C44167A00495014 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; + 1D3972502C44167A00495014 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; + 1D3972512C44167A00495014 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; + 1D3972562C44168E00495014 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; + 1D3972582C4416A300495014 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + 1D3972592C4416A300495014 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; + 1D39725D2C4416CE00495014 /* RecipeListMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListMapper.swift; sourceTree = ""; }; + 1D3972612C4416E400495014 /* UIView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; + 1D3972632C4416F400495014 /* UserDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDTO.swift; sourceTree = ""; }; + 1D3972652C44171100495014 /* RecipeListItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListItemViewModel.swift; sourceTree = ""; }; + 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCase.swift; sourceTree = ""; }; + 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailRepository.swift; sourceTree = ""; }; + 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailInteractor.swift; sourceTree = ""; }; 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeImageDTO.swift; sourceTree = ""; }; 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDTO.swift; sourceTree = ""; }; 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipePageDTO.swift; sourceTree = ""; }; 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkResponseDTO.swift; sourceTree = ""; }; - - 1DDE911B2C36717B0078DFD3 /* String+Validation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Validation.swift"; sourceTree = ""; }; - 1DDE911C2C36717B0078DFD3 /* UIImageViewImageLoading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageViewImageLoading.swift; sourceTree = ""; }; - 1DDE91202C3671840078DFD3 /* Fonts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; - 1DDE91222C3671910078DFD3 /* CustomNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; - 1DDE91242C3671B20078DFD3 /* RecipeListMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListMapper.swift; sourceTree = ""; }; - 1DDE91272C3671DB0078DFD3 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; - 1DDE91292C3671EC0078DFD3 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; - 1DDE912A2C3671EC0078DFD3 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; - 1DDE912D2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCase.swift; sourceTree = ""; }; - 1DDE912F2C36720A0078DFD3 /* RecipeDetailInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailInteractor.swift; sourceTree = ""; }; - 1DDE91322C3672170078DFD3 /* RecipeDetailCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailCoordinator.swift; sourceTree = ""; }; - 1DDE91342C3672230078DFD3 /* RecipeDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewModel.swift; sourceTree = ""; }; - 1DDE91362C36722A0078DFD3 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; - 1DDE91372C36722A0078DFD3 /* RecipeDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailView.swift; sourceTree = ""; }; - 1DDE913A2C3672410078DFD3 /* UserDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDTO.swift; sourceTree = ""; }; - 1DDE913C2C3672490078DFD3 /* RecipeDetailFetchService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailFetchService.swift; sourceTree = ""; }; - 1DDE913E2C3672720078DFD3 /* RecipeDetailRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailRepository.swift; sourceTree = ""; }; - 1DDE91402C3672850078DFD3 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; - - 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIConfig.swift; sourceTree = ""; }; - 1D7368B52C3442C8000EF904 /* String+Validation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Validation.swift"; sourceTree = ""; }; - 1D7368B62C3442C8000EF904 /* UIImageViewImageLoading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageViewImageLoading.swift; sourceTree = ""; }; - 1D7368B92C3442DE000EF904 /* RecipeListMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListMapper.swift; sourceTree = ""; }; - 1D7368C62C344378000EF904 /* UserDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDTO.swift; sourceTree = ""; }; - 1D7368C82C3443A1000EF904 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; - 1D7368C92C3443A1000EF904 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; - 1D7368CD2C344403000EF904 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; - 1D7368D12C34FADD000EF904 /* FetchRecipeDetailUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCase.swift; sourceTree = ""; }; - 1D7368D32C34FAE8000EF904 /* RecipeDetailInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailInteractor.swift; sourceTree = ""; }; - 1D7368D72C34FB07000EF904 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; - 1D7368D92C34FB14000EF904 /* RecipeDetailRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailRepository.swift; sourceTree = ""; }; - 1D7368DB2C34FB32000EF904 /* CustomNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; - 1D7368DF2C34FB38000EF904 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; - 1D7368E02C34FB38000EF904 /* RecipeDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailView.swift; sourceTree = ""; }; - 1D7368E12C34FB38000EF904 /* RecipeDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewModel.swift; sourceTree = ""; }; - 1D7368E62C34FB66000EF904 /* RecipeDetailCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailCoordinator.swift; sourceTree = ""; }; - 1D7368E92C34FBF7000EF904 /* MainTabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; - 1D95A0A32C37B0E200F09077 /* Fonts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; - 1D95A0A72C37C7D400F09077 /* RecipeDetailError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailError.swift; sourceTree = ""; }; - + 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListInteractor.swift; sourceTree = ""; }; + 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIConfig.swift; sourceTree = ""; }; + 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDeatilInteractorTests.swift; sourceTree = ""; }; + 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; + 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailError.swift; sourceTree = ""; }; + 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRecipeTests.swift; sourceTree = ""; }; + 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedListRepository.swift; sourceTree = ""; }; 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchFeedListRepository.swift; sourceTree = ""; }; 1DE19EB02C1B42200031804A /* NetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; - 1DE19EBA2C1B422F0031804A /* RecipeListItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListItemViewModel.swift; sourceTree = ""; }; + 1DE19EB42C1B422F0031804A /* RecipeDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewModel.swift; sourceTree = ""; }; + 1DE19EB62C1B422F0031804A /* RecipeDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDetailView.swift; sourceTree = ""; }; 1DE19EBB2C1B422F0031804A /* SearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = ""; }; 1DE19EBC2C1B422F0031804A /* RecipeListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListViewController.swift; sourceTree = ""; }; 1DE19EBD2C1B422F0031804A /* RecipeListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListView.swift; sourceTree = ""; }; 1DE19EBE2C1B422F0031804A /* RecipeListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListCell.swift; sourceTree = ""; }; - 1DF829B02C299F1F00C337FC /* RecipeListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListInteractor.swift; sourceTree = ""; }; + 1DF829B32C2A7A7D00C337FC /* Fonts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; + 1DF829B62C2A7CDC00C337FC /* UIImageViewImageLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageViewImageLoading.swift; sourceTree = ""; }; + 1DF829B82C2A818D00C337FC /* String+Validation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Validation.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -204,14 +182,11 @@ 1D12839F2C15E7A700C5A870 /* Entities */ = { isa = PBXGroup; children = ( - - 1DDE912A2C3671EC0078DFD3 /* Comment.swift */, - 1DDE91292C3671EC0078DFD3 /* User.swift */, - 1D95A0A72C37C7D400F09077 /* RecipeDetailError.swift */, 1D1283A12C15E94300C5A870 /* Recipe.swift */, - 1D7368C82C3443A1000EF904 /* Comment.swift */, - 1D7368C92C3443A1000EF904 /* User.swift */, + 1D3972592C4416A300495014 /* Comment.swift */, + 1D3972582C4416A300495014 /* User.swift */, 1D1283A32C15EA8100C5A870 /* RecipeType.swift */, + 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */, ); path = Entities; sourceTree = ""; @@ -220,9 +195,8 @@ isa = PBXGroup; children = ( 1D1283A92C15EBCF00C5A870 /* SearchFeedUseCase.swift */, - 1DDE912D2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift */, - 1D7368D12C34FADD000EF904 /* FetchRecipeDetailUseCase.swift */, 1D1283AB2C15EBE600C5A870 /* FetchFeedListUseCase.swift */, + 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */, ); path = UseCases; sourceTree = ""; @@ -248,9 +222,8 @@ children = ( 1D4741CB2C1B4F8D009381CE /* DTO */, 1D1283C92C16D9C600C5A870 /* RecipeFetchService.swift */, - 1DDE913C2C3672490078DFD3 /* RecipeDetailFetchService.swift */, 1DE19EB02C1B42200031804A /* NetworkService.swift */, - 1D60CC442C3F932D00D08FA3 /* APIConfig.swift */, + 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */, ); path = Network; sourceTree = ""; @@ -280,15 +253,10 @@ 1D2C16E42BE532B700C04508 /* HomeCafeRecipes */ = { isa = PBXGroup; children = ( - 1DDE91312C3672170078DFD3 /* Coordinators */, - 1DDE91262C3671DB0078DFD3 /* Utilities */, - 1DDE911F2C3671840078DFD3 /* Resources */, - 1DDE911A2C36717B0078DFD3 /* Extensions */, - - 1D95A0A22C37B0E200F09077 /* Resources */, - 1D7368E52C34FB66000EF904 /* Coordinators */, - 1D7368CC2C344403000EF904 /* Utilities */, - 1D7368B42C3442C8000EF904 /* Extensions */, + 1D3972552C44168E00495014 /* Utilities */, + 1D39724E2C44167A00495014 /* Router */, + 1DF829B52C2A7C8600C337FC /* Extensions */, + 1DF829B22C2A7A0B00C337FC /* Resources */, 1DE19EB22C1B422F0031804A /* Presentation */, 1D1283AD2C16974B00C5A870 /* Data */, 1D740B402C15E6680001B704 /* Domain */, @@ -306,6 +274,8 @@ isa = PBXGroup; children = ( 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */, + 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */, + 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */, ); path = HomeCafeRecipesTests; sourceTree = ""; @@ -319,147 +289,79 @@ path = HomeCafeRecipesUITests; sourceTree = ""; }; - 1D4741CB2C1B4F8D009381CE /* DTO */ = { + 1D2C6F612C2446AF004BB54E /* Tabbar */ = { isa = PBXGroup; children = ( - 1D7368C62C344378000EF904 /* UserDTO.swift */, - 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */, - 1DDE91402C3672850078DFD3 /* RecipeDetailDTO.swift */, - 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */, - 1DDE913A2C3672410078DFD3 /* UserDTO.swift */, - 1D7368D72C34FB07000EF904 /* RecipeDetailDTO.swift */, - 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */, - 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */, + 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */, ); - path = DTO; + path = Tabbar; sourceTree = ""; }; - 1D7368B42C3442C8000EF904 /* Extensions */ = { + 1D39724E2C44167A00495014 /* Router */ = { isa = PBXGroup; children = ( - 1D7368B52C3442C8000EF904 /* String+Validation.swift */, - 1D7368B62C3442C8000EF904 /* UIImageViewImageLoading.swift */, + 1D39724F2C44167A00495014 /* AddRecipeRouter.swift */, + 1D3972502C44167A00495014 /* RecipeListRouter.swift */, + 1D3972512C44167A00495014 /* Router.swift */, ); - path = Extensions; + path = Router; sourceTree = ""; }; - 1D7368CC2C344403000EF904 /* Utilities */ = { + 1D3972552C44168E00495014 /* Utilities */ = { isa = PBXGroup; children = ( - 1D7368CD2C344403000EF904 /* DateFormatter+Extensions.swift */, + 1D3972562C44168E00495014 /* DateFormatter+Extensions.swift */, ); path = Utilities; sourceTree = ""; }; - 1D7368DD2C34FB38000EF904 /* Feed */ = { - isa = PBXGroup; - children = ( - 1D7368DE2C34FB38000EF904 /* View */, - 1D7368E12C34FB38000EF904 /* RecipeDetailViewModel.swift */, - ); - path = Feed; - sourceTree = ""; - }; - 1D7368DE2C34FB38000EF904 /* View */ = { - isa = PBXGroup; - children = ( - 1D7368DF2C34FB38000EF904 /* RecipeDetailViewController.swift */, - 1D7368E02C34FB38000EF904 /* RecipeDetailView.swift */, - ); - path = View; - sourceTree = ""; - }; - 1D7368E52C34FB66000EF904 /* Coordinators */ = { + 1D39725C2C4416CE00495014 /* Mapper */ = { isa = PBXGroup; children = ( - 1D7368E62C34FB66000EF904 /* RecipeDetailCoordinator.swift */, + 1D39725D2C4416CE00495014 /* RecipeListMapper.swift */, ); - path = Coordinators; + name = Mapper; + path = ../../../../../HomeCafeRecipesLocal/HomeCafeRecipes/HomeCafeRecipes/Presentation/Mapper; sourceTree = ""; }; - 1D7368E82C34FBF7000EF904 /* Tabbar */ = { + 1D4741CB2C1B4F8D009381CE /* DTO */ = { isa = PBXGroup; children = ( - 1D7368E92C34FBF7000EF904 /* MainTabBarController.swift */, + 1D4741CC2C1B4F8D009381CE /* RecipeImageDTO.swift */, + 1D3972632C4416F400495014 /* UserDTO.swift */, + 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */, + 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */, + 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */, + 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */, ); - path = Tabbar; + path = DTO; sourceTree = ""; }; 1D740B402C15E6680001B704 /* Domain */ = { isa = PBXGroup; children = ( - 1DF829AF2C299F1F00C337FC /* Interactor */, + 1DE19EA12C1B41FE0031804A /* Interactor */, 1D1283A02C15E92C00C5A870 /* UseCases */, 1D12839F2C15E7A700C5A870 /* Entities */, ); path = Domain; sourceTree = ""; }; - - 1DDE911A2C36717B0078DFD3 /* Extensions */ = { - isa = PBXGroup; - children = ( - 1DDE911B2C36717B0078DFD3 /* String+Validation.swift */, - 1DDE911C2C36717B0078DFD3 /* UIImageViewImageLoading.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 1DDE911F2C3671840078DFD3 /* Resources */ = { + 1DE19EA12C1B41FE0031804A /* Interactor */ = { isa = PBXGroup; children = ( - 1DDE91202C3671840078DFD3 /* Fonts.swift */, - - 1D95A0A22C37B0E200F09077 /* Resources */ = { - isa = PBXGroup; - children = ( - 1D95A0A32C37B0E200F09077 /* Fonts.swift */, - + 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */, + 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */, ); - path = Resources; - sourceTree = ""; - }; - - 1DDE91262C3671DB0078DFD3 /* Utilities */ = { - isa = PBXGroup; - children = ( - 1DDE91272C3671DB0078DFD3 /* DateFormatter+Extensions.swift */, - ); - path = Utilities; - sourceTree = ""; - }; - 1DDE91312C3672170078DFD3 /* Coordinators */ = { - isa = PBXGroup; - children = ( - 1DDE91322C3672170078DFD3 /* RecipeDetailCoordinator.swift */, - ); - path = Coordinators; - sourceTree = ""; - }; - 1DDFFD822C1C09AB0083B077 /* Mapper */ = { - isa = PBXGroup; - children = ( - 1DDE91242C3671B20078DFD3 /* RecipeListMapper.swift */, - - 1DDFFD822C1C09AB0083B077 /* Mapper */ = { - isa = PBXGroup; - children = ( - 1D7368B92C3442DE000EF904 /* RecipeListMapper.swift */, - - ); - path = Mapper; + path = Interactor; sourceTree = ""; }; 1DE19EA42C1B420A0031804A /* Repositories */ = { isa = PBXGroup; children = ( 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */, - - 1DDE913E2C3672720078DFD3 /* RecipeDetailRepository.swift */, - - 1D7368D92C34FB14000EF904 /* RecipeDetailRepository.swift */, - 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */, + 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */, ); path = Repositories; sourceTree = ""; @@ -467,22 +369,19 @@ 1DE19EB22C1B422F0031804A /* Presentation */ = { isa = PBXGroup; children = ( - 1DDE91222C3671910078DFD3 /* CustomNavigationBar.swift */, - 1D7368E82C34FBF7000EF904 /* Tabbar */, - 1D7368DD2C34FB38000EF904 /* Feed */, - 1D7368DB2C34FB32000EF904 /* CustomNavigationBar.swift */, - - 1DDFFD822C1C09AB0083B077 /* Mapper */, + 1D39725C2C4416CE00495014 /* Mapper */, + 1D2C6F612C2446AF004BB54E /* Tabbar */, + 1DE19EB32C1B422F0031804A /* Feed */, 1DE19EB72C1B422F0031804A /* FeedList */, + 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */, ); path = Presentation; sourceTree = ""; }; - 1DE19EB32C1B422F0031804A /* Feed */ = { isa = PBXGroup; children = ( - 1DDE91342C3672230078DFD3 /* RecipeDetailViewModel.swift */, + 1DE19EB42C1B422F0031804A /* RecipeDetailViewModel.swift */, 1DE19EB52C1B422F0031804A /* View */, ); path = Feed; @@ -491,16 +390,16 @@ 1DE19EB52C1B422F0031804A /* View */ = { isa = PBXGroup; children = ( - 1DDE91372C36722A0078DFD3 /* RecipeDetailView.swift */, - 1DDE91362C36722A0078DFD3 /* RecipeDetailViewController.swift */, + 1DE19EB62C1B422F0031804A /* RecipeDetailView.swift */, + 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */, ); path = View; sourceTree = ""; }; - 1DE19EB72C1B422F0031804A /* FeedList */ = { isa = PBXGroup; children = ( + 1D3972652C44171100495014 /* RecipeListItemViewModel.swift */, 1DE19EB92C1B422F0031804A /* View */, ); path = FeedList; @@ -509,7 +408,6 @@ 1DE19EB92C1B422F0031804A /* View */ = { isa = PBXGroup; children = ( - 1DE19EBA2C1B422F0031804A /* RecipeListItemViewModel.swift */, 1DE19EBB2C1B422F0031804A /* SearchBar.swift */, 1DE19EBC2C1B422F0031804A /* RecipeListViewController.swift */, 1DE19EBD2C1B422F0031804A /* RecipeListView.swift */, @@ -518,14 +416,22 @@ path = View; sourceTree = ""; }; - 1DF829AF2C299F1F00C337FC /* Interactor */ = { + 1DF829B22C2A7A0B00C337FC /* Resources */ = { isa = PBXGroup; children = ( - 1DDE912F2C36720A0078DFD3 /* RecipeDetailInteractor.swift */, - 1D7368D32C34FAE8000EF904 /* RecipeDetailInteractor.swift */, - 1DF829B02C299F1F00C337FC /* RecipeListInteractor.swift */, + 1DF829B32C2A7A7D00C337FC /* Fonts.swift */, ); - path = Interactor; + path = Resources; + sourceTree = ""; + }; + 1DF829B52C2A7C8600C337FC /* Extensions */ = { + isa = PBXGroup; + children = ( + 1DF829B62C2A7CDC00C337FC /* UIImageViewImageLoading.swift */, + 1DF829B82C2A818D00C337FC /* String+Validation.swift */, + 1D3972612C4416E400495014 /* UIView+Extensions.swift */, + ); + path = Extensions; sourceTree = ""; }; /* End PBXGroup section */ @@ -669,77 +575,50 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1DF829B12C299F1F00C337FC /* RecipeListInteractor.swift in Sources */, + 1D3972532C44167A00495014 /* RecipeListRouter.swift in Sources */, + 1D39725B2C4416A300495014 /* Comment.swift in Sources */, + 1D439E9E2C2C598A008530A5 /* RecipeDetailRepository.swift in Sources */, + 1D2C6F6C2C27051D004BB54E /* CustomNavigationBar.swift in Sources */, + 1D3972522C44167A00495014 /* AddRecipeRouter.swift in Sources */, 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */, - 1D7368EA2C34FBF7000EF904 /* MainTabBarController.swift in Sources */, - 1D60CC452C3F932D00D08FA3 /* APIConfig.swift in Sources */, - 1D7368D42C34FAE8000EF904 /* RecipeDetailInteractor.swift in Sources */, 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */, - - 1DDE911E2C36717B0078DFD3 /* UIImageViewImageLoading.swift in Sources */, - 1DDE912B2C3671EC0078DFD3 /* User.swift in Sources */, - 1DDE91352C3672230078DFD3 /* RecipeDetailViewModel.swift in Sources */, - 1DDE913B2C3672410078DFD3 /* UserDTO.swift in Sources */, 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, - 1DDE91392C36722A0078DFD3 /* RecipeDetailView.swift in Sources */, - - 1D7368CB2C3443A1000EF904 /* User.swift in Sources */, - 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, - 1D7368CE2C344403000EF904 /* DateFormatter+Extensions.swift in Sources */, - 1D7368E32C34FB38000EF904 /* RecipeDetailView.swift in Sources */, - + 1D2C6F652C2446D8004BB54E /* MainTabBarController.swift in Sources */, + 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */, + 1D3972622C4416E400495014 /* UIView+Extensions.swift in Sources */, 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */, - 1DDE91282C3671DB0078DFD3 /* DateFormatter+Extensions.swift in Sources */, - 1DDE91332C3672170078DFD3 /* RecipeDetailCoordinator.swift in Sources */, - 1DDE91382C36722A0078DFD3 /* RecipeDetailViewController.swift in Sources */, + 1D3972662C44171100495014 /* RecipeListItemViewModel.swift in Sources */, 1DE19EB12C1B42200031804A /* NetworkService.swift in Sources */, - - 1DDE913F2C3672720078DFD3 /* RecipeDetailRepository.swift in Sources */, - 1D1283AC2C15EBE600C5A870 /* FetchFeedListUseCase.swift in Sources */, - 1DDE91252C3671B20078DFD3 /* RecipeListMapper.swift in Sources */, - + 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */, 1D1283AC2C15EBE600C5A870 /* FetchFeedListUseCase.swift in Sources */, - 1D7368E22C34FB38000EF904 /* RecipeDetailViewController.swift in Sources */, - + 1D3972542C44167A00495014 /* Router.swift in Sources */, + 1DF829B72C2A7CDC00C337FC /* UIImageViewImageLoading.swift in Sources */, + 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */, 1D1283A42C15EA8100C5A870 /* RecipeType.swift in Sources */, - 1D7368D82C34FB07000EF904 /* RecipeDetailDTO.swift in Sources */, - 1D7368DA2C34FB14000EF904 /* RecipeDetailRepository.swift in Sources */, + 1DF829B42C2A7A7D00C337FC /* Fonts.swift in Sources */, + 1D39725A2C4416A300495014 /* User.swift in Sources */, 1D4741D22C1B4F8D009381CE /* RecipeDTO.swift in Sources */, + 1DE19EC02C1B422F0031804A /* RecipeDetailView.swift in Sources */, 1D1283AA2C15EBCF00C5A870 /* SearchFeedUseCase.swift in Sources */, 1DE19EA82C1B420A0031804A /* SearchFeedListRepository.swift in Sources */, - - 1D95A0A42C37B0E200F09077 /* Fonts.swift in Sources */, - - 1DE19EC22C1B422F0031804A /* RecipeListItemViewModel.swift in Sources */, - 1D7368C72C344378000EF904 /* UserDTO.swift in Sources */, 1DE19EC32C1B422F0031804A /* SearchBar.swift in Sources */, + 1D439EA22C2C6997008530A5 /* RecipeDetailInteractor.swift in Sources */, + 1D73686E2C305757000EF904 /* RecipeDetailDTO.swift in Sources */, + 1D39725F2C4416CE00495014 /* RecipeListMapper.swift in Sources */, + 1D4741D72C1B4FF4009381CE /* RecipeListInteractor.swift in Sources */, 1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */, - 1DDE91232C3671920078DFD3 /* CustomNavigationBar.swift in Sources */, + 1D3972642C4416F500495014 /* UserDTO.swift in Sources */, 1D4741D12C1B4F8D009381CE /* RecipeImageDTO.swift in Sources */, - 1DDE91412C3672850078DFD3 /* RecipeDetailDTO.swift in Sources */, 1DE19EA72C1B420A0031804A /* FeedListRepository.swift in Sources */, 1DE19EC62C1B422F0031804A /* RecipeListCell.swift in Sources */, - - 1DDE91212C3671840078DFD3 /* Fonts.swift in Sources */, - 1DDE913D2C3672490078DFD3 /* RecipeDetailFetchService.swift in Sources */, - 1DDE91302C36720A0078DFD3 /* RecipeDetailInteractor.swift in Sources */, - 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */, - 1DDE912C2C3671EC0078DFD3 /* Comment.swift in Sources */, - 1DDE911D2C36717B0078DFD3 /* String+Validation.swift in Sources */, - 1D7368E72C34FB66000EF904 /* RecipeDetailCoordinator.swift in Sources */, - 1D7368D22C34FADD000EF904 /* FetchRecipeDetailUseCase.swift in Sources */, + 1DF829B92C2A818D00C337FC /* String+Validation.swift in Sources */, 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */, - 1D95A0A82C37C7D400F09077 /* RecipeDetailError.swift in Sources */, + 1DE19EBF2C1B422F0031804A /* RecipeDetailViewModel.swift in Sources */, 1D1283A22C15E94300C5A870 /* Recipe.swift in Sources */, - 1D7368BA2C3442DE000EF904 /* RecipeListMapper.swift in Sources */, - 1D7368CA2C3443A1000EF904 /* Comment.swift in Sources */, 1D1283CA2C16D9C600C5A870 /* RecipeFetchService.swift in Sources */, - 1DDE912E2C3671FD0078DFD3 /* FetchRecipeDetailUseCase.swift in Sources */, - 1D7368E42C34FB38000EF904 /* RecipeDetailViewModel.swift in Sources */, - 1D7368B82C3442C8000EF904 /* UIImageViewImageLoading.swift in Sources */, 1D4741D42C1B4F8D009381CE /* NetworkResponseDTO.swift in Sources */, - 1D7368B72C3442C8000EF904 /* String+Validation.swift in Sources */, - 1D7368DC2C34FB32000EF904 /* CustomNavigationBar.swift in Sources */, + 1D439E9C2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift in Sources */, + 1D3972572C44168E00495014 /* DateFormatter+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -747,8 +626,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1D60CC462C3F932D00D08FA3 /* APIConfig.swift in Sources */, + 1D6958DF2C3D5E35008604B3 /* NetworkService.swift in Sources */, + 1D6958DC2C3D5E20008604B3 /* RecipeDetailRepository.swift in Sources */, + 1D6958E12C3D5E44008604B3 /* RecipeDetailDTO.swift in Sources */, + 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */, + 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */, + 1D6958DE2C3D5E2C008604B3 /* RecipeType.swift in Sources */, + 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */, 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */, + 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */, + 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */, + 1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */, + 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */, + 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */, + 1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift index b02de71..65ced8d 100755 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift @@ -6,6 +6,7 @@ // import Foundation + import RxSwift protocol RecipeListInteractorDelegate: AnyObject { @@ -13,7 +14,7 @@ protocol RecipeListInteractorDelegate: AnyObject { func showRecipeDetail(ID: Int) } -protocol InputRecipeListInteractor { +protocol RecipeListInteractor { func viewDidLoad() func fetchNextPage() func didSelectItem(ID: Int) @@ -21,11 +22,7 @@ protocol InputRecipeListInteractor { func resetSearch() } -protocol OutputRecipeListInteractor { - var recipes: Observable> { get } -} - -class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteractor { +class RecipeListInteractorImpl: RecipeListInteractor { private let disposeBag = DisposeBag() private let fetchFeedListUseCase: FetchFeedListUseCase @@ -40,10 +37,6 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto private let recipesSubject = BehaviorSubject>(value: .success([])) - var recipes: Observable> { - return recipesSubject.asObservable() - } - init(fetchFeedListUseCase: FetchFeedListUseCase, searchFeedListUseCase: SearchFeedListUseCase) { self.fetchFeedListUseCase = fetchFeedListUseCase self.searchFeedListUseCase = searchFeedListUseCase @@ -51,15 +44,6 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto func setDelegate(_ delegate: RecipeListInteractorDelegate) { self.delegate = delegate - bindOutputs() - } - - private func bindOutputs() { - recipes - .subscribe(onNext: { [weak self] result in - self?.delegate?.fetchedRecipes(result: result) - }) - .disposed(by: disposeBag) } func viewDidLoad() { @@ -67,7 +51,8 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto } func fetchNextPage() { - fetchNextRecipes(nextPage: currentPage) + guard !isFetching else { return } + fetchNextRecipes() } func didSelectItem(ID: Int) { @@ -78,6 +63,7 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto isSearching = false currentSearchQuery = nil currentPage = 1 + allRecipes.removeAll() recipesSubject.onNext(.success([])) fetchRecipes() } @@ -89,9 +75,11 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto isSearching = true currentPage = 1 searchFeedListUseCase.execute(title: title, pageNumber: currentPage) - .subscribe { [weak self] result in + .subscribe(onSuccess: { [weak self] result in self?.handleResult(result) - } + }, onFailure: { [weak self] error in + self?.handleResult(.failure(error)) + }) .disposed(by: disposeBag) } @@ -99,19 +87,23 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto guard !isFetching else { return } isFetching = true fetchFeedListUseCase.execute(pageNumber: currentPage) - .subscribe { [weak self] result in + .subscribe(onSuccess: { [weak self] result in self?.handleResult(result) - } + }, onFailure: { [weak self] error in + self?.handleResult(.failure(error)) + }) .disposed(by: disposeBag) } - private func fetchNextRecipes(nextPage: Int) { + private func fetchNextRecipes() { guard !isFetching else { return } isFetching = true - fetchFeedListUseCase.execute(pageNumber: nextPage) - .subscribe { [weak self] result in + fetchFeedListUseCase.execute(pageNumber: currentPage) + .subscribe(onSuccess: { [weak self] result in self?.handleResult(result) - } + }, onFailure: { [weak self] error in + self?.handleResult(.failure(error)) + }) .disposed(by: disposeBag) } @@ -127,11 +119,10 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto } else { allRecipes.append(contentsOf: recipes) } - self.recipesSubject.onNext(.success(allRecipes)) - self.currentPage += 1 + delegate?.fetchedRecipes(result: .success(allRecipes)) + currentPage += 1 case .failure(let error): - recipesSubject.onNext(.failure(error)) + delegate?.fetchedRecipes(result: .failure(error)) } } - } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift index 710f217..0b7d44b 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift @@ -9,16 +9,18 @@ import UIKit final class RecipeListViewController: UIViewController { - private var interactor: RecipeListInteractor - private var recipes: [RecipeListItemViewModel] = [] + private var interactor: RecipeListInteractorImpl private let searchBar = SearchBar() private let recipeListView = RecipeListView() - - init(interactor: RecipeListInteractor) { + private let recipeListMapper = RecipeListMapper() + private let router: RecipeListRouterProtocol + + init(interactor: RecipeListInteractorImpl, router: RecipeListRouterProtocol) { self.interactor = interactor + self.router = router super.init(nibName: nil, bundle: nil) self.interactor.setDelegate(self) - + recipeListView.delegate = self } required init?(coder: NSCoder) { @@ -27,7 +29,6 @@ final class RecipeListViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - recipeListView.delegate = self setupUI() interactor.viewDidLoad() } @@ -36,16 +37,16 @@ final class RecipeListViewController: UIViewController { view.backgroundColor = .white view.addSubview(searchBar) view.addSubview(recipeListView) - + searchBar.translatesAutoresizingMaskIntoConstraints = false recipeListView.translatesAutoresizingMaskIntoConstraints = false - + NSLayoutConstraint.activate([ searchBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10), searchBar.heightAnchor.constraint(equalToConstant: 50), - + recipeListView.topAnchor.constraint(equalTo: searchBar.bottomAnchor), recipeListView.leadingAnchor.constraint(equalTo: view.leadingAnchor), recipeListView.trailingAnchor.constraint(equalTo: view.trailingAnchor), @@ -54,10 +55,10 @@ final class RecipeListViewController: UIViewController { searchBar.setDelegate(self) } - } // MARK: - UISearchBarDelegate + extension RecipeListViewController: UISearchBarDelegate { func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { if searchText.isBlank { @@ -75,6 +76,7 @@ extension RecipeListViewController: UISearchBarDelegate { } // MARK: - RecipeListInteractorDelegate + extension RecipeListViewController: RecipeListInteractorDelegate { func fetchedRecipes(result: Result<[Recipe], Error>) { switch result { @@ -90,7 +92,7 @@ extension RecipeListViewController: RecipeListInteractorDelegate { } func showRecipeDetail(ID: Int) { - coordinator.showRecipeDetail(from: self, recipeID: ID) + router.navigateToRecipeDetail(from: self, recipeID: ID) } } @@ -100,7 +102,7 @@ extension RecipeListViewController: RecipeListViewDelegate { interactor.didSelectItem(ID: ID) } - func ScrollToBottom() { + func scrollToBottom() { interactor.fetchNextPage() } } From 06a6f896495eae6c7e50707cafc4df7e26e975d8 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 15 Jul 2024 00:56:58 +0900 Subject: [PATCH 06/51] =?UTF-8?q?Fix:=20RecipeDetailInteractor=EC=9D=98=20?= =?UTF-8?q?Ouput=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Interactor/RecipeDetailInteractor.swift | 51 ++++--------------- .../View/RecipeDetailViewController.swift | 16 ++++-- 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift index 187863f..ef9c80c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift @@ -6,71 +6,42 @@ // import Foundation + import RxSwift protocol RecipeDetailInteractorDelegate: AnyObject { func fetchedRecipe(result: Result) } -protocol InputRecipeDetailInteractor { +protocol RecipeDetailInteractor { func viewDidLoad() } -protocol OutputRecipeDetailInteractor { - var recipe: Observable> { get } -} - -class RecipeDetailInteractor: InputRecipeDetailInteractor, OutputRecipeDetailInteractor { - +class RecipeDetailInteractorImpl: RecipeDetailInteractor { + private let fetchRecipeDetailUseCase: FetchRecipeDetailUseCase private let recipeID: Int private let disposeBag = DisposeBag() - private let recipeDetailSubject = PublishSubject>() weak var delegate: RecipeDetailInteractorDelegate? - - var recipe: Observable> { - return recipeDetailSubject.asObservable() - } - - init( - fetchRecipeDetailUseCase: FetchRecipeDetailUseCase, - recipeID: Int - ) { + + init(fetchRecipeDetailUseCase: FetchRecipeDetailUseCase, recipeID: Int) { self.fetchRecipeDetailUseCase = fetchRecipeDetailUseCase self.recipeID = recipeID } func setDelegate(_ delegate: RecipeDetailInteractorDelegate) { self.delegate = delegate - bindOutputs() - } - - private func bindOutputs() { - recipe - .subscribe(onNext: { [weak self] result in - self?.delegate?.fetchedRecipe(result: result) - }) - .disposed(by: disposeBag) } - + func viewDidLoad() { fetchRecipeDetail() } - + private func fetchRecipeDetail() { fetchRecipeDetailUseCase.execute(recipeID: recipeID) - .subscribe { [weak self] result in - self?.handleResult(result) - } + .subscribe(onSuccess: { [weak self] result in + self?.delegate?.fetchedRecipe(result: result) + }) .disposed(by: disposeBag) } - - private func handleResult(_ result: Result) { - switch result { - case .success(let recipe): - self.recipeDetailSubject.onNext(.success(recipe)) - case .failure(let error): - self.recipeDetailSubject.onNext(.failure(error)) - } - } } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift index c6ec16d..a038e83 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift @@ -13,12 +13,12 @@ final class RecipeDetailViewController: UIViewController { private let contentView = RecipeDetailView() private let customNavigationBar = CustomNavigationBar() - private let interactor: RecipeDetailInteractor + private let interactor: RecipeDetailInteractorImpl private let disposeBag = DisposeBag() private var recipeDetailViewModel: RecipeDetailViewModel? private let recipeListMapper = RecipeListMapper() - init(interactor: RecipeDetailInteractor) { + init(interactor: RecipeDetailInteractorImpl) { self.interactor = interactor super.init(nibName: nil, bundle: nil) self.interactor.setDelegate(self) @@ -37,7 +37,7 @@ final class RecipeDetailViewController: UIViewController { interactor.viewDidLoad() contentView.customNavigationBar.backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside) } - + private func displayError(_ error: Error) { let alert = UIAlertController(title: "해당 레시피를 로드하는데 실패했습니다.", message: error.localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) @@ -60,7 +60,15 @@ extension RecipeDetailViewController: RecipeDetailInteractorDelegate { self.contentView.configure(with: recipeItemViewModel) } case .failure(let error): - self.displayError(error) + DispatchQueue.main.async { + self.displayError(error) + } } } } + +extension RecipeDetailViewController: Drawable { + var viewController: UIViewController? { + return self + } +} From 7a7cfe1c51dc105668e9bbd782696315a5a14102 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Wed, 17 Jul 2024 22:07:56 +0900 Subject: [PATCH 07/51] =?UTF-8?q?Fix:=20addTarget=EB=A5=BC=20addAction?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes.xcodeproj/project.pbxproj | 14 ++++++++++---- .../UploadRecipe/RecipeUploadImgaeCell.swift | 11 ++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj index a03b736..ce32d2c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj +++ b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj @@ -32,7 +32,6 @@ 1D39721D2C438EDD00495014 /* SelectImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972192C438EDD00495014 /* SelectImageCell.swift */; }; 1D39721E2C438EDD00495014 /* AddRecipeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */; }; 1D39721F2C438EDD00495014 /* RecipeUploadImgaeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */; }; - 1D3972202C438EDD00495014 /* AddRecipeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721C2C438EDD00495014 /* AddRecipeView.swift */; }; 1D3972252C438EF500495014 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972222C438EF500495014 /* AddRecipeRouter.swift */; }; 1D3972262C438EF500495014 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972232C438EF500495014 /* RecipeListRouter.swift */; }; 1D3972272C438EF500495014 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972242C438EF500495014 /* Router.swift */; }; @@ -43,6 +42,8 @@ 1D3972312C43907300495014 /* RecipeUploadDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972302C43907300495014 /* RecipeUploadDTO.swift */; }; 1D3972332C43907B00495014 /* ErrorResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972322C43907B00495014 /* ErrorResponseDTO.swift */; }; 1D3972352C4390E200495014 /* RecipeUploadResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972342C4390E200495014 /* RecipeUploadResponseDTO.swift */; }; + 1D39724C2C43C35700495014 /* AddRecipeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39724B2C43C35700495014 /* AddRecipeView.swift */; }; + 1D39724D2C43C35700495014 /* AddRecipeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39724B2C43C35700495014 /* AddRecipeView.swift */; }; 1D439E9C2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */; }; 1D439E9E2C2C598A008530A5 /* RecipeDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */; }; 1D439EA22C2C6997008530A5 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */; }; @@ -66,6 +67,7 @@ 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */; }; 1D73686E2C305757000EF904 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */; }; 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */; }; + 1DBC63642C47C84900DA00C2 /* AddRecipeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBC63632C47C84900DA00C2 /* AddRecipeError.swift */; }; 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */; }; 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */; }; 1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */; }; @@ -129,7 +131,6 @@ 1D3972192C438EDD00495014 /* SelectImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectImageCell.swift; sourceTree = ""; }; 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeViewController.swift; sourceTree = ""; }; 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeUploadImgaeCell.swift; sourceTree = ""; }; - 1D39721C2C438EDD00495014 /* AddRecipeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeView.swift; sourceTree = ""; }; 1D3972222C438EF500495014 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; 1D3972232C438EF500495014 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; 1D3972242C438EF500495014 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; @@ -140,6 +141,7 @@ 1D3972302C43907300495014 /* RecipeUploadDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeUploadDTO.swift; sourceTree = ""; }; 1D3972322C43907B00495014 /* ErrorResponseDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorResponseDTO.swift; sourceTree = ""; }; 1D3972342C4390E200495014 /* RecipeUploadResponseDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeUploadResponseDTO.swift; sourceTree = ""; }; + 1D39724B2C43C35700495014 /* AddRecipeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeView.swift; sourceTree = ""; }; 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCase.swift; sourceTree = ""; }; 1D439E9D2C2C598A008530A5 /* RecipeDetailRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailRepository.swift; sourceTree = ""; }; 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailInteractor.swift; sourceTree = ""; }; @@ -152,6 +154,7 @@ 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDeatilInteractorTests.swift; sourceTree = ""; }; 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailError.swift; sourceTree = ""; }; + 1DBC63632C47C84900DA00C2 /* AddRecipeError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRecipeError.swift; sourceTree = ""; }; 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRecipeTests.swift; sourceTree = ""; }; 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -207,6 +210,7 @@ 1D1283A12C15E94300C5A870 /* Recipe.swift */, 1D1283A32C15EA8100C5A870 /* RecipeType.swift */, 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */, + 1DBC63632C47C84900DA00C2 /* AddRecipeError.swift */, ); path = Entities; sourceTree = ""; @@ -333,7 +337,7 @@ 1D3972192C438EDD00495014 /* SelectImageCell.swift */, 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */, 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */, - 1D39721C2C438EDD00495014 /* AddRecipeView.swift */, + 1D39724B2C43C35700495014 /* AddRecipeView.swift */, ); path = UploadRecipe; sourceTree = ""; @@ -613,10 +617,10 @@ buildActionMask = 2147483647; files = ( 1D39722B2C438FD300495014 /* SaveRecipeUseCase.swift in Sources */, + 1DBC63642C47C84900DA00C2 /* AddRecipeError.swift in Sources */, 1D3972292C438F1C00495014 /* AddRecipeInteractor.swift in Sources */, 1D439E9E2C2C598A008530A5 /* RecipeDetailRepository.swift in Sources */, 1D2C6F6C2C27051D004BB54E /* CustomNavigationBar.swift in Sources */, - 1D3972202C438EDD00495014 /* AddRecipeView.swift in Sources */, 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */, 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */, 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, @@ -639,6 +643,7 @@ 1D1283AA2C15EBCF00C5A870 /* SearchFeedUseCase.swift in Sources */, 1D39722D2C43904800495014 /* AddRecipeRepository.swift in Sources */, 1D3972142C438E9C00495014 /* User.swift in Sources */, + 1D39724C2C43C35700495014 /* AddRecipeView.swift in Sources */, 1D3972332C43907B00495014 /* ErrorResponseDTO.swift in Sources */, 1DE19EA82C1B420A0031804A /* SearchFeedListRepository.swift in Sources */, 1DE19EC32C1B422F0031804A /* SearchBar.swift in Sources */, @@ -687,6 +692,7 @@ 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */, 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */, 1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */, + 1D39724D2C43C35700495014 /* AddRecipeView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift index 2eb5000..739cd97 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift @@ -56,7 +56,12 @@ final class RecipeUploadImgaeCell: UICollectionViewCell { private func setupDeleteButton() { deleteButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) deleteButton.tintColor = .white - deleteButton.addTarget(self, action: #selector(deleteImage), for: .touchUpInside) + deleteButton.addAction( + UIAction(handler: { [weak self] _ in + self?.delegate?.didTapDeleteButton(self!) + }), + for: .touchUpInside + ) } private func addSubviews() { @@ -93,8 +98,4 @@ final class RecipeUploadImgaeCell: UICollectionViewCell { imageView.image = image representativeLabel.isHidden = !isRepresentative } - - @objc private func deleteImage() { - delegate?.didTapDeleteButton(in: self) - } } From bdd5f40457350e4c28df28c5a35d82cd0071c055 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Wed, 17 Jul 2024 22:10:00 +0900 Subject: [PATCH 08/51] =?UTF-8?q?Fix:=20[weak=20self]=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeViewController.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 2666e5c..0c728f4 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -194,8 +194,9 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { } } - dispatchGroup.notify(queue: .main) { - self.contentView.images.append(contentsOf: newImages) + dispatchGroup.notify(queue: .main) { [weak self] in + guard let self else { return } + self.updateImages(newImages: self.images + newImages) } } } From bf8676f64975b31a3c31509429084189421ce1a7 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Wed, 17 Jul 2024 23:51:49 +0900 Subject: [PATCH 09/51] =?UTF-8?q?Fix:=20RecipeListViewController=EA=B0=80?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=EC=B2=B4=EA=B0=80=20=EC=95=84=EB=8B=8C=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=86=A0=EC=BD=9C=EC=9D=84=20=EB=B3=B4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FeedList/View/RecipeListViewController.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift index 0b7d44b..65e19f2 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift @@ -9,13 +9,14 @@ import UIKit final class RecipeListViewController: UIViewController { - private var interactor: RecipeListInteractorImpl + private var interactor: RecipeListInteractor + private var recipes: [RecipeListItemViewModel] = [] private let searchBar = SearchBar() private let recipeListView = RecipeListView() private let recipeListMapper = RecipeListMapper() private let router: RecipeListRouterProtocol - init(interactor: RecipeListInteractorImpl, router: RecipeListRouterProtocol) { + init(interactor: RecipeListInteractor, router: RecipeListRouterProtocol) { self.interactor = interactor self.router = router super.init(nibName: nil, bundle: nil) From a1b8b3731ef6eb9b46eb16d6101175b062d2851d Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Wed, 17 Jul 2024 23:55:05 +0900 Subject: [PATCH 10/51] =?UTF-8?q?Fix:=20RecipeDetailViewController?= =?UTF-8?q?=EA=B0=80=20=EA=B5=AC=ED=98=84=EC=B2=B4=EA=B0=80=20=EC=95=84?= =?UTF-8?q?=EB=8B=8C=20=ED=94=84=EB=A1=9C=ED=86=A0=EC=BD=9C=EC=9D=84=20?= =?UTF-8?q?=EB=B3=B4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Feed/View/RecipeDetailViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift index a038e83..b833a01 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift @@ -13,12 +13,12 @@ final class RecipeDetailViewController: UIViewController { private let contentView = RecipeDetailView() private let customNavigationBar = CustomNavigationBar() - private let interactor: RecipeDetailInteractorImpl + private let interactor: RecipeDetailInteractor private let disposeBag = DisposeBag() private var recipeDetailViewModel: RecipeDetailViewModel? private let recipeListMapper = RecipeListMapper() - init(interactor: RecipeDetailInteractorImpl) { + init(interactor: RecipeDetailInteractor) { self.interactor = interactor super.init(nibName: nil, bundle: nil) self.interactor.setDelegate(self) From ef21ffea381303af167e29e36acf313bf1d1ab94 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Wed, 17 Jul 2024 23:57:31 +0900 Subject: [PATCH 11/51] =?UTF-8?q?Fix:=20execute=20=EC=8B=A4=ED=8C=A8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/Interactor/RecipeDetailInteractor.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift index ef9c80c..1d4a4d9 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift @@ -41,6 +41,8 @@ class RecipeDetailInteractorImpl: RecipeDetailInteractor { fetchRecipeDetailUseCase.execute(recipeID: recipeID) .subscribe(onSuccess: { [weak self] result in self?.delegate?.fetchedRecipe(result: result) + }, onFailure: { [weak self] error in + self?.delegate?.fetchedRecipe(result: .failure(error)) }) .disposed(by: disposeBag) } From 718ce57083fc18428df34847a4cc7a9cb1420027 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Wed, 17 Jul 2024 23:58:17 +0900 Subject: [PATCH 12/51] =?UTF-8?q?Fix:=20RecipeListInteractor,=20RecipeDeta?= =?UTF-8?q?ilInteractor=20=ED=8F=AC=EB=A1=9C=ED=86=A0=EC=BD=9C=EC=97=90=20?= =?UTF-8?q?setDelegate=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/Interactor/RecipeDetailInteractor.swift | 1 + .../HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift index 1d4a4d9..387a18a 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift @@ -15,6 +15,7 @@ protocol RecipeDetailInteractorDelegate: AnyObject { protocol RecipeDetailInteractor { func viewDidLoad() + func setDelegate(_ delegate: RecipeDetailInteractorDelegate) } class RecipeDetailInteractorImpl: RecipeDetailInteractor { diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift index 65ced8d..375db4f 100755 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift @@ -20,6 +20,7 @@ protocol RecipeListInteractor { func didSelectItem(ID: Int) func searchRecipes(with query: String) func resetSearch() + func setDelegate(_ delegate: RecipeListInteractorDelegate) } class RecipeListInteractorImpl: RecipeListInteractor { From 54ef20385de02a468e31429449b823e87cb23373 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 10:52:54 +0900 Subject: [PATCH 13/51] =?UTF-8?q?Fix:=20ViewController=EC=97=90=20?= =?UTF-8?q?=EC=9E=88=EB=8D=98=20addTarget=EC=9D=84=20contentView=EC=97=90?= =?UTF-8?q?=EC=84=9C=20addAction=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeView.swift | 7 +++++++ .../UploadRecipe/AddRecipeViewController.swift | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index c3e75e5..360da62 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -10,6 +10,7 @@ import UIKit protocol AddRecipeViewDelegate: AnyObject { func selectImageButtonTapped() func didTapDeleteButton(at index: Int) + func didTapSubmitButton() } final class AddRecipeView: UIView { @@ -96,6 +97,12 @@ final class AddRecipeView: UIView { submitButton.setTitleColor(.white, for: .normal) submitButton.backgroundColor = .blue submitButton.layer.cornerRadius = 5 + submitButton.addAction( + UIAction( + handler: { [weak self] _ in + self?.delegate?.didTapSubmitButton() + }) + , for: .touchUpInside) } private func setupCustomNavigationBar() { diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 0c728f4..d6dedff 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -35,7 +35,6 @@ final class AddRecipeViewController: UIViewController { super.viewDidLoad() setupUI() contentView.delegate = self - contentView.submitButton.addTarget(self, action: #selector(saveRecipe), for: .touchUpInside) setupNavigationBar() } @@ -168,6 +167,13 @@ extension AddRecipeViewController: AddRecipeViewDelegate { func didTapDeleteButton(at index: Int) { contentView.images.remove(at: index) + func didTapSubmitButton() { + let title = contentView.getTitleText() ?? "" + let description = contentView.getDescriptionText() ?? "" + addRecipeInteractor.updateTitle(title) + addRecipeInteractor.updateDescription(description) + saveRecipeToServer() + } } } From 0ea1638dde567808af0e51e12f66a8df1b1d39b0 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 11:02:06 +0900 Subject: [PATCH 14/51] =?UTF-8?q?Fix:=20saveRecipe=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20=ED=9B=84=20saveRecipeToServer?= =?UTF-8?q?=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=97=AC=20=EB=94=94?= =?UTF-8?q?=ED=85=8C=EC=9D=BC=ED=95=9C=20=EB=A1=9C=EC=A7=81=EC=9D=80=20int?= =?UTF-8?q?eractor=EC=97=90=EC=84=9C=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddRecipeViewController.swift | 47 +++++-------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index d6dedff..809380e 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -62,44 +62,21 @@ final class AddRecipeViewController: UIViewController { navigationController?.popViewController(animated: true) } - @objc private func saveRecipe() { - guard !contentView.images.isEmpty else { - showAlert(title: "이미지 없음", message: "최소 한 장의 이미지를 추가해 주세요.") - return - } - guard let title = contentView.titleTextField.text, let description = contentView.descriptionTextView.text else { - showAlert(title: "입력 오류", message: "제목과 설명을 모두 입력해 주세요.") - return - } - - guard !title.isBlank else { - showAlert(title: "제목 없음", message: "제목을 입력해 주세요.") - return - } - - guard description.count > 10 else { - showAlert(title: "설명 부족", message: "설명을 10자 이상 입력해 주세요.") - return - } - - saveRecipeToServer(title: title, description: description, images: contentView.images) - } - - private func saveRecipeToServer(title: String, description: String, images: [UIImage]) { - + private func saveRecipeToServer() { // MARK: 임시 userID 설정 - let userId = 6 - let recipeType = recipeType.rawValue - - addRecipeInteractor.saveRecipe(userId: userId, recipeType: recipeType, title: title, description: description, images: images) - .subscribe(onSuccess: { recipe in + let userID = 6 + + addRecipeInteractor.saveRecipe(userID: userID, recipeType: recipeType) + .subscribe(onSuccess: { [weak self] result in DispatchQueue.main.async { - self.showSuccessAlert(title: "업로드 성공", message: "레시피가 성공적으로 업로드되었습니다.", success: true) - } }, onFailure: { error in - DispatchQueue.main.async { - self.showSuccessAlert(title: "업로드 실패", message: "레시피 업로드에 실패했습니다.", success: false) + switch result { + case .success: + self?.showCompletedAlert(title: "업로드 성공", message: "레시피가 성공적으로 업로드되었습니다.", success: true) + case .failure(let error): + self?.showCompletedAlert(title: error.title, message: error.localizedDescription, success: false) } - }) + } + }) .disposed(by: disposeBag) } From 58ca752240cc08e04c6578774bcae89cef6f7567 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 11:02:57 +0900 Subject: [PATCH 15/51] =?UTF-8?q?Fix:=20showAlert,showSuccessAlert?= =?UTF-8?q?=EC=9D=84=20showCompletedAlert=EB=A1=9C=20=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeViewController.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 809380e..17fa240 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -80,7 +80,7 @@ final class AddRecipeViewController: UIViewController { .disposed(by: disposeBag) } - private func showSuccessAlert(title: String, message: String, success: Bool) { + private func showCompletedAlert(title: String, message: String, success: Bool) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in if success { @@ -91,12 +91,6 @@ final class AddRecipeViewController: UIViewController { present(alert, animated: true, completion: nil) } - private func showAlert(title: String, message: String) { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "확인", style: .default, handler: nil)) - present(alert, animated: true, completion: nil) - } - private func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) { let status = PHPhotoLibrary.authorizationStatus() switch status { From a67556459dc9307cfebd1cdb91baa7d3980b79b7 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 12:12:23 +0900 Subject: [PATCH 16/51] =?UTF-8?q?Fix:=20View=EC=97=90=20images=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=9B=84=20collectionView=EB=A5=BC=20private?= =?UTF-8?q?=20=ED=95=98=EA=B2=8C=20=EC=B2=98=EB=A6=AC,=20didset=EC=97=90?= =?UTF-8?q?=20=EC=9E=88=EB=8D=98=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=93=A4?= =?UTF-8?q?=EC=9D=84=20=EB=94=B0=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20=EC=8B=9C?= =?UTF-8?q?=EC=BC=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeView.swift | 16 +++++++++------- .../UploadRecipe/AddRecipeViewController.swift | 11 +++++++++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index 360da62..d87d7e2 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -22,17 +22,11 @@ final class AddRecipeView: UIView { let titleTextField = UITextField() let descriptionTextView = UITextView() let submitButton = UIButton(type: .system) + private let collectionView: UICollectionView let customNavigationBar = CustomNavigationBar() weak var delegate: AddRecipeViewDelegate? - var images: [UIImage] = [] { - didSet { - collectionView.reloadData() - imageCounterLabel.text = "\(images.count)/5" - } - } - override init(frame: CGRect) { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal @@ -168,6 +162,14 @@ final class AddRecipeView: UIView { submitButton.heightAnchor.constraint(equalToConstant: 50) ]) } + + func updateImageCounter(count: Int) { + imageCounterLabel.text = "\(count)/5" + } + + func reloadCollectionView() { + collectionView.reloadData() + } } // MARK: UICollectionViewDataSource diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 17fa240..1dd4229 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -117,7 +117,7 @@ extension AddRecipeViewController: AddRecipeViewDelegate { checkPhotoLibraryPermission { granted in if granted { var config = PHPickerConfiguration() - config.selectionLimit = 5 - self.contentView.images.count + config.selectionLimit = 5 config.filter = .images let picker = PHPickerViewController(configuration: config) @@ -138,6 +138,10 @@ extension AddRecipeViewController: AddRecipeViewDelegate { func didTapDeleteButton(at index: Int) { contentView.images.remove(at: index) + contentView.reloadCollectionView() + contentView.updateImageCounter(count: addRecipeInteractor.numberOfImages()) + } + func didTapSubmitButton() { let title = contentView.getTitleText() ?? "" let description = contentView.getDescriptionText() ?? "" @@ -173,7 +177,8 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { dispatchGroup.notify(queue: .main) { [weak self] in guard let self else { return } - self.updateImages(newImages: self.images + newImages) + self.contentView.reloadCollectionView() + self.contentView.updateImageCounter(count: self.addRecipeInteractor.numberOfImages()) } } } @@ -185,5 +190,7 @@ extension AddRecipeViewController: ImageCollectionViewCellDelegate { if let indexPath = contentView.collectionView.indexPath(for: cell) { contentView.images.remove(at: indexPath.item - 1) } + contentView.reloadCollectionView() + contentView.updateImageCounter(count: addRecipeInteractor.numberOfImages()) } } From 33d696f2d6a9a72b0c11b155c5d13f042e6667fd Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 12:15:31 +0900 Subject: [PATCH 17/51] =?UTF-8?q?Fix:=20didTapDeleteButton=20in=EC=9D=84?= =?UTF-8?q?=20=5F=20=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeView.swift | 2 +- .../UploadRecipe/AddRecipeViewController.swift | 7 +++---- .../Presentation/UploadRecipe/RecipeUploadImgaeCell.swift | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index d87d7e2..92ef648 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -213,7 +213,7 @@ extension AddRecipeView { // MARK: ImageCollectionViewCellDelegate extension AddRecipeView: ImageCollectionViewCellDelegate { - func didTapDeleteButton(in cell: RecipeUploadImgaeCell) { + func didTapDeleteButton(_ cell: RecipeUploadImgaeCell) { if let indexPath = collectionView.indexPath(for: cell) { delegate?.didTapDeleteButton(at: indexPath.item - 1) } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 1dd4229..6502e90 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -186,10 +186,9 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { // MARK: ImageCollectionViewCellDelegate extension AddRecipeViewController: ImageCollectionViewCellDelegate { - func didTapDeleteButton(in cell: RecipeUploadImgaeCell) { - if let indexPath = contentView.collectionView.indexPath(for: cell) { - contentView.images.remove(at: indexPath.item - 1) - } + func didTapDeleteButton(_ cell: RecipeUploadImgaeCell) { + guard let indexPath = contentView.indexPathForCell(cell) else { return } + addRecipeInteractor.removeImage(at: indexPath.item - 1) contentView.reloadCollectionView() contentView.updateImageCounter(count: addRecipeInteractor.numberOfImages()) } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift index 739cd97..d8a5844 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift @@ -8,7 +8,7 @@ import UIKit protocol ImageCollectionViewCellDelegate: AnyObject { - func didTapDeleteButton(in cell: RecipeUploadImgaeCell) + func didTapDeleteButton(_ cell: RecipeUploadImgaeCell) } final class RecipeUploadImgaeCell: UICollectionViewCell { From 84b39d74600b55728be6e4b8962f70b41ee5bca9 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 12:17:02 +0900 Subject: [PATCH 18/51] =?UTF-8?q?Fix:=20=EA=B0=81=20UI=EC=9A=94=EC=86=8C?= =?UTF-8?q?=EB=93=A4=EC=9D=84=20private=20=ED=95=98=EA=B2=8C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=ED=9B=84=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=B4=20=EC=A0=91=EA=B7=BC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeView.swift | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index 92ef648..2988926 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -18,11 +18,10 @@ final class AddRecipeView: UIView { private let imageCounterLabel = UILabel() private let titleLabel = UILabel() private let descriptionLabel = UILabel() - let collectionView: UICollectionView - let titleTextField = UITextField() - let descriptionTextView = UITextView() - let submitButton = UIButton(type: .system) private let collectionView: UICollectionView + private let titleTextField = UITextField() + private let descriptionTextView = UITextView() + private let submitButton = UIButton(type: .system) let customNavigationBar = CustomNavigationBar() weak var delegate: AddRecipeViewDelegate? @@ -170,6 +169,18 @@ final class AddRecipeView: UIView { func reloadCollectionView() { collectionView.reloadData() } + + func getTitleText() -> String? { + return titleTextField.text + } + + func getDescriptionText() -> String? { + return descriptionTextView.text + } + + func indexPathForCell(_ cell: UICollectionViewCell) -> IndexPath? { + return collectionView.indexPath(for: cell) + } } // MARK: UICollectionViewDataSource From 496945c2ff03804db53299b26dbad7d65690ed5c Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 12:18:01 +0900 Subject: [PATCH 19/51] =?UTF-8?q?Fix:=20addTarget=EC=9D=84=20addAction?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeView.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index 2988926..1da6a95 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -193,7 +193,14 @@ extension AddRecipeView: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if indexPath.item == 0 { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SelectImageCell", for: indexPath) as! SelectImageCell - cell.selectImageButton.addTarget(self, action: #selector(selectImageButtonTapped), for: .touchUpInside) + cell.selectImageButton.addAction( + UIAction( + handler: { [weak self] _ in + self?.delegate?.selectImageButtonTapped() + } + ), + for: .touchUpInside + ) return cell } else { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! RecipeUploadImgaeCell @@ -210,17 +217,10 @@ extension AddRecipeView: UICollectionViewDataSource { extension AddRecipeView: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if indexPath.item == 0 { - selectImageButtonTapped() + delegate?.selectImageButtonTapped() } } } - -extension AddRecipeView { - @objc private func selectImageButtonTapped() { - delegate?.selectImageButtonTapped() - } -} - // MARK: ImageCollectionViewCellDelegate extension AddRecipeView: ImageCollectionViewCellDelegate { From bed3b82d9a63d33508690576d12a76886826c29d Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 12:18:44 +0900 Subject: [PATCH 20/51] =?UTF-8?q?Fix:=20numberOfImages,recipeImage=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=86=A0=EC=BD=9C=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeView.swift | 12 ++++++++---- .../UploadRecipe/AddRecipeViewController.swift | 7 +++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index 1da6a95..018742a 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -11,6 +11,8 @@ protocol AddRecipeViewDelegate: AnyObject { func selectImageButtonTapped() func didTapDeleteButton(at index: Int) func didTapSubmitButton() + func numberOfImages() -> Int + func recipeImage(at index: Int) -> UIImage? } final class AddRecipeView: UIView { @@ -186,8 +188,9 @@ final class AddRecipeView: UIView { // MARK: UICollectionViewDataSource extension AddRecipeView: UICollectionViewDataSource { - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return images.count + 1 + func collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { + return (delegate?.numberOfImages() ?? 0) + 1 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { @@ -204,8 +207,9 @@ extension AddRecipeView: UICollectionViewDataSource { return cell } else { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! RecipeUploadImgaeCell - let image = images[indexPath.item - 1] - cell.configure(with: image, isRepresentative: indexPath.item == 1) + if let image = delegate?.recipeImage(at: indexPath.item - 1) { + cell.configure(with: image, isRepresentative: indexPath.item == 1) + } cell.delegate = self return cell } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 6502e90..3c2b732 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -149,6 +149,13 @@ extension AddRecipeViewController: AddRecipeViewDelegate { addRecipeInteractor.updateDescription(description) saveRecipeToServer() } + + func numberOfImages() -> Int { + return addRecipeInteractor.numberOfImages() + } + + func recipeImage(at index: Int) -> UIImage? { + return addRecipeInteractor.image(at: index) } } From eb151d29968798e8e68aa656eabf50e40df3b963 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 12:19:07 +0900 Subject: [PATCH 21/51] =?UTF-8?q?Fix:=20images=EB=A5=BC=20interactor?= =?UTF-8?q?=EB=A1=9C=20=EA=B4=80=EB=A6=AC=ED=95=98=EB=A9=B4=EC=84=9C=20?= =?UTF-8?q?=EC=83=9D=EA=B8=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeViewController.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 3c2b732..0bffddc 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -137,7 +137,7 @@ extension AddRecipeViewController: AddRecipeViewDelegate { } func didTapDeleteButton(at index: Int) { - contentView.images.remove(at: index) + addRecipeInteractor.removeImage(at: index) contentView.reloadCollectionView() contentView.updateImageCounter(count: addRecipeInteractor.numberOfImages()) } @@ -184,6 +184,7 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { dispatchGroup.notify(queue: .main) { [weak self] in guard let self else { return } + newImages.forEach { self.addRecipeInteractor.addImage($0) } self.contentView.reloadCollectionView() self.contentView.updateImageCounter(count: self.addRecipeInteractor.numberOfImages()) } From e44034815111774782b293d239840489257b3d5c Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 15:53:10 +0900 Subject: [PATCH 22/51] =?UTF-8?q?Fix:=20=EC=86=8D=EC=84=B1=EA=B0=92?= =?UTF-8?q?=EC=9D=84=20=EC=84=A0=EC=96=B8=EB=B6=80=EC=97=90=20=EC=84=A0?= =?UTF-8?q?=EC=96=B8=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeView.swift | 100 ++++++++++-------- .../UploadRecipe/RecipeUploadImgaeCell.swift | 69 ++++++------ 2 files changed, 87 insertions(+), 82 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index 018742a..f2e38ba 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -17,13 +17,59 @@ protocol AddRecipeViewDelegate: AnyObject { final class AddRecipeView: UIView { - private let imageCounterLabel = UILabel() - private let titleLabel = UILabel() - private let descriptionLabel = UILabel() + private let imageCounterLabel: UILabel = { + let label = UILabel() + label.font = Fonts.bodyFont + label.textColor = .gray + label.text = "0/5" + return label + }() + + private let titleLabel: UILabel = { + let label = UILabel() + label.text = "제목" + return label + }() + + private let descriptionLabel: UILabel = { + let label = UILabel() + label.text = "내용" + return label + }() + private let collectionView: UICollectionView - private let titleTextField = UITextField() - private let descriptionTextView = UITextView() - private let submitButton = UIButton(type: .system) + + private let titleTextField: UITextField = { + let textField = UITextField() + textField.placeholder = "제목을 입력하세요" + textField.borderStyle = .roundedRect + return textField + }() + + private let descriptionTextView: UITextView = { + let textView = UITextView() + textView.layer.borderColor = UIColor.lightGray.cgColor + textView.layer.borderWidth = 1 + textView.layer.cornerRadius = 5 + textView.font = Fonts.titleFont + return textView + }() + + private lazy var submitButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("레시피 등록", for: .normal) + button.setTitleColor(.white, for: .normal) + button.backgroundColor = .blue + button.layer.cornerRadius = 5 + button.addAction( + UIAction( + handler: { [weak self] _ in + self?.delegate?.didTapSubmitButton() + }), + for: .touchUpInside) + return button + }() + let customNavigationBar = CustomNavigationBar() weak var delegate: AddRecipeViewDelegate? @@ -46,59 +92,18 @@ final class AddRecipeView: UIView { private func setupUI() { backgroundColor = .white - - setupLabel() setupCollectionView() - setupImageCounterLabel() - setupTitleTextField() - setupDescriptionTextView() - setupSubmitButton() setupCustomNavigationBar() addSubviews() setupConstraints() } - private func setupLabel() { - titleLabel.text = "제목" - descriptionLabel.text = "내용" - } - private func setupCollectionView() { collectionView.dataSource = self collectionView.delegate = self collectionView.register(RecipeUploadImgaeCell.self, forCellWithReuseIdentifier: "ImageCell") collectionView.register(SelectImageCell.self, forCellWithReuseIdentifier: "SelectImageCell") } - private func setupImageCounterLabel() { - imageCounterLabel.font = Fonts.bodyFont - imageCounterLabel.textColor = .gray - imageCounterLabel.text = "0/5" - } - - private func setupTitleTextField() { - titleTextField.placeholder = "제목을 입력하세요" - titleTextField.borderStyle = .roundedRect - } - - private func setupDescriptionTextView() { - descriptionTextView.layer.borderColor = UIColor.lightGray.cgColor - descriptionTextView.layer.borderWidth = 1 - descriptionTextView.layer.cornerRadius = 5 - descriptionTextView.font = Fonts.titleFont - } - - private func setupSubmitButton() { - submitButton.setTitle("레시피 등록", for: .normal) - submitButton.setTitleColor(.white, for: .normal) - submitButton.backgroundColor = .blue - submitButton.layer.cornerRadius = 5 - submitButton.addAction( - UIAction( - handler: { [weak self] _ in - self?.delegate?.didTapSubmitButton() - }) - , for: .touchUpInside) - } private func setupCustomNavigationBar() { customNavigationBar.translatesAutoresizingMaskIntoConstraints = false @@ -225,6 +230,7 @@ extension AddRecipeView: UICollectionViewDelegate { } } } + // MARK: ImageCollectionViewCellDelegate extension AddRecipeView: ImageCollectionViewCellDelegate { diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift index d8a5844..c89e6e2 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/RecipeUploadImgaeCell.swift @@ -13,9 +13,40 @@ protocol ImageCollectionViewCellDelegate: AnyObject { final class RecipeUploadImgaeCell: UICollectionViewCell { - private let imageView = UIImageView() - private let representativeLabel = UILabel() - private let deleteButton = UIButton(type: .system) + private let imageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.layer.cornerRadius = 10 + return imageView + }() + + private let representativeLabel: UILabel = { + let label = UILabel() + label.font = Fonts.bodyFont + label.textColor = .white + label.backgroundColor = .gray + label.text = "대표 사진" + label.textAlignment = .center + label.isHidden = true + label.layer.cornerRadius = 10 + label.clipsToBounds = true + return label + }() + + private lazy var deleteButton: UIButton = { + let button = UIButton(type: .system) + button.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) + button.tintColor = .white + button.addAction( + UIAction(handler: { [weak self] _ in + guard let self = self else { return } + self.delegate?.didTapDeleteButton(self) + }), + for: .touchUpInside + ) + return button + }() weak var delegate: ImageCollectionViewCellDelegate? @@ -29,41 +60,10 @@ final class RecipeUploadImgaeCell: UICollectionViewCell { } private func setupUI() { - setupImageView() - setupLabel() - setupDeleteButton() addSubviews() setupConstraints() } - private func setupImageView() { - imageView.contentMode = .scaleAspectFill - imageView.clipsToBounds = true - imageView.layer.cornerRadius = 10 - } - - private func setupLabel() { - representativeLabel.font = .systemFont(ofSize: 12, weight: .bold) - representativeLabel.textColor = .white - representativeLabel.backgroundColor = .gray - representativeLabel.text = "대표 사진" - representativeLabel.textAlignment = .center - representativeLabel.isHidden = true - representativeLabel.layer.cornerRadius = 10 - representativeLabel.clipsToBounds = true - } - - private func setupDeleteButton() { - deleteButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) - deleteButton.tintColor = .white - deleteButton.addAction( - UIAction(handler: { [weak self] _ in - self?.delegate?.didTapDeleteButton(self!) - }), - for: .touchUpInside - ) - } - private func addSubviews() { contentView.addSubview(imageView) contentView.addSubview(representativeLabel) @@ -91,7 +91,6 @@ final class RecipeUploadImgaeCell: UICollectionViewCell { deleteButton.widthAnchor.constraint(equalToConstant: 20), deleteButton.heightAnchor.constraint(equalToConstant: 20) ]) - } func configure(with image: UIImage, isRepresentative: Bool) { From 433cc5518db753c329ebce4c76b32c1541c120ce Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 22:48:52 +0900 Subject: [PATCH 23/51] =?UTF-8?q?Fix:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=82=B4=EC=9A=A9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Feed/View/RecipeDetailViewController.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift index b833a01..75dc4e3 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift @@ -67,8 +67,3 @@ extension RecipeDetailViewController: RecipeDetailInteractorDelegate { } } -extension RecipeDetailViewController: Drawable { - var viewController: UIViewController? { - return self - } -} From b583cae56c04d1af47cfb72a988c9a5fd26de475 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 23:01:46 +0900 Subject: [PATCH 24/51] =?UTF-8?q?Fix:=20=EC=A4=84=EB=B0=94=EA=BF=88=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/Interactor/RecipeDetailInteractor.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift index 387a18a..931ce56 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift @@ -25,7 +25,10 @@ class RecipeDetailInteractorImpl: RecipeDetailInteractor { private let disposeBag = DisposeBag() weak var delegate: RecipeDetailInteractorDelegate? - init(fetchRecipeDetailUseCase: FetchRecipeDetailUseCase, recipeID: Int) { + init( + fetchRecipeDetailUseCase: FetchRecipeDetailUseCase, + recipeID: Int + ) { self.fetchRecipeDetailUseCase = fetchRecipeDetailUseCase self.recipeID = recipeID } From e7381ee4628e15415a0e33ed7db153973c1b7cdf Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Thu, 18 Jul 2024 23:25:51 +0900 Subject: [PATCH 25/51] =?UTF-8?q?Fix:=20touchUpInside=20=EC=A4=84=EB=B0=94?= =?UTF-8?q?=EA=BF=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeView.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index f2e38ba..d261d57 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -66,7 +66,8 @@ final class AddRecipeView: UIView { handler: { [weak self] _ in self?.delegate?.didTapSubmitButton() }), - for: .touchUpInside) + for: .touchUpInside + ) return button }() From 15e3b644f79c4f6681ebc7394a5c1d62e5d0ae2b Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 02:06:06 +0900 Subject: [PATCH 26/51] =?UTF-8?q?Fix:=20updateImageCounter,reloadCollectio?= =?UTF-8?q?nView=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20updateImageView?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=20=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeView.swift | 5 +---- .../UploadRecipe/AddRecipeViewController.swift | 11 ++++------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index d261d57..d011d03 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -170,11 +170,8 @@ final class AddRecipeView: UIView { ]) } - func updateImageCounter(count: Int) { + func updateImageView(count: Int) { imageCounterLabel.text = "\(count)/5" - } - - func reloadCollectionView() { collectionView.reloadData() } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 0bffddc..212184b 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -138,8 +138,7 @@ extension AddRecipeViewController: AddRecipeViewDelegate { func didTapDeleteButton(at index: Int) { addRecipeInteractor.removeImage(at: index) - contentView.reloadCollectionView() - contentView.updateImageCounter(count: addRecipeInteractor.numberOfImages()) + contentView.updateImageView(count: addRecipeViewModel.images.count) } func didTapSubmitButton() { @@ -185,8 +184,7 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { dispatchGroup.notify(queue: .main) { [weak self] in guard let self else { return } newImages.forEach { self.addRecipeInteractor.addImage($0) } - self.contentView.reloadCollectionView() - self.contentView.updateImageCounter(count: self.addRecipeInteractor.numberOfImages()) + contentView.updateImageView(count: numberOfImages()) } } } @@ -196,8 +194,7 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { extension AddRecipeViewController: ImageCollectionViewCellDelegate { func didTapDeleteButton(_ cell: RecipeUploadImgaeCell) { guard let indexPath = contentView.indexPathForCell(cell) else { return } - addRecipeInteractor.removeImage(at: indexPath.item - 1) - contentView.reloadCollectionView() - contentView.updateImageCounter(count: addRecipeInteractor.numberOfImages()) + addRecipeInteractor.removeRecipeImage(at: indexPath.item - 1) + contentView.updateImageView(count: self.numberOfImages()) } } From 0e5df0294181a1fb997d5f466233a2b7f663ad9a Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 02:06:31 +0900 Subject: [PATCH 27/51] =?UTF-8?q?Feat:=20AddRecipeViewModel=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeViewModel.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewModel.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewModel.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewModel.swift new file mode 100644 index 0000000..721ef1b --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewModel.swift @@ -0,0 +1,14 @@ +// +// AddRecipeViewModel.swift +// HomeCafeRecipes +// +// Created by 김건호 on 7/19/24. +// + +import UIKit + +struct AddRecipeViewModel { + var images: [UIImage] + var title: String + var description: String +} From 10151ba101a1e7d8b058d907c904ba7a9fbebe17 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 02:08:50 +0900 Subject: [PATCH 28/51] =?UTF-8?q?Fix:=20ViewModel=EC=9D=84=20=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=97=AC=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRecipe/AddRecipeViewController.swift | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 212184b..c5fe316 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -16,10 +16,12 @@ final class AddRecipeViewController: UIViewController { private let recipeType: RecipeType private let addRecipeInteractor: AddRecipeInteractor private let disposeBag = DisposeBag() + private var addRecipeViewModel: AddRecipeViewModel init(recipeType: RecipeType, addRecipeInteractor: AddRecipeInteractor) { self.recipeType = recipeType self.addRecipeInteractor = addRecipeInteractor + self.addRecipeViewModel = AddRecipeViewModel(images: addRecipeInteractor.getRecipeImages(), title: addRecipeInteractor.getRecipeTitle(), description: addRecipeInteractor.getRecipeDescription()) super.init(nibName: nil, bundle: nil) } @@ -138,6 +140,7 @@ extension AddRecipeViewController: AddRecipeViewDelegate { func didTapDeleteButton(at index: Int) { addRecipeInteractor.removeImage(at: index) + updateaddRecipeViewModel() contentView.updateImageView(count: addRecipeViewModel.images.count) } @@ -150,11 +153,19 @@ extension AddRecipeViewController: AddRecipeViewDelegate { } func numberOfImages() -> Int { - return addRecipeInteractor.numberOfImages() + return addRecipeViewModel.images.count } func recipeImage(at index: Int) -> UIImage? { - return addRecipeInteractor.image(at: index) + return addRecipeViewModel.images[index] + } + + private func updateaddRecipeViewModel() { + addRecipeViewModel = AddRecipeViewModel( + images: addRecipeInteractor.getRecipeImages(), + title: addRecipeInteractor.getRecipeTitle(), + description: addRecipeInteractor.getRecipeDescription() + ) } } @@ -184,6 +195,7 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { dispatchGroup.notify(queue: .main) { [weak self] in guard let self else { return } newImages.forEach { self.addRecipeInteractor.addImage($0) } + updateaddRecipeViewModel() contentView.updateImageView(count: numberOfImages()) } } From 77bab892ef3aeb89864efc586427fed33b4be28d Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 02:23:30 +0900 Subject: [PATCH 29/51] =?UTF-8?q?Fix:=20getTitleText,getDescriptionText?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20computed=20property?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes.xcodeproj/project.pbxproj | 66 +++++++++++++------ .../UploadRecipe/AddRecipeView.swift | 6 +- .../AddRecipeViewController.swift | 4 +- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj index ce32d2c..c4701d4 100644 --- a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj +++ b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj @@ -16,6 +16,17 @@ 1D1283B42C16983900C5A870 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 1D1283B32C16983900C5A870 /* RxSwift */; }; 1D1283B62C16984E00C5A870 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 1D1283B52C16984E00C5A870 /* RxCocoa */; }; 1D1283CA2C16D9C600C5A870 /* RecipeFetchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283C92C16D9C600C5A870 /* RecipeFetchService.swift */; }; + 1D166CFC2C49666B00A50963 /* AddRecipeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166CFB2C49666B00A50963 /* AddRecipeViewModel.swift */; }; + 1D166CFD2C49666B00A50963 /* AddRecipeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166CFB2C49666B00A50963 /* AddRecipeViewModel.swift */; }; + 1D166D032C4ACD9F00A50963 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D002C4ACD9F00A50963 /* AddRecipeRouter.swift */; }; + 1D166D042C4ACD9F00A50963 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D002C4ACD9F00A50963 /* AddRecipeRouter.swift */; }; + 1D166D052C4ACD9F00A50963 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D012C4ACD9F00A50963 /* RecipeListRouter.swift */; }; + 1D166D062C4ACD9F00A50963 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D012C4ACD9F00A50963 /* RecipeListRouter.swift */; }; + 1D166D072C4ACD9F00A50963 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D022C4ACD9F00A50963 /* Router.swift */; }; + 1D166D082C4ACD9F00A50963 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D022C4ACD9F00A50963 /* Router.swift */; }; + 1D166D092C4AD3B600A50963 /* AddRecipeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */; }; + 1D166D0A2C4AD3B600A50963 /* RecipeUploadImgaeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */; }; + 1D166D0B2C4AD3B600A50963 /* SelectImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972192C438EDD00495014 /* SelectImageCell.swift */; }; 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E52BE532B700C04508 /* AppDelegate.swift */; }; 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E92BE532B700C04508 /* ViewController.swift */; }; 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */; }; @@ -32,9 +43,6 @@ 1D39721D2C438EDD00495014 /* SelectImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972192C438EDD00495014 /* SelectImageCell.swift */; }; 1D39721E2C438EDD00495014 /* AddRecipeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */; }; 1D39721F2C438EDD00495014 /* RecipeUploadImgaeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */; }; - 1D3972252C438EF500495014 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972222C438EF500495014 /* AddRecipeRouter.swift */; }; - 1D3972262C438EF500495014 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972232C438EF500495014 /* RecipeListRouter.swift */; }; - 1D3972272C438EF500495014 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972242C438EF500495014 /* Router.swift */; }; 1D3972292C438F1C00495014 /* AddRecipeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972282C438F1C00495014 /* AddRecipeInteractor.swift */; }; 1D39722B2C438FD300495014 /* SaveRecipeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39722A2C438FD300495014 /* SaveRecipeUseCase.swift */; }; 1D39722D2C43904800495014 /* AddRecipeRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39722C2C43904800495014 /* AddRecipeRepository.swift */; }; @@ -109,6 +117,10 @@ 1D1283A92C15EBCF00C5A870 /* SearchFeedUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchFeedUseCase.swift; sourceTree = ""; }; 1D1283AB2C15EBE600C5A870 /* FetchFeedListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchFeedListUseCase.swift; sourceTree = ""; }; 1D1283C92C16D9C600C5A870 /* RecipeFetchService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeFetchService.swift; sourceTree = ""; }; + 1D166CFB2C49666B00A50963 /* AddRecipeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRecipeViewModel.swift; sourceTree = ""; }; + 1D166D002C4ACD9F00A50963 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; + 1D166D012C4ACD9F00A50963 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; + 1D166D022C4ACD9F00A50963 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; 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 = ""; }; 1D2C16E92BE532B700C04508 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -131,9 +143,6 @@ 1D3972192C438EDD00495014 /* SelectImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectImageCell.swift; sourceTree = ""; }; 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeViewController.swift; sourceTree = ""; }; 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeUploadImgaeCell.swift; sourceTree = ""; }; - 1D3972222C438EF500495014 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; - 1D3972232C438EF500495014 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; - 1D3972242C438EF500495014 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; 1D3972282C438F1C00495014 /* AddRecipeInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeInteractor.swift; sourceTree = ""; }; 1D39722A2C438FD300495014 /* SaveRecipeUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SaveRecipeUseCase.swift; sourceTree = ""; }; 1D39722C2C43904800495014 /* AddRecipeRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRepository.swift; sourceTree = ""; }; @@ -254,6 +263,23 @@ path = Network; sourceTree = ""; }; + 1D166CFE2C49668500A50963 /* View */ = { + isa = PBXGroup; + children = ( + ); + path = View; + sourceTree = ""; + }; + 1D166CFF2C4ACD9F00A50963 /* Router */ = { + isa = PBXGroup; + children = ( + 1D166D002C4ACD9F00A50963 /* AddRecipeRouter.swift */, + 1D166D012C4ACD9F00A50963 /* RecipeListRouter.swift */, + 1D166D022C4ACD9F00A50963 /* Router.swift */, + ); + path = Router; + sourceTree = ""; + }; 1D2C16D92BE532B700C04508 = { isa = PBXGroup; children = ( @@ -279,7 +305,7 @@ 1D2C16E42BE532B700C04508 /* HomeCafeRecipes */ = { isa = PBXGroup; children = ( - 1D3972212C438EF500495014 /* Router */, + 1D166CFF2C4ACD9F00A50963 /* Router */, 1D39720B2C438D8300495014 /* Utilities */, 1DF829B52C2A7C8600C337FC /* Extensions */, 1DF829B22C2A7A0B00C337FC /* Resources */, @@ -338,20 +364,12 @@ 1D39721A2C438EDD00495014 /* AddRecipeViewController.swift */, 1D39721B2C438EDD00495014 /* RecipeUploadImgaeCell.swift */, 1D39724B2C43C35700495014 /* AddRecipeView.swift */, + 1D166CFB2C49666B00A50963 /* AddRecipeViewModel.swift */, + 1D166CFE2C49668500A50963 /* View */, ); path = UploadRecipe; sourceTree = ""; }; - 1D3972212C438EF500495014 /* Router */ = { - isa = PBXGroup; - children = ( - 1D3972222C438EF500495014 /* AddRecipeRouter.swift */, - 1D3972232C438EF500495014 /* RecipeListRouter.swift */, - 1D3972242C438EF500495014 /* Router.swift */, - ); - path = Router; - sourceTree = ""; - }; 1D4741CB2C1B4F8D009381CE /* DTO */ = { isa = PBXGroup; children = ( @@ -624,6 +642,7 @@ 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */, 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */, 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, + 1D166CFC2C49666B00A50963 /* AddRecipeViewModel.swift in Sources */, 1D2C6F652C2446D8004BB54E /* MainTabBarController.swift in Sources */, 1D39721D2C438EDD00495014 /* SelectImageCell.swift in Sources */, 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */, @@ -632,8 +651,8 @@ 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */, 1D1283AC2C15EBE600C5A870 /* FetchFeedListUseCase.swift in Sources */, 1DF829B72C2A7CDC00C337FC /* UIImageViewImageLoading.swift in Sources */, + 1D166D072C4ACD9F00A50963 /* Router.swift in Sources */, 1D39722F2C43906300495014 /* RecipePostService.swift in Sources */, - 1D3972252C438EF500495014 /* AddRecipeRouter.swift in Sources */, 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */, 1D1283A42C15EA8100C5A870 /* RecipeType.swift in Sources */, 1D3972312C43907300495014 /* RecipeUploadDTO.swift in Sources */, @@ -641,6 +660,7 @@ 1D4741D22C1B4F8D009381CE /* RecipeDTO.swift in Sources */, 1DE19EC02C1B422F0031804A /* RecipeDetailView.swift in Sources */, 1D1283AA2C15EBCF00C5A870 /* SearchFeedUseCase.swift in Sources */, + 1D166D052C4ACD9F00A50963 /* RecipeListRouter.swift in Sources */, 1D39722D2C43904800495014 /* AddRecipeRepository.swift in Sources */, 1D3972142C438E9C00495014 /* User.swift in Sources */, 1D39724C2C43C35700495014 /* AddRecipeView.swift in Sources */, @@ -656,12 +676,11 @@ 1D3972112C438E6A00495014 /* RecipeListItemViewModel.swift in Sources */, 1D3972352C4390E200495014 /* RecipeUploadResponseDTO.swift in Sources */, 1DE19EC62C1B422F0031804A /* RecipeListCell.swift in Sources */, - 1D3972272C438EF500495014 /* Router.swift in Sources */, 1DF829B92C2A818D00C337FC /* String+Validation.swift in Sources */, 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */, + 1D166D032C4ACD9F00A50963 /* AddRecipeRouter.swift in Sources */, 1DE19EBF2C1B422F0031804A /* RecipeDetailViewModel.swift in Sources */, 1D39720F2C438E1F00495014 /* RecipeListMapper.swift in Sources */, - 1D3972262C438EF500495014 /* RecipeListRouter.swift in Sources */, 1D1283A22C15E94300C5A870 /* Recipe.swift in Sources */, 1D3972152C438E9C00495014 /* Comment.swift in Sources */, 1D39721E2C438EDD00495014 /* AddRecipeViewController.swift in Sources */, @@ -678,14 +697,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1D166D062C4ACD9F00A50963 /* RecipeListRouter.swift in Sources */, + 1D166CFD2C49666B00A50963 /* AddRecipeViewModel.swift in Sources */, 1D6958DF2C3D5E35008604B3 /* NetworkService.swift in Sources */, + 1D166D042C4ACD9F00A50963 /* AddRecipeRouter.swift in Sources */, + 1D166D0A2C4AD3B600A50963 /* RecipeUploadImgaeCell.swift in Sources */, 1D6958DC2C3D5E20008604B3 /* RecipeDetailRepository.swift in Sources */, 1D6958E12C3D5E44008604B3 /* RecipeDetailDTO.swift in Sources */, + 1D166D082C4ACD9F00A50963 /* Router.swift in Sources */, 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */, 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */, 1D6958DE2C3D5E2C008604B3 /* RecipeType.swift in Sources */, + 1D166D0B2C4AD3B600A50963 /* SelectImageCell.swift in Sources */, 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */, 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */, + 1D166D092C4AD3B600A50963 /* AddRecipeViewController.swift in Sources */, 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */, 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */, 1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */, diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift index d011d03..803151c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeView.swift @@ -175,11 +175,11 @@ final class AddRecipeView: UIView { collectionView.reloadData() } - func getTitleText() -> String? { - return titleTextField.text + var titleText: String { + return titleTextField.text ?? "" } - func getDescriptionText() -> String? { + var descriptionText: String { return descriptionTextView.text } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index c5fe316..30f41cb 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -145,8 +145,8 @@ extension AddRecipeViewController: AddRecipeViewDelegate { } func didTapSubmitButton() { - let title = contentView.getTitleText() ?? "" - let description = contentView.getDescriptionText() ?? "" + let title = contentView.titleText + let description = contentView.descriptionText addRecipeInteractor.updateTitle(title) addRecipeInteractor.updateDescription(description) saveRecipeToServer() From 42550855fa967d230f3b26caca42607cd5db2739 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 02:40:10 +0900 Subject: [PATCH 30/51] =?UTF-8?q?Fix:=20setDelegate=20=EC=82=AD=EC=A0=9C,?= =?UTF-8?q?=20=EB=9D=BC=EC=9A=B0=ED=84=B0=EC=97=90=EC=84=9C=20delegate=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=ED=95=98=EB=8A=94=20=ED=98=95=EC=8B=9D?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes.xcodeproj/project.pbxproj | 46 +++++++++++-------- .../Interactor/RecipeDetailInteractor.swift | 9 +--- .../Interactor/RecipeListInteractor.swift | 9 +--- .../View/RecipeDetailViewController.swift | 3 +- .../View/RecipeListViewController.swift | 3 +- 5 files changed, 32 insertions(+), 38 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj index 8d2bc08..509dc8c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj +++ b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj @@ -16,6 +16,12 @@ 1D1283B42C16983900C5A870 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 1D1283B32C16983900C5A870 /* RxSwift */; }; 1D1283B62C16984E00C5A870 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 1D1283B52C16984E00C5A870 /* RxCocoa */; }; 1D1283CA2C16D9C600C5A870 /* RecipeFetchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283C92C16D9C600C5A870 /* RecipeFetchService.swift */; }; + 1D166D132C4AD9A700A50963 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D102C4AD9A700A50963 /* AddRecipeRouter.swift */; }; + 1D166D142C4AD9A700A50963 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D102C4AD9A700A50963 /* AddRecipeRouter.swift */; }; + 1D166D152C4AD9A700A50963 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D112C4AD9A700A50963 /* RecipeListRouter.swift */; }; + 1D166D162C4AD9A700A50963 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D112C4AD9A700A50963 /* RecipeListRouter.swift */; }; + 1D166D172C4AD9A700A50963 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D122C4AD9A700A50963 /* Router.swift */; }; + 1D166D182C4AD9A700A50963 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D122C4AD9A700A50963 /* Router.swift */; }; 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E52BE532B700C04508 /* AppDelegate.swift */; }; 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E92BE532B700C04508 /* ViewController.swift */; }; 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */; }; @@ -23,9 +29,6 @@ 1D2C17092BE532B800C04508 /* HomeCafeRecipesUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C17082BE532B800C04508 /* HomeCafeRecipesUITestsLaunchTests.swift */; }; 1D2C6F652C2446D8004BB54E /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */; }; 1D2C6F6C2C27051D004BB54E /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */; }; - 1D3972522C44167A00495014 /* AddRecipeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39724F2C44167A00495014 /* AddRecipeRouter.swift */; }; - 1D3972532C44167A00495014 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972502C44167A00495014 /* RecipeListRouter.swift */; }; - 1D3972542C44167A00495014 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972512C44167A00495014 /* Router.swift */; }; 1D3972572C44168E00495014 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972562C44168E00495014 /* DateFormatter+Extensions.swift */; }; 1D39725A2C4416A300495014 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972582C4416A300495014 /* User.swift */; }; 1D39725B2C4416A300495014 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972592C4416A300495014 /* Comment.swift */; }; @@ -97,6 +100,9 @@ 1D1283A92C15EBCF00C5A870 /* SearchFeedUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchFeedUseCase.swift; sourceTree = ""; }; 1D1283AB2C15EBE600C5A870 /* FetchFeedListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchFeedListUseCase.swift; sourceTree = ""; }; 1D1283C92C16D9C600C5A870 /* RecipeFetchService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeFetchService.swift; sourceTree = ""; }; + 1D166D102C4AD9A700A50963 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; + 1D166D112C4AD9A700A50963 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; + 1D166D122C4AD9A700A50963 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; 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 = ""; }; 1D2C16E92BE532B700C04508 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -110,9 +116,6 @@ 1D2C17082BE532B800C04508 /* HomeCafeRecipesUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCafeRecipesUITestsLaunchTests.swift; sourceTree = ""; }; 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; - 1D39724F2C44167A00495014 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; - 1D3972502C44167A00495014 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; - 1D3972512C44167A00495014 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; 1D3972562C44168E00495014 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; 1D3972582C4416A300495014 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 1D3972592C4416A300495014 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; @@ -228,6 +231,16 @@ path = Network; sourceTree = ""; }; + 1D166D0F2C4AD9A700A50963 /* Router */ = { + isa = PBXGroup; + children = ( + 1D166D102C4AD9A700A50963 /* AddRecipeRouter.swift */, + 1D166D112C4AD9A700A50963 /* RecipeListRouter.swift */, + 1D166D122C4AD9A700A50963 /* Router.swift */, + ); + path = Router; + sourceTree = ""; + }; 1D2C16D92BE532B700C04508 = { isa = PBXGroup; children = ( @@ -253,8 +266,8 @@ 1D2C16E42BE532B700C04508 /* HomeCafeRecipes */ = { isa = PBXGroup; children = ( + 1D166D0F2C4AD9A700A50963 /* Router */, 1D3972552C44168E00495014 /* Utilities */, - 1D39724E2C44167A00495014 /* Router */, 1DF829B52C2A7C8600C337FC /* Extensions */, 1DF829B22C2A7A0B00C337FC /* Resources */, 1DE19EB22C1B422F0031804A /* Presentation */, @@ -297,16 +310,6 @@ path = Tabbar; sourceTree = ""; }; - 1D39724E2C44167A00495014 /* Router */ = { - isa = PBXGroup; - children = ( - 1D39724F2C44167A00495014 /* AddRecipeRouter.swift */, - 1D3972502C44167A00495014 /* RecipeListRouter.swift */, - 1D3972512C44167A00495014 /* Router.swift */, - ); - path = Router; - sourceTree = ""; - }; 1D3972552C44168E00495014 /* Utilities */ = { isa = PBXGroup; children = ( @@ -575,11 +578,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1D3972532C44167A00495014 /* RecipeListRouter.swift in Sources */, 1D39725B2C4416A300495014 /* Comment.swift in Sources */, 1D439E9E2C2C598A008530A5 /* RecipeDetailRepository.swift in Sources */, 1D2C6F6C2C27051D004BB54E /* CustomNavigationBar.swift in Sources */, - 1D3972522C44167A00495014 /* AddRecipeRouter.swift in Sources */, 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */, 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */, 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, @@ -589,9 +590,9 @@ 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */, 1D3972662C44171100495014 /* RecipeListItemViewModel.swift in Sources */, 1DE19EB12C1B42200031804A /* NetworkService.swift in Sources */, + 1D166D132C4AD9A700A50963 /* AddRecipeRouter.swift in Sources */, 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */, 1D1283AC2C15EBE600C5A870 /* FetchFeedListUseCase.swift in Sources */, - 1D3972542C44167A00495014 /* Router.swift in Sources */, 1DF829B72C2A7CDC00C337FC /* UIImageViewImageLoading.swift in Sources */, 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */, 1D1283A42C15EA8100C5A870 /* RecipeType.swift in Sources */, @@ -606,10 +607,12 @@ 1D73686E2C305757000EF904 /* RecipeDetailDTO.swift in Sources */, 1D39725F2C4416CE00495014 /* RecipeListMapper.swift in Sources */, 1D4741D72C1B4FF4009381CE /* RecipeListInteractor.swift in Sources */, + 1D166D172C4AD9A700A50963 /* Router.swift in Sources */, 1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */, 1D3972642C4416F500495014 /* UserDTO.swift in Sources */, 1D4741D12C1B4F8D009381CE /* RecipeImageDTO.swift in Sources */, 1DE19EA72C1B420A0031804A /* FeedListRepository.swift in Sources */, + 1D166D152C4AD9A700A50963 /* RecipeListRouter.swift in Sources */, 1DE19EC62C1B422F0031804A /* RecipeListCell.swift in Sources */, 1DF829B92C2A818D00C337FC /* String+Validation.swift in Sources */, 1DE19EC42C1B422F0031804A /* RecipeListViewController.swift in Sources */, @@ -632,14 +635,17 @@ 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */, 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */, 1D6958DE2C3D5E2C008604B3 /* RecipeType.swift in Sources */, + 1D166D162C4AD9A700A50963 /* RecipeListRouter.swift in Sources */, 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */, 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */, 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */, + 1D166D182C4AD9A700A50963 /* Router.swift in Sources */, 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */, 1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */, 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */, 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */, 1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */, + 1D166D142C4AD9A700A50963 /* AddRecipeRouter.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift index 931ce56..ee47406 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift @@ -14,8 +14,7 @@ protocol RecipeDetailInteractorDelegate: AnyObject { } protocol RecipeDetailInteractor { - func viewDidLoad() - func setDelegate(_ delegate: RecipeDetailInteractorDelegate) + func viewDidLoad() } class RecipeDetailInteractorImpl: RecipeDetailInteractor { @@ -32,11 +31,7 @@ class RecipeDetailInteractorImpl: RecipeDetailInteractor { self.fetchRecipeDetailUseCase = fetchRecipeDetailUseCase self.recipeID = recipeID } - - func setDelegate(_ delegate: RecipeDetailInteractorDelegate) { - self.delegate = delegate - } - + func viewDidLoad() { fetchRecipeDetail() } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift index 375db4f..8ee8f01 100755 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift @@ -20,7 +20,6 @@ protocol RecipeListInteractor { func didSelectItem(ID: Int) func searchRecipes(with query: String) func resetSearch() - func setDelegate(_ delegate: RecipeListInteractorDelegate) } class RecipeListInteractorImpl: RecipeListInteractor { @@ -28,7 +27,7 @@ class RecipeListInteractorImpl: RecipeListInteractor { private let disposeBag = DisposeBag() private let fetchFeedListUseCase: FetchFeedListUseCase private let searchFeedListUseCase: SearchFeedListUseCase - private weak var delegate: RecipeListInteractorDelegate? + weak var delegate: RecipeListInteractorDelegate? private var currentPage: Int = 1 private var isFetching = false @@ -42,11 +41,7 @@ class RecipeListInteractorImpl: RecipeListInteractor { self.fetchFeedListUseCase = fetchFeedListUseCase self.searchFeedListUseCase = searchFeedListUseCase } - - func setDelegate(_ delegate: RecipeListInteractorDelegate) { - self.delegate = delegate - } - + func viewDidLoad() { fetchRecipes() } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift index 75dc4e3..b6d7256 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift @@ -20,8 +20,7 @@ final class RecipeDetailViewController: UIViewController { init(interactor: RecipeDetailInteractor) { self.interactor = interactor - super.init(nibName: nil, bundle: nil) - self.interactor.setDelegate(self) + super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift index 65e19f2..ac37e81 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift @@ -19,8 +19,7 @@ final class RecipeListViewController: UIViewController { init(interactor: RecipeListInteractor, router: RecipeListRouterProtocol) { self.interactor = interactor self.router = router - super.init(nibName: nil, bundle: nil) - self.interactor.setDelegate(self) + super.init(nibName: nil, bundle: nil) recipeListView.delegate = self } From 9047d564d10fc5127f055e3da29e9aee476f7c27 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 16:12:55 +0900 Subject: [PATCH 31/51] =?UTF-8?q?Fix:=20numberOfImages=EB=A1=9C=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/UploadRecipe/AddRecipeViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index 30f41cb..b989451 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -141,7 +141,7 @@ extension AddRecipeViewController: AddRecipeViewDelegate { func didTapDeleteButton(at index: Int) { addRecipeInteractor.removeImage(at: index) updateaddRecipeViewModel() - contentView.updateImageView(count: addRecipeViewModel.images.count) + contentView.updateImageView(count: numberOfImages()) } func didTapSubmitButton() { From baa8ac8fa466aea53226d568e38a7a126fec5406 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 16:50:29 +0900 Subject: [PATCH 32/51] =?UTF-8?q?Feat:=20Router=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes/Router/Router.swift | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift b/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift new file mode 100644 index 0000000..d092968 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift @@ -0,0 +1,93 @@ +// +// Router.swift +// HomeCafeRecipes +// +// Created by 김건호 on 7/9/24. +// + +import UIKit + +public typealias NavigationBackClosure = () -> Void + +public protocol Drawable { + var viewController: UIViewController? { get } +} + +public protocol RouterProtocol { + func push ( + _ drawable: Drawable, + from viewController: UIViewController, + isAnimated: Bool, + onNavigateBack closure: NavigationBackClosure? + ) +} + +class Router: NSObject, RouterProtocol { + private var closures: [String: NavigationBackClosure] = [:] + + func push( + _ drawable: Drawable, + from viewController: UIViewController, + isAnimated: Bool, + onNavigateBack closure: NavigationBackClosure? + ) { + guard let targetViewController = drawable.viewController else { + return + } + + if let closure = closure { + closures.updateValue(closure, forKey: targetViewController.description) + } + viewController.navigationController?.pushViewController(targetViewController, animated: isAnimated) + } + + private func executeClosure(_ viewController: UIViewController) { + guard let closure = closures.removeValue(forKey: viewController.description) else { return } + closure() + } +} + +extension Router { + func createRecipeListDependencies() -> RecipeListViewController { + let baseNetworkService = BaseNetworkService() + let recipeFetchService = RecipeFetchServiceImpl(networkService: baseNetworkService) + let feedListRepository = FeedListRepositoryImpl(networkService: recipeFetchService) + let searchFeedRepository = SearchFeedRepositoryImpl(networkService: recipeFetchService) + let fetchFeedListUseCase = FetchFeedListUseCaseImpl(repository: feedListRepository) + let searchFeedListUseCase = SearchFeedListUseCaseImpl(repository: searchFeedRepository) + let recipeListInteractor = RecipeListInteractorImpl( + fetchFeedListUseCase: fetchFeedListUseCase, + searchFeedListUseCase: searchFeedListUseCase + ) + let recipeListRouter = RecipeListRouterImpl(router: self) + let recipeListVC = RecipeListViewController( + interactor: recipeListInteractor, + router: recipeListRouter + ) + recipeListInteractor.delegate = recipeListVC + return recipeListVC + } + + func createAddRecipeDependencies(recipeType: RecipeType) -> AddRecipeViewController { + let baseNetworkService = BaseNetworkService() + let recipePostService = RecipePostServiceImpl(networkService: baseNetworkService) + let saveRepository = AddRecipeRepositoryImpl(recipePostService: recipePostService) + let saveRecipeUseCase = SaveRecipeUseCaseImpl(repository: saveRepository) + let addRecipeInteractor = AddRecipeInteractorImpl(saveRecipeUseCase: saveRecipeUseCase) + let addRecipeVC = AddRecipeViewController(recipeType: recipeType, addRecipeInteractor: addRecipeInteractor) + return addRecipeVC + } + + func createRecipeDetailDependencies(recipeID: Int) -> RecipeDetailViewController { + let baseNetworkService = BaseNetworkService() + let recipeDetailRepository = RecipeDetailRepositoryImpl(networkService: baseNetworkService) + let fetchRecipeDetailUseCase = FetchRecipeDetailUseCaseImpl(repository: recipeDetailRepository) + let detailInteractor = RecipeDetailInteractorImpl( + fetchRecipeDetailUseCase: fetchRecipeDetailUseCase, + recipeID: recipeID + ) + let detailVC = RecipeDetailViewController(interactor: detailInteractor) + detailInteractor.delegate = detailVC + return detailVC + } +} From 6f1738b309d1a3ab3d71f2e5070621839d75c256 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 16:53:00 +0900 Subject: [PATCH 33/51] =?UTF-8?q?Fix:=20RecipeListRouter=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Router/RecipeListRouter.swift | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift b/HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift new file mode 100644 index 0000000..4e0c7a3 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift @@ -0,0 +1,25 @@ +// +// RecipeListRouter.swift +// HomeCafeRecipes +// +// Created by 김건호 on 7/9/24. +// + +import UIKit + +protocol RecipeListRouter { + func navigateToRecipeDetail(from viewController: UIViewController, recipeID: Int) +} + +class RecipeListRouterImpl: RecipeListRouter { + private let router: Router + + init(router: Router) { + self.router = router + } + + func navigateToRecipeDetail(from viewController: UIViewController, recipeID: Int) { + let detailVC = router.createRecipeDetailDependencies(recipeID: recipeID) + router.push(detailVC, from: viewController, isAnimated: true, onNavigateBack: nil) + } +} From 5adae124d8446f60976bfa54b79ed3508d78940b Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 21 Jul 2024 12:03:34 +0900 Subject: [PATCH 34/51] =?UTF-8?q?Fix:=20Recipe=EC=97=90=20dummy=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes/Domain/Entities/Recipe.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift index 06e9520..d474d1b 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift @@ -18,3 +18,10 @@ struct Recipe { let likeCount: Int let createdAt: Date } + +extension Recipe { + + static func dummy() -> Recipe { + .init(id: 1, type: .coffee, name: "", description: "", writer: .init(id: 1, profileImage: "", nickname: "", createdAt: Date()), imageUrls: [], isLikedByCurrentUser: false, likeCount: 0, createdAt: Date()) + } +} From 0518ea3727b8b24ccc2e2a0203d9f9a50dff9f04 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 21 Jul 2024 01:51:23 +0900 Subject: [PATCH 35/51] =?UTF-8?q?Feat:=20RecipeDetailInteractorTests=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RecipeDeatilInteractorTests.swift | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift new file mode 100644 index 0000000..3a9f24c --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift @@ -0,0 +1,115 @@ +// +// RecipeDeatilInteractorTests.swift +// HomeCafeRecipesTests +// +// Created by 김건호 on 7/9/24. +// + +import Foundation +import XCTest + +import RxSwift + +@testable +import HomeCafeRecipes + +final class RecipeDetailInteractorTests: XCTestCase { + var fetchRecipeDetailUsecase: FetchRecipeDetailUseCaseMock! + var delegate: RecipeDetailInteractorDelegateMock! + + class FetchRecipeDetailUseCaseMock: FetchRecipeDetailUseCase { + var executeCallCount: Int = 0 + var executeStub: Single> = .just(.failure(NSError())) + func execute(recipeID: Int) -> Single> { + executeCallCount += 1 + return executeStub + } + } + + class RecipeDetailInteractorDelegateMock: RecipeDetailInteractorDelegate { + var fetchedCallCount: Int = 0 + var fetchedRecipeResult: Result? + func fetchedRecipe(result: Result) { + fetchedCallCount += 1 + fetchedRecipeResult = result + } + } + + func createInteractor(recipeID: Int = 0) -> RecipeDetailInteractor { + let interactor = RecipeDetailInteractorImpl( + fetchRecipeDetailUseCase: fetchRecipeDetailUsecase, + recipeID: recipeID + ) + + interactor.delegate = delegate + return interactor + } + + override func setUpWithError() throws { + fetchRecipeDetailUsecase = .init() + delegate = .init() + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } +} + +// MARK: viewDidLoad + +extension RecipeDetailInteractorTests { + + func test_화면이_로드될때_FetchRecipeDetailUsecase를_실행합니다() { + // given + let interactor = createInteractor() + + // when + interactor.viewDidLoad() + + // then + XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1) + } + + func test_FetchRecipeDetailUsecase의_성공응답이오면_Delegate로_성공을_전달합니다() { + // given + let interactor = createInteractor() + let recipe = Recipe.dummy() + fetchRecipeDetailUsecase.executeStub = .just(.success(recipe)) + + // when + interactor.viewDidLoad() + + // then + XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1) + XCTAssertEqual(self.delegate.fetchedCallCount, 1) + + if case .success(let fetchedRecipe)? = self.delegate.fetchedRecipeResult { + XCTAssertEqual(fetchedRecipe.id, recipe.id) + } else { + XCTFail("Expected success but got failure or nil") + } + } + + func test_FetchRecipeDetailUsecase의_실패응답이오면_Delegate로_실패를_전달합니다() { + + // given + let interactor = createInteractor() + let error = NSError(domain: "TestError", code: -1) + fetchRecipeDetailUsecase.executeStub = .just(.failure(error)) + + // when + interactor.viewDidLoad() + + // then + XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1) + XCTAssertEqual(self.delegate.fetchedCallCount, 1) + + if case .failure(let fetchedError as NSError) = self.delegate.fetchedRecipeResult { + XCTAssertEqual(fetchedError.domain, error.domain) + XCTAssertEqual(fetchedError.code, error.code) + } else { + XCTFail("Expected success but got failure or nil") + } + + } +} From 93bd4673c06f25ffd8b5dd9ed1c312909a31133a Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 21 Jul 2024 01:52:04 +0900 Subject: [PATCH 36/51] =?UTF-8?q?Feat:=20FetchRecipeDetailUseCaseTests=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes.xcodeproj/project.pbxproj | 70 ++++++++-- .../FetchRecipeDetailUseCaseTests.swift | 126 ++++++++++++++++++ 2 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift diff --git a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj index 509dc8c..635ab13 100644 --- a/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj +++ b/HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj @@ -22,6 +22,34 @@ 1D166D162C4AD9A700A50963 /* RecipeListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D112C4AD9A700A50963 /* RecipeListRouter.swift */; }; 1D166D172C4AD9A700A50963 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D122C4AD9A700A50963 /* Router.swift */; }; 1D166D182C4AD9A700A50963 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166D122C4AD9A700A50963 /* Router.swift */; }; + 1D166DC12C4C207F00A50963 /* RecipeDeatilInteractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166DBF2C4C207E00A50963 /* RecipeDeatilInteractorTests.swift */; }; + 1D166DC22C4C207F00A50963 /* FetchRecipeDetailUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D166DC02C4C207E00A50963 /* FetchRecipeDetailUseCaseTests.swift */; }; + 1D166DC32C4C212A00A50963 /* UserDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972632C4416F400495014 /* UserDTO.swift */; }; + 1D166DC42C4C212F00A50963 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972582C4416A300495014 /* User.swift */; }; + 1D166DC52C4C213700A50963 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */; }; + 1D166DC62C4C213700A50963 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */; }; + 1D166DC72C4C213C00A50963 /* RecipeListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBC2C1B422F0031804A /* RecipeListViewController.swift */; }; + 1D166DC82C4C214700A50963 /* RecipeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB62C1B422F0031804A /* RecipeDetailView.swift */; }; + 1D166DC92C4C214B00A50963 /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F6B2C27051D004BB54E /* CustomNavigationBar.swift */; }; + 1D166DCA2C4C215C00A50963 /* RecipeListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */; }; + 1D166DCB2C4C216800A50963 /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972562C44168E00495014 /* DateFormatter+Extensions.swift */; }; + 1D166DCC2C4C216D00A50963 /* RecipeFetchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283C92C16D9C600C5A870 /* RecipeFetchService.swift */; }; + 1D166DCD2C4C217E00A50963 /* SearchFeedUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283A92C15EBCF00C5A870 /* SearchFeedUseCase.swift */; }; + 1D166DCE2C4C218700A50963 /* FetchFeedListUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283AB2C15EBE600C5A870 /* FetchFeedListUseCase.swift */; }; + 1D166DCF2C4C21A400A50963 /* SearchFeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */; }; + 1D166DD02C4C21A900A50963 /* FeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */; }; + 1D166DD12C4C21BF00A50963 /* String+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B82C2A818D00C337FC /* String+Validation.swift */; }; + 1D166DD22C4C21C200A50963 /* UIImageViewImageLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B62C2A7CDC00C337FC /* UIImageViewImageLoading.swift */; }; + 1D166DD32C4C21D700A50963 /* RecipeListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D39725D2C4416CE00495014 /* RecipeListMapper.swift */; }; + 1D166DD42C4C21DB00A50963 /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C6F642C2446D8004BB54E /* MainTabBarController.swift */; }; + 1D166DD52C4C21E600A50963 /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBB2C1B422F0031804A /* SearchBar.swift */; }; + 1D166DD62C4C21EC00A50963 /* RecipeListItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3972652C44171100495014 /* RecipeListItemViewModel.swift */; }; + 1D166DD72C4C21F000A50963 /* RecipeListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBE2C1B422F0031804A /* RecipeListCell.swift */; }; + 1D166DD82C4C220000A50963 /* RecipeListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EBD2C1B422F0031804A /* RecipeListView.swift */; }; + 1D166DD92C4C220A00A50963 /* RecipeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EB42C1B422F0031804A /* RecipeDetailViewModel.swift */; }; + 1D166DDA2C4C220E00A50963 /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF829B32C2A7A7D00C337FC /* Fonts.swift */; }; + 1D166DDB2C4C221A00A50963 /* RecipePageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CE2C1B4F8D009381CE /* RecipePageDTO.swift */; }; + 1D166DDC2C4C222B00A50963 /* RecipeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CD2C1B4F8D009381CE /* RecipeDTO.swift */; }; 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E52BE532B700C04508 /* AppDelegate.swift */; }; 1D2C16EA2BE532B700C04508 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16E92BE532B700C04508 /* ViewController.swift */; }; 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */; }; @@ -46,7 +74,6 @@ 1D4741D72C1B4FF4009381CE /* RecipeListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */; }; 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */; }; 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */; }; - 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */; }; 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439EA12C2C6997008530A5 /* RecipeDetailInteractor.swift */; }; 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D439E9B2C2C58DD008530A5 /* FetchRecipeDetailUseCase.swift */; }; 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1283A12C15E94300C5A870 /* Recipe.swift */; }; @@ -59,8 +86,6 @@ 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */; }; 1D73686E2C305757000EF904 /* RecipeDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */; }; 1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */; }; - 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */; }; - 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */; }; 1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */; }; 1DE19EA72C1B420A0031804A /* FeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */; }; 1DE19EA82C1B420A0031804A /* SearchFeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA62C1B420A0031804A /* SearchFeedListRepository.swift */; }; @@ -103,6 +128,8 @@ 1D166D102C4AD9A700A50963 /* AddRecipeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddRecipeRouter.swift; sourceTree = ""; }; 1D166D112C4AD9A700A50963 /* RecipeListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListRouter.swift; sourceTree = ""; }; 1D166D122C4AD9A700A50963 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; + 1D166DBF2C4C207E00A50963 /* RecipeDeatilInteractorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeDeatilInteractorTests.swift; sourceTree = ""; }; + 1D166DC02C4C207E00A50963 /* FetchRecipeDetailUseCaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchRecipeDetailUseCaseTests.swift; sourceTree = ""; }; 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 = ""; }; 1D2C16E92BE532B700C04508 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -132,10 +159,8 @@ 1D4741CF2C1B4F8D009381CE /* NetworkResponseDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkResponseDTO.swift; sourceTree = ""; }; 1D4741D62C1B4FF4009381CE /* RecipeListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipeListInteractor.swift; sourceTree = ""; }; 1D60CC3C2C3E4F1600D08FA3 /* APIConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIConfig.swift; sourceTree = ""; }; - 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDeatilInteractorTests.swift; sourceTree = ""; }; 1D73686D2C305757000EF904 /* RecipeDetailDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailDTO.swift; sourceTree = ""; }; 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailError.swift; sourceTree = ""; }; - 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRecipeTests.swift; sourceTree = ""; }; 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = ""; }; 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedListRepository.swift; sourceTree = ""; }; @@ -286,9 +311,9 @@ 1D2C16FB2BE532B800C04508 /* HomeCafeRecipesTests */ = { isa = PBXGroup; children = ( + 1D166DC02C4C207E00A50963 /* FetchRecipeDetailUseCaseTests.swift */, + 1D166DBF2C4C207E00A50963 /* RecipeDeatilInteractorTests.swift */, 1D2C16FC2BE532B800C04508 /* HomeCafeRecipesTests.swift */, - 1DDE90CE2C3590C40078DFD3 /* AddRecipeTests.swift */, - 1D6958D72C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift */, ); path = HomeCafeRecipesTests; sourceTree = ""; @@ -585,7 +610,6 @@ 1DE19EC52C1B422F0031804A /* RecipeListView.swift in Sources */, 1D4741D32C1B4F8D009381CE /* RecipePageDTO.swift in Sources */, 1D2C6F652C2446D8004BB54E /* MainTabBarController.swift in Sources */, - 1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */, 1D3972622C4416E400495014 /* UIView+Extensions.swift in Sources */, 1D2C16E62BE532B700C04508 /* AppDelegate.swift in Sources */, 1D3972662C44171100495014 /* RecipeListItemViewModel.swift in Sources */, @@ -597,6 +621,7 @@ 1D60CC3D2C3E4F1600D08FA3 /* APIConfig.swift in Sources */, 1D1283A42C15EA8100C5A870 /* RecipeType.swift in Sources */, 1DF829B42C2A7A7D00C337FC /* Fonts.swift in Sources */, + 1D166DC52C4C213700A50963 /* RecipeDetailViewController.swift in Sources */, 1D39725A2C4416A300495014 /* User.swift in Sources */, 1D4741D22C1B4F8D009381CE /* RecipeDTO.swift in Sources */, 1DE19EC02C1B422F0031804A /* RecipeDetailView.swift in Sources */, @@ -630,22 +655,47 @@ buildActionMask = 2147483647; files = ( 1D6958DF2C3D5E35008604B3 /* NetworkService.swift in Sources */, + 1D166DCD2C4C217E00A50963 /* SearchFeedUseCase.swift in Sources */, + 1D166DDB2C4C221A00A50963 /* RecipePageDTO.swift in Sources */, 1D6958DC2C3D5E20008604B3 /* RecipeDetailRepository.swift in Sources */, + 1D166DD62C4C21EC00A50963 /* RecipeListItemViewModel.swift in Sources */, 1D6958E12C3D5E44008604B3 /* RecipeDetailDTO.swift in Sources */, - 1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */, 1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */, + 1D166DD02C4C21A900A50963 /* FeedListRepository.swift in Sources */, + 1D166DCA2C4C215C00A50963 /* RecipeListInteractor.swift in Sources */, + 1D166DD52C4C21E600A50963 /* SearchBar.swift in Sources */, 1D6958DE2C3D5E2C008604B3 /* RecipeType.swift in Sources */, + 1D166DC72C4C213C00A50963 /* RecipeListViewController.swift in Sources */, 1D166D162C4AD9A700A50963 /* RecipeListRouter.swift in Sources */, + 1D166DD32C4C21D700A50963 /* RecipeListMapper.swift in Sources */, + 1D166DCC2C4C216D00A50963 /* RecipeFetchService.swift in Sources */, + 1D166DD92C4C220A00A50963 /* RecipeDetailViewModel.swift in Sources */, + 1D166DC92C4C214B00A50963 /* CustomNavigationBar.swift in Sources */, + 1D166DDA2C4C220E00A50963 /* Fonts.swift in Sources */, + 1D166DC82C4C214700A50963 /* RecipeDetailView.swift in Sources */, + 1D166DC32C4C212A00A50963 /* UserDTO.swift in Sources */, 1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */, + 1D166DDC2C4C222B00A50963 /* RecipeDTO.swift in Sources */, + 1D166DD42C4C21DB00A50963 /* MainTabBarController.swift in Sources */, 1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */, 1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */, 1D166D182C4AD9A700A50963 /* Router.swift in Sources */, 1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */, 1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */, - 1DDE90CF2C3590C40078DFD3 /* AddRecipeTests.swift in Sources */, + 1D166DD82C4C220000A50963 /* RecipeListView.swift in Sources */, + 1D166DD12C4C21BF00A50963 /* String+Validation.swift in Sources */, + 1D166DD22C4C21C200A50963 /* UIImageViewImageLoading.swift in Sources */, + 1D166DD72C4C21F000A50963 /* RecipeListCell.swift in Sources */, 1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */, + 1D166DCE2C4C218700A50963 /* FetchFeedListUseCase.swift in Sources */, 1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */, + 1D166DCB2C4C216800A50963 /* DateFormatter+Extensions.swift in Sources */, 1D166D142C4AD9A700A50963 /* AddRecipeRouter.swift in Sources */, + 1D166DC12C4C207F00A50963 /* RecipeDeatilInteractorTests.swift in Sources */, + 1D166DC22C4C207F00A50963 /* FetchRecipeDetailUseCaseTests.swift in Sources */, + 1D166DCF2C4C21A400A50963 /* SearchFeedListRepository.swift in Sources */, + 1D166DC62C4C213700A50963 /* RecipeDetailViewController.swift in Sources */, + 1D166DC42C4C212F00A50963 /* User.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift new file mode 100644 index 0000000..8fe1cf5 --- /dev/null +++ b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift @@ -0,0 +1,126 @@ +// +// FetchRecipeDetailUseCaseTests.swift +// HomeCafeRecipesTests +// +// Created by 김건호 on 7/17/24. +// + +import Foundation +import XCTest + +import RxSwift + +@testable +import HomeCafeRecipes + +final class FetchRecipeDetailUseCaseTests: XCTestCase { + + var fetchRecipeDetailRepository: FetchRecipeRepositoryMock! + var disposeBag: DisposeBag! + + class FetchRecipeRepositoryMock: RecipeDetailRepository { + var fetchRecipeDetailCallCount: Int = 0 + var fetchRecipeDetailStub: Single = .just(Recipe.dummy()) + func fetchRecipeDetail(recipeID: Int) -> Single { + fetchRecipeDetailCallCount += 1 + return fetchRecipeDetailStub + } + } + + func createUseCase() -> FetchRecipeDetailUseCase { + let usecase = FetchRecipeDetailUseCaseImpl(repository: fetchRecipeDetailRepository) + return usecase + } + + override func setUpWithError() throws { + fetchRecipeDetailRepository = .init() + disposeBag = .init() + } + + override func tearDownWithError() throws { + } +} + +extension FetchRecipeDetailUseCaseTests { + + func test_execute를_호출하면_1번_RecipeDetailRepository의_fetchRecipeDetail을_호출합니다(){ + + // Given + + let usecase = createUseCase() + fetchRecipeDetailRepository.fetchRecipeDetailStub = .just(Recipe.dummy()) + + // When + + usecase.execute(recipeID: 1) + .subscribe() + .disposed(by: disposeBag) + + // Then + + XCTAssertEqual(fetchRecipeDetailRepository.fetchRecipeDetailCallCount, 1) + } + + func test_RecipeDetailRepository의_성공응답이오면_Recipe를_반환합니다(){ + + // Given + + let usecase = createUseCase() + let recipe = Recipe.dummy() + fetchRecipeDetailRepository.fetchRecipeDetailStub = .just(recipe) + let expectation = self.expectation(description: "Fetch Recipe Success") + + // When + + usecase.execute(recipeID: 1) + .subscribe(onSuccess: { result in + if case .success(let fetchedRecipe) = result { + // Then + + XCTAssertEqual(fetchedRecipe.id, recipe.id) + expectation.fulfill() + } else { + XCTFail("Expected success but got failure") + } + }, onFailure: { error in + XCTFail("Expected success but got error: \(error)") + }) + .disposed(by: disposeBag) + + wait(for: [expectation], timeout: 1.0) + XCTAssertEqual(fetchRecipeDetailRepository.fetchRecipeDetailCallCount, 1) + } + + func test_RecipeDetailRepository의_실패응답이오면_Error를_반환합니다() { + + // Given + + let usecase = createUseCase() + let error = NSError(domain: "TestError", code: -1) + fetchRecipeDetailRepository.fetchRecipeDetailStub = .error(error) + let expectation = self.expectation(description: "Fetch Recipe Failure") + + // When + + usecase.execute(recipeID: 1) + .subscribe(onSuccess: { result in + if case .failure(let receivedError as NSError) = result { + // Then + + XCTAssertEqual(receivedError.domain, error.domain) + XCTAssertEqual(receivedError.code, error.code) + expectation.fulfill() + } else { + XCTFail("Expected failure but got success") + } + }, onFailure: { error in + XCTFail("Expected failure but got error: \(error)") + }) + .disposed(by: disposeBag) + + wait(for: [expectation], timeout: 1.0) + XCTAssertEqual(fetchRecipeDetailRepository.fetchRecipeDetailCallCount, 1) + + } + +} From 396e9bca617b47ccd7be9695283e16612d0c1084 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 18:48:40 +0900 Subject: [PATCH 37/51] =?UTF-8?q?Fix:=20RecipeListViewController,RecipeLis?= =?UTF-8?q?tView=20coordinator=EC=82=AD=EC=A0=9C=20router=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FeedList/View/RecipeListView.swift | 1 - .../FeedList/View/RecipeListViewController.swift | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListView.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListView.swift index 28ab024..e3bac63 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListView.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListView.swift @@ -23,7 +23,6 @@ final class RecipeListView: UIView { private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) private var recipes: [RecipeListItemViewModel] = [] - weak var coordinator: RecipeDetailCoordinatorProtocol? weak var delegate: RecipeListViewDelegate? override init(frame: CGRect) { diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift index 710f217..434158c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift @@ -13,12 +13,14 @@ final class RecipeListViewController: UIViewController { private var recipes: [RecipeListItemViewModel] = [] private let searchBar = SearchBar() private let recipeListView = RecipeListView() - - init(interactor: RecipeListInteractor) { - self.interactor = interactor - super.init(nibName: nil, bundle: nil) + private let recipeListMapper = RecipeListMapper() + private let router: RecipeListRouter + + init(interactor: RecipeListInteractor, router: RecipeListRouter) { self.interactor.setDelegate(self) - + self.interactor = interactor + self.router = router + super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { @@ -90,7 +92,7 @@ extension RecipeListViewController: RecipeListInteractorDelegate { } func showRecipeDetail(ID: Int) { - coordinator.showRecipeDetail(from: self, recipeID: ID) + router.navigateToRecipeDetail(from: self, recipeID: ID) } } From 4213bfc3ded5c1140285d918d0ffe6e14d90cf15 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 18:56:56 +0900 Subject: [PATCH 38/51] =?UTF-8?q?Fix:=20RecipeDetailViewController?= =?UTF-8?q?=EC=97=90=20Drawable=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Feed/View/RecipeDetailViewController.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift index c6ec16d..b7c65ff 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift @@ -64,3 +64,9 @@ extension RecipeDetailViewController: RecipeDetailInteractorDelegate { } } } + +extension RecipeDetailViewController: Drawable { + var viewController: UIViewController? { + return self + } +} From d49fa45c81f994da8278d2db3cc027cfc0949643 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sat, 20 Jul 2024 18:59:32 +0900 Subject: [PATCH 39/51] =?UTF-8?q?Fix:=20MainTabbarController=EC=97=90=20ro?= =?UTF-8?q?uter=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Tabbar/MainTabBarController.swift | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift index e592ca4..ea666a3 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift @@ -11,6 +11,16 @@ class MainTabBarController: UITabBarController, UITabBarControllerDelegate { private let addButton = UIButton(type: .custom) private let buttonSize = CGSize(all: 64.0) + private let router = Router() + + init(router: Router) { + self.router = router + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } override func viewDidLoad() { super.viewDidLoad() @@ -33,23 +43,26 @@ class MainTabBarController: UITabBarController, UITabBarControllerDelegate { } private func setupTabBar() { - let baseneworkServie = BaseNetworkService() - let networkService = RecipeFetchServiceImpl(networkService: baseneworkServie) - let repository = FeedListRepositoryImpl(networkService: networkService) - let searchrepository = SearchFeedRepositoryImpl(networkService: networkService) - let fetchFeedListUseCase = FetchFeedListUseCaseImpl(repository: repository) - let searchFeedListUsecase = SearchFeedListUseCaseImpl(repository: searchrepository) - - let recipeListViewModel = RecipeListInteractor(fetchFeedListUseCase: fetchFeedListUseCase, searchFeedListUseCase: searchFeedListUsecase) - - let recipeListVC = RecipeListViewController(interactor: recipeListViewModel) - recipeListVC.tabBarItem = UITabBarItem(title: "Recipes", image: UIImage(systemName: "list.bullet"), tag: 0) + let recipeListVC = router.createRecipeListDependencies() + let favoritesVC = createFavoritesViewController() + recipeListVC.tabBarItem = UITabBarItem( + title: "Recipes", + image: UIImage(systemName: "list.bullet"), + tag: 0 + ) + favoritesVC.tabBarItem = UITabBarItem( + title: "Favorites", + image: UIImage(systemName: "bookmark"), + tag: 1 + ) + viewControllers = [recipeListVC, favoritesVC] + } + + private func createFavoritesViewController() -> UIViewController { let favoritesVC = UIViewController() favoritesVC.view.backgroundColor = .white - favoritesVC.tabBarItem = UITabBarItem(title: "Favorites", image: UIImage(systemName: "bookmark"), tag: 1) - - viewControllers = [recipeListVC, favoritesVC] + return favoritesVC } private func setupActionButton() { @@ -68,12 +81,12 @@ class MainTabBarController: UITabBarController, UITabBarControllerDelegate { let alert = UIAlertController(title: "게시물 작성", message: "어떤 게시물을 작성하실 건가요?", preferredStyle: .actionSheet) alert.addAction(UIAlertAction(title: "Coffee", style: .default, handler: { [weak self] _ in guard let self else { return } - let addRecipeVC = AddRecipeViewController(recipeType: .coffee) + let addRecipeVC = self.router.createAddRecipeDependencies(recipeType: .coffee) self.navigationController?.pushViewController(addRecipeVC, animated: true) })) alert.addAction(UIAlertAction(title: "Dessert", style: .default, handler: { [weak self] _ in guard let self else { return } - let addRecipeVC = AddRecipeViewController(recipeType: .dessert) + let addRecipeVC = self.router.createAddRecipeDependencies(recipeType: .dessert) self.navigationController?.pushViewController(addRecipeVC, animated: true) })) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) From dfdf9a6a082e71d2e5d96d48a7effba282c615d0 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 21 Jul 2024 16:26:09 +0900 Subject: [PATCH 40/51] =?UTF-8?q?Fix:=20SceneDelegate=EC=97=90=20Router=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift b/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift index aa44d9a..1e8615b 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/SceneDelegate.swift @@ -10,7 +10,7 @@ import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - + var router: Router? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. @@ -18,8 +18,12 @@ 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) + router = Router() + guard let router else { return } + + let tabBarController = MainTabBarController(router: router) + let navigationController = UINavigationController(rootViewController: tabBarController) + navigationController.isNavigationBarHidden = true window?.rootViewController = navigationController window?.makeKeyAndVisible() } From bfe9ba7c8e005554d3c45cd2aeb3e396433724ff Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Sun, 21 Jul 2024 20:01:43 +0900 Subject: [PATCH 41/51] =?UTF-8?q?Fix:=20Interactor=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=9A=94=EC=B2=AD=20=ED=9B=84=20delegate?= =?UTF-8?q?=EB=A1=9C=20viewmodel=EC=9D=84=20=EA=B5=AC=EC=84=B1=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddRecipeViewController.swift | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift index b989451..1422bce 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/UploadRecipe/AddRecipeViewController.swift @@ -16,12 +16,11 @@ final class AddRecipeViewController: UIViewController { private let recipeType: RecipeType private let addRecipeInteractor: AddRecipeInteractor private let disposeBag = DisposeBag() - private var addRecipeViewModel: AddRecipeViewModel + private var addRecipeViewModel: AddRecipeViewModel? init(recipeType: RecipeType, addRecipeInteractor: AddRecipeInteractor) { self.recipeType = recipeType self.addRecipeInteractor = addRecipeInteractor - self.addRecipeViewModel = AddRecipeViewModel(images: addRecipeInteractor.getRecipeImages(), title: addRecipeInteractor.getRecipeTitle(), description: addRecipeInteractor.getRecipeDescription()) super.init(nibName: nil, bundle: nil) } @@ -38,6 +37,7 @@ final class AddRecipeViewController: UIViewController { setupUI() contentView.delegate = self setupNavigationBar() + addRecipeInteractor.loadRecipeData() } private func setupUI() { @@ -67,7 +67,7 @@ final class AddRecipeViewController: UIViewController { private func saveRecipeToServer() { // MARK: 임시 userID 설정 let userID = 6 - + addRecipeInteractor.saveRecipe(userID: userID, recipeType: recipeType) .subscribe(onSuccess: { [weak self] result in DispatchQueue.main.async { @@ -139,33 +139,25 @@ extension AddRecipeViewController: AddRecipeViewDelegate { } func didTapDeleteButton(at index: Int) { - addRecipeInteractor.removeImage(at: index) - updateaddRecipeViewModel() + addRecipeInteractor.removeRecipeImage(at: index) + addRecipeInteractor.loadRecipeData() contentView.updateImageView(count: numberOfImages()) } func didTapSubmitButton() { let title = contentView.titleText let description = contentView.descriptionText - addRecipeInteractor.updateTitle(title) - addRecipeInteractor.updateDescription(description) + addRecipeInteractor.updateRecipeTitle(title) + addRecipeInteractor.updateRecipeDescription(description) saveRecipeToServer() } func numberOfImages() -> Int { - return addRecipeViewModel.images.count + return addRecipeViewModel?.images.count ?? 0 } func recipeImage(at index: Int) -> UIImage? { - return addRecipeViewModel.images[index] - } - - private func updateaddRecipeViewModel() { - addRecipeViewModel = AddRecipeViewModel( - images: addRecipeInteractor.getRecipeImages(), - title: addRecipeInteractor.getRecipeTitle(), - description: addRecipeInteractor.getRecipeDescription() - ) + return addRecipeViewModel?.images[index] } } @@ -194,8 +186,8 @@ extension AddRecipeViewController: PHPickerViewControllerDelegate { dispatchGroup.notify(queue: .main) { [weak self] in guard let self else { return } - newImages.forEach { self.addRecipeInteractor.addImage($0) } - updateaddRecipeViewModel() + newImages.forEach { self.addRecipeInteractor.addRecipeImage($0) } + addRecipeInteractor.loadRecipeData() contentView.updateImageView(count: numberOfImages()) } } @@ -210,3 +202,12 @@ extension AddRecipeViewController: ImageCollectionViewCellDelegate { contentView.updateImageView(count: self.numberOfImages()) } } + +// MARK: AddRecipeInteractorDelegate + +extension AddRecipeViewController: AddRecipeInteractorDelegate { + func didLoadRecipeData(viewModel: AddRecipeViewModel) { + self.addRecipeViewModel = viewModel + self.contentView.updateImageView(count: numberOfImages()) + } +} From d7ab88c5f1a5e697baae3f8b327cd0d88abab064 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 00:09:41 +0900 Subject: [PATCH 42/51] =?UTF-8?q?Fix:=20dummy=20=EC=A4=84=EB=B0=94?= =?UTF-8?q?=EA=BF=88=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/Entities/Recipe.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift index d474d1b..637781c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift @@ -22,6 +22,21 @@ struct Recipe { extension Recipe { static func dummy() -> Recipe { - .init(id: 1, type: .coffee, name: "", description: "", writer: .init(id: 1, profileImage: "", nickname: "", createdAt: Date()), imageUrls: [], isLikedByCurrentUser: false, likeCount: 0, createdAt: Date()) + .init( + id: 1, + type: .coffee, + name: "", + description: "", + writer: .init( + id: 1, + profileImage: "", + nickname: "", + createdAt: Date() + ), + imageUrls: [], + isLikedByCurrentUser: false, + likeCount: 0, + createdAt: Date() + ) } } From 415e9a4a459f263410b1bb49afbf0f15de26a310 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 13:07:04 +0900 Subject: [PATCH 43/51] =?UTF-8?q?Fix:=20Mock=20=EA=B0=9D=EC=B2=B4=20final?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift | 2 +- .../HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift index 8fe1cf5..7ce5be7 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift @@ -18,7 +18,7 @@ final class FetchRecipeDetailUseCaseTests: XCTestCase { var fetchRecipeDetailRepository: FetchRecipeRepositoryMock! var disposeBag: DisposeBag! - class FetchRecipeRepositoryMock: RecipeDetailRepository { + final class FetchRecipeRepositoryMock: RecipeDetailRepository { var fetchRecipeDetailCallCount: Int = 0 var fetchRecipeDetailStub: Single = .just(Recipe.dummy()) func fetchRecipeDetail(recipeID: Int) -> Single { diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift index 3a9f24c..24daac3 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift @@ -17,7 +17,7 @@ final class RecipeDetailInteractorTests: XCTestCase { var fetchRecipeDetailUsecase: FetchRecipeDetailUseCaseMock! var delegate: RecipeDetailInteractorDelegateMock! - class FetchRecipeDetailUseCaseMock: FetchRecipeDetailUseCase { + final class FetchRecipeDetailUseCaseMock: FetchRecipeDetailUseCase { var executeCallCount: Int = 0 var executeStub: Single> = .just(.failure(NSError())) func execute(recipeID: Int) -> Single> { @@ -26,7 +26,7 @@ final class RecipeDetailInteractorTests: XCTestCase { } } - class RecipeDetailInteractorDelegateMock: RecipeDetailInteractorDelegate { + final class RecipeDetailInteractorDelegateMock: RecipeDetailInteractorDelegate { var fetchedCallCount: Int = 0 var fetchedRecipeResult: Result? func fetchedRecipe(result: Result) { From 18959c6afb2549a585f4959584979d096d1cc18c Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 13:07:33 +0900 Subject: [PATCH 44/51] =?UTF-8?q?Fix:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift | 3 --- .../HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift | 4 ---- 2 files changed, 7 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift index 7ce5be7..379cdf0 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift @@ -36,9 +36,6 @@ final class FetchRecipeDetailUseCaseTests: XCTestCase { fetchRecipeDetailRepository = .init() disposeBag = .init() } - - override func tearDownWithError() throws { - } } extension FetchRecipeDetailUseCaseTests { diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift index 24daac3..d7150fc 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift @@ -49,10 +49,6 @@ final class RecipeDetailInteractorTests: XCTestCase { fetchRecipeDetailUsecase = .init() delegate = .init() } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } } // MARK: viewDidLoad From 80597bd1ae50fc6609e43a15f62c8aad092bd121 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 13:13:04 +0900 Subject: [PATCH 45/51] =?UTF-8?q?Fix:=20dummyRecipe=EB=A1=9C=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes/Domain/Entities/Recipe.swift | 2 +- .../FetchRecipeDetailUseCaseTests.swift | 8 ++++---- .../RecipeDeatilInteractorTests.swift | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift index 637781c..5da605c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift @@ -21,7 +21,7 @@ struct Recipe { extension Recipe { - static func dummy() -> Recipe { + static func dummyRecipe() -> Recipe { .init( id: 1, type: .coffee, diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift index 379cdf0..95bd50a 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift @@ -20,7 +20,7 @@ final class FetchRecipeDetailUseCaseTests: XCTestCase { final class FetchRecipeRepositoryMock: RecipeDetailRepository { var fetchRecipeDetailCallCount: Int = 0 - var fetchRecipeDetailStub: Single = .just(Recipe.dummy()) + var fetchRecipeDetailStub: Single = .just(Recipe.dummyRecipe()) func fetchRecipeDetail(recipeID: Int) -> Single { fetchRecipeDetailCallCount += 1 return fetchRecipeDetailStub @@ -41,11 +41,11 @@ final class FetchRecipeDetailUseCaseTests: XCTestCase { extension FetchRecipeDetailUseCaseTests { func test_execute를_호출하면_1번_RecipeDetailRepository의_fetchRecipeDetail을_호출합니다(){ - + // Given let usecase = createUseCase() - fetchRecipeDetailRepository.fetchRecipeDetailStub = .just(Recipe.dummy()) + fetchRecipeDetailRepository.fetchRecipeDetailStub = .just(Recipe.dummyRecipe()) // When @@ -63,7 +63,7 @@ extension FetchRecipeDetailUseCaseTests { // Given let usecase = createUseCase() - let recipe = Recipe.dummy() + let recipe = Recipe.dummyRecipe() fetchRecipeDetailRepository.fetchRecipeDetailStub = .just(recipe) let expectation = self.expectation(description: "Fetch Recipe Success") diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift index d7150fc..adb5c4b 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift @@ -69,7 +69,7 @@ extension RecipeDetailInteractorTests { func test_FetchRecipeDetailUsecase의_성공응답이오면_Delegate로_성공을_전달합니다() { // given let interactor = createInteractor() - let recipe = Recipe.dummy() + let recipe = Recipe.dummyRecipe() fetchRecipeDetailUsecase.executeStub = .just(.success(recipe)) // when From 7e579b806c43788a36b32723a6838cc624100e0b Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 13:20:59 +0900 Subject: [PATCH 46/51] =?UTF-8?q?Fix:=20self.delegate.fetchedRecipeResult?= =?UTF-8?q?=EC=97=90=EC=84=9C=20self=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift index adb5c4b..6d0e51a 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift @@ -79,7 +79,7 @@ extension RecipeDetailInteractorTests { XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1) XCTAssertEqual(self.delegate.fetchedCallCount, 1) - if case .success(let fetchedRecipe)? = self.delegate.fetchedRecipeResult { + if case .success(let fetchedRecipe)? = delegate.fetchedRecipeResult { XCTAssertEqual(fetchedRecipe.id, recipe.id) } else { XCTFail("Expected success but got failure or nil") @@ -100,7 +100,7 @@ extension RecipeDetailInteractorTests { XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1) XCTAssertEqual(self.delegate.fetchedCallCount, 1) - if case .failure(let fetchedError as NSError) = self.delegate.fetchedRecipeResult { + if case .failure(let fetchedError as NSError) = delegate.fetchedRecipeResult { XCTAssertEqual(fetchedError.domain, error.domain) XCTAssertEqual(fetchedError.code, error.code) } else { From d0d27b028709004f6f3d3d99e0cd54957511b638 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 13:21:53 +0900 Subject: [PATCH 47/51] =?UTF-8?q?Fix:=20FetchRecipeDetailUseCaseImpl=20?= =?UTF-8?q?=EA=B0=9C=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift index 95bd50a..eedbc3a 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift @@ -28,7 +28,9 @@ final class FetchRecipeDetailUseCaseTests: XCTestCase { } func createUseCase() -> FetchRecipeDetailUseCase { - let usecase = FetchRecipeDetailUseCaseImpl(repository: fetchRecipeDetailRepository) + let usecase = FetchRecipeDetailUseCaseImpl( + repository: fetchRecipeDetailRepository + ) return usecase } From 0cc06c1021df24805560f8eb38bce90f2f7d2ab7 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 18:56:04 +0900 Subject: [PATCH 48/51] =?UTF-8?q?Fix:=20test=20=EB=84=A4=EC=9D=B4=EB=B0=8D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift index 6d0e51a..9c15b98 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift @@ -55,7 +55,7 @@ final class RecipeDetailInteractorTests: XCTestCase { extension RecipeDetailInteractorTests { - func test_화면이_로드될때_FetchRecipeDetailUsecase를_실행합니다() { + func test_화면이_로드될때_FetchRecipeDetailUsecase를_호출합니다() { // given let interactor = createInteractor() From 61854b3e9742ce3ba3a985716a7cd325395e9afd Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Mon, 22 Jul 2024 23:11:08 +0900 Subject: [PATCH 49/51] =?UTF-8?q?Fix:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift index eedbc3a..0a70e08 100644 --- a/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift +++ b/HomeCafeRecipes/HomeCafeRecipesTests/FetchRecipeDetailUseCaseTests.swift @@ -42,7 +42,7 @@ final class FetchRecipeDetailUseCaseTests: XCTestCase { extension FetchRecipeDetailUseCaseTests { - func test_execute를_호출하면_1번_RecipeDetailRepository의_fetchRecipeDetail을_호출합니다(){ + func test_execute를_호출하면_RecipeDetailRepository의_fetchRecipeDetail을_호출합니다(){ // Given From e4b31153795db79c4aed17ef216eb6c495654667 Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Tue, 23 Jul 2024 14:40:39 +0900 Subject: [PATCH 50/51] =?UTF-8?q?Fix:=20=EC=83=81=EC=88=98=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=ED=9B=84=20=EB=B0=94=EB=A1=9C=20=EC=A3=BC=EC=9E=85?= =?UTF-8?q?=EC=8B=9C=ED=82=A4=EB=8A=94=20=EC=BD=94=EB=93=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeCafeRecipes/Router/Router.swift | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift b/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift index d092968..0ada8ca 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift @@ -49,15 +49,21 @@ class Router: NSObject, RouterProtocol { extension Router { func createRecipeListDependencies() -> RecipeListViewController { - let baseNetworkService = BaseNetworkService() - let recipeFetchService = RecipeFetchServiceImpl(networkService: baseNetworkService) - let feedListRepository = FeedListRepositoryImpl(networkService: recipeFetchService) - let searchFeedRepository = SearchFeedRepositoryImpl(networkService: recipeFetchService) - let fetchFeedListUseCase = FetchFeedListUseCaseImpl(repository: feedListRepository) - let searchFeedListUseCase = SearchFeedListUseCaseImpl(repository: searchFeedRepository) let recipeListInteractor = RecipeListInteractorImpl( - fetchFeedListUseCase: fetchFeedListUseCase, - searchFeedListUseCase: searchFeedListUseCase + fetchFeedListUseCase: FetchFeedListUseCaseImpl( + repository: FeedListRepositoryImpl( + networkService: RecipeFetchServiceImpl( + networkService: BaseNetworkService() + ) + ) + ), + searchFeedListUseCase: SearchFeedListUseCaseImpl( + repository: SearchFeedRepositoryImpl( + networkService: RecipeFetchServiceImpl( + networkService: BaseNetworkService() + ) + ) + ) ) let recipeListRouter = RecipeListRouterImpl(router: self) let recipeListVC = RecipeListViewController( @@ -69,21 +75,30 @@ extension Router { } func createAddRecipeDependencies(recipeType: RecipeType) -> AddRecipeViewController { - let baseNetworkService = BaseNetworkService() - let recipePostService = RecipePostServiceImpl(networkService: baseNetworkService) - let saveRepository = AddRecipeRepositoryImpl(recipePostService: recipePostService) - let saveRecipeUseCase = SaveRecipeUseCaseImpl(repository: saveRepository) - let addRecipeInteractor = AddRecipeInteractorImpl(saveRecipeUseCase: saveRecipeUseCase) - let addRecipeVC = AddRecipeViewController(recipeType: recipeType, addRecipeInteractor: addRecipeInteractor) + let addRecipeInteractor = AddRecipeInteractorImpl( + saveRecipeUseCase: AddRecipeUseCaseImpl( + repository: AddRecipeRepositoryImpl( + recipePostService: RecipePostServiceImpl( + networkService: BaseNetworkService() + ) + ) + ) + ) + let addRecipeVC = AddRecipeViewController( + recipeType: recipeType, + addRecipeInteractor: addRecipeInteractor + ) + addRecipeInteractor.delegate = addRecipeVC return addRecipeVC } func createRecipeDetailDependencies(recipeID: Int) -> RecipeDetailViewController { - let baseNetworkService = BaseNetworkService() - let recipeDetailRepository = RecipeDetailRepositoryImpl(networkService: baseNetworkService) - let fetchRecipeDetailUseCase = FetchRecipeDetailUseCaseImpl(repository: recipeDetailRepository) let detailInteractor = RecipeDetailInteractorImpl( - fetchRecipeDetailUseCase: fetchRecipeDetailUseCase, + fetchRecipeDetailUseCase: FetchRecipeDetailUseCaseImpl( + repository: RecipeDetailRepositoryImpl( + networkService: BaseNetworkService() + ) + ), recipeID: recipeID ) let detailVC = RecipeDetailViewController(interactor: detailInteractor) From 9c07a9b1677f8e9df46c3c99119d7200d17ac3ae Mon Sep 17 00:00:00 2001 From: GeonH0 Date: Tue, 23 Jul 2024 14:44:05 +0900 Subject: [PATCH 51/51] =?UTF-8?q?Fix:=20create=5F=5F=5FDependencies=20?= =?UTF-8?q?=EC=97=90=EC=84=9C=20make=5F=5F=5FViewController=EB=A1=9C=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Tabbar/MainTabBarController.swift | 4 ++-- .../HomeCafeRecipes/Router/RecipeListRouter.swift | 2 +- HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift index ea666a3..a57e50c 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Presentation/Tabbar/MainTabBarController.swift @@ -81,12 +81,12 @@ class MainTabBarController: UITabBarController, UITabBarControllerDelegate { let alert = UIAlertController(title: "게시물 작성", message: "어떤 게시물을 작성하실 건가요?", preferredStyle: .actionSheet) alert.addAction(UIAlertAction(title: "Coffee", style: .default, handler: { [weak self] _ in guard let self else { return } - let addRecipeVC = self.router.createAddRecipeDependencies(recipeType: .coffee) + let addRecipeVC = router.makeAddRecipeViewController(recipeType: .coffee) self.navigationController?.pushViewController(addRecipeVC, animated: true) })) alert.addAction(UIAlertAction(title: "Dessert", style: .default, handler: { [weak self] _ in guard let self else { return } - let addRecipeVC = self.router.createAddRecipeDependencies(recipeType: .dessert) + let addRecipeVC = router.makeAddRecipeViewController(recipeType: .dessert) self.navigationController?.pushViewController(addRecipeVC, animated: true) })) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) diff --git a/HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift b/HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift index 4e0c7a3..bf15166 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Router/RecipeListRouter.swift @@ -19,7 +19,7 @@ class RecipeListRouterImpl: RecipeListRouter { } func navigateToRecipeDetail(from viewController: UIViewController, recipeID: Int) { - let detailVC = router.createRecipeDetailDependencies(recipeID: recipeID) + let detailVC = router.makeRecipeDetailViewController(recipeID: recipeID) router.push(detailVC, from: viewController, isAnimated: true, onNavigateBack: nil) } } diff --git a/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift b/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift index 0ada8ca..570dbf0 100644 --- a/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift +++ b/HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift @@ -48,7 +48,7 @@ class Router: NSObject, RouterProtocol { } extension Router { - func createRecipeListDependencies() -> RecipeListViewController { + func makeRecipeListViewController() -> RecipeListViewController { let recipeListInteractor = RecipeListInteractorImpl( fetchFeedListUseCase: FetchFeedListUseCaseImpl( repository: FeedListRepositoryImpl( @@ -74,7 +74,7 @@ extension Router { return recipeListVC } - func createAddRecipeDependencies(recipeType: RecipeType) -> AddRecipeViewController { + func makeAddRecipeViewController(recipeType: RecipeType) -> AddRecipeViewController { let addRecipeInteractor = AddRecipeInteractorImpl( saveRecipeUseCase: AddRecipeUseCaseImpl( repository: AddRecipeRepositoryImpl( @@ -92,7 +92,7 @@ extension Router { return addRecipeVC } - func createRecipeDetailDependencies(recipeID: Int) -> RecipeDetailViewController { + func makeRecipeDetailViewController(recipeID: Int) -> RecipeDetailViewController { let detailInteractor = RecipeDetailInteractorImpl( fetchRecipeDetailUseCase: FetchRecipeDetailUseCaseImpl( repository: RecipeDetailRepositoryImpl(