diff --git a/.DS_Store b/.DS_Store index 331ed93..15ad726 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Drink-EG/Drink-EG.xcodeproj/project.pbxproj b/Drink-EG/Drink-EG.xcodeproj/project.pbxproj index 9fafcf9..f15e272 100644 --- a/Drink-EG/Drink-EG.xcodeproj/project.pbxproj +++ b/Drink-EG/Drink-EG.xcodeproj/project.pbxproj @@ -40,6 +40,8 @@ 165401212C6E56BD008A9DBF /* RatingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165401202C6E56BD008A9DBF /* RatingView.swift */; }; 165401232C6E57BC008A9DBF /* CardSliderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165401222C6E57BC008A9DBF /* CardSliderCell.swift */; }; 1654014C2C6F41B0008A9DBF /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1654014B2C6F41B0008A9DBF /* ContentView.swift */; }; + 1654014E2C6F9582008A9DBF /* APIResponseNoteResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1654014D2C6F9582008A9DBF /* APIResponseNoteResponse.swift */; }; + 165401502C6F960A008A9DBF /* NoteResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1654014F2C6F960A008A9DBF /* NoteResponse.swift */; }; 16752F9D2C5A7FB90001907D /* HexCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16752F9C2C5A7FB90001907D /* HexCode.swift */; }; 16B97CD42C4BEB0900D8B453 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16B97CD32C4BEB0900D8B453 /* AppDelegate.swift */; }; 16B97CD62C4BEB0900D8B453 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16B97CD52C4BEB0900D8B453 /* SceneDelegate.swift */; }; @@ -78,6 +80,14 @@ 1F598F112C5CBE7A000CE79F /* SecondTasteTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F598F102C5CBE7A000CE79F /* SecondTasteTestViewController.swift */; }; 1F8DE5772C4D4ED800961A59 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8DE5762C4D4ED700961A59 /* MainTabBarViewController.swift */; }; 1F8DE5792C4D5A4D00961A59 /* SettingMainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8DE5782C4D5A4D00961A59 /* SettingMainController.swift */; }; + 1F8F99F32C6F386B00EAEF6C /* SearchAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99F22C6F386B00EAEF6C /* SearchAPI.swift */; }; + 1F8F99F52C6F40F400EAEF6C /* APIResponseWineSearchResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99F42C6F40F400EAEF6C /* APIResponseWineSearchResponse.swift */; }; + 1F8F99F82C6F52C600EAEF6C /* WineSearchResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99F72C6F52C600EAEF6C /* WineSearchResponse.swift */; }; + 1F8F99FA2C6F538300EAEF6C /* WineInfoResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99F92C6F538300EAEF6C /* WineInfoResponse.swift */; }; + 1F8F99FC2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99FB2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift */; }; + 1FBD19532C6CFABB005C16A8 /* WineShopListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FBD19522C6CFABB005C16A8 /* WineShopListCollectionViewCell.swift */; }; + 1FBD19552C6D2BF7005C16A8 /* ReviewListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FBD19542C6D2BF7005C16A8 /* ReviewListViewController.swift */; }; + 1FBD19572C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FBD19562C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift */; }; 5E22192D2C69D592005849FB /* Pretendard-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5E2219242C69D592005849FB /* Pretendard-Bold.otf */; }; 5E22192E2C69D592005849FB /* Pretendard-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5E2219252C69D592005849FB /* Pretendard-Black.otf */; }; 5E22192F2C69D592005849FB /* Pretendard-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5E2219262C69D592005849FB /* Pretendard-Regular.otf */; }; @@ -113,6 +123,8 @@ 5E22196E2C6B2EA0005849FB /* RatingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E22196D2C6B2EA0005849FB /* RatingViewController.swift */; }; 5E2219712C6B5B5B005849FB /* Cosmos in Frameworks */ = {isa = PBXBuildFile; productRef = 5E2219702C6B5B5B005849FB /* Cosmos */; }; 5E2219732C6B661A005849FB /* CheckNoteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2219722C6B661A005849FB /* CheckNoteViewController.swift */; }; + 5E22197B2C6BB56F005849FB /* SDWebImage in Frameworks */ = {isa = PBXBuildFile; productRef = 5E22197A2C6BB56F005849FB /* SDWebImage */; }; + 5E22197D2C6BB56F005849FB /* SDWebImageMapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5E22197C2C6BB56F005849FB /* SDWebImageMapKit */; }; 5E23147F2C5901BB004E2013 /* (null) in Sources */ = {isa = PBXBuildFile; }; /* End PBXBuildFile section */ @@ -149,6 +161,8 @@ 165401202C6E56BD008A9DBF /* RatingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RatingView.swift; path = ../../../../../../../../Downloads/RatingView.swift; sourceTree = ""; }; 165401222C6E57BC008A9DBF /* CardSliderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CardSliderCell.swift; path = ../../../../../../../../Downloads/CardSliderCell.swift; sourceTree = ""; }; 1654014B2C6F41B0008A9DBF /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 1654014D2C6F9582008A9DBF /* APIResponseNoteResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIResponseNoteResponse.swift; sourceTree = ""; }; + 1654014F2C6F960A008A9DBF /* NoteResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteResponse.swift; sourceTree = ""; }; 16752F9C2C5A7FB90001907D /* HexCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HexCode.swift; sourceTree = ""; }; 16B97CD02C4BEB0900D8B453 /* Drink-EG.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Drink-EG.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 16B97CD32C4BEB0900D8B453 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -188,6 +202,14 @@ 1F598F102C5CBE7A000CE79F /* SecondTasteTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondTasteTestViewController.swift; sourceTree = ""; }; 1F8DE5762C4D4ED700961A59 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = ""; }; 1F8DE5782C4D5A4D00961A59 /* SettingMainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SettingMainController.swift; path = "Drink-EG/Sources/VCs/Main/SettingMainController.swift"; sourceTree = SOURCE_ROOT; }; + 1F8F99F22C6F386B00EAEF6C /* SearchAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchAPI.swift; sourceTree = ""; }; + 1F8F99F42C6F40F400EAEF6C /* APIResponseWineSearchResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIResponseWineSearchResponse.swift; sourceTree = ""; }; + 1F8F99F72C6F52C600EAEF6C /* WineSearchResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WineSearchResponse.swift; sourceTree = ""; }; + 1F8F99F92C6F538300EAEF6C /* WineInfoResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WineInfoResponse.swift; sourceTree = ""; }; + 1F8F99FB2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIResponseWineInfoResponse.swift; sourceTree = ""; }; + 1FBD19522C6CFABB005C16A8 /* WineShopListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WineShopListCollectionViewCell.swift; sourceTree = ""; }; + 1FBD19542C6D2BF7005C16A8 /* ReviewListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewListViewController.swift; sourceTree = ""; }; + 1FBD19562C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewListCollectionViewCell.swift; sourceTree = ""; }; 5E2219242C69D592005849FB /* Pretendard-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Bold.otf"; sourceTree = ""; }; 5E2219252C69D592005849FB /* Pretendard-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Black.otf"; sourceTree = ""; }; 5E2219262C69D592005849FB /* Pretendard-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Regular.otf"; sourceTree = ""; }; @@ -229,8 +251,10 @@ 5E22195E2C69DDB5005849FB /* SnapKit in Frameworks */, 165401162C6E3858008A9DBF /* CardSlider in Frameworks */, 5E2219672C69DE78005849FB /* KakaoSDK in Frameworks */, + 5E22197B2C6BB56F005849FB /* SDWebImage in Frameworks */, 5E2219612C69DDBF005849FB /* Alamofire in Frameworks */, 5E22196A2C69DEEA005849FB /* Toast in Frameworks */, + 5E22197D2C6BB56F005849FB /* SDWebImageMapKit in Frameworks */, 5E2219642C69DE43005849FB /* Moya in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -241,10 +265,12 @@ 165400F42C69EEE6008A9DBF /* Datas */ = { isa = PBXGroup; children = ( + 1F8F99F62C6F52A100EAEF6C /* Search */, 165401022C69F305008A9DBF /* WineClass */, 165401012C69F297008A9DBF /* WineNews */, 1F205A322C69FE9800E80659 /* JoinNLoginRequest.swift */, 165401062C6BA5D8008A9DBF /* MemberInfoRequest.swift */, + 1654014F2C6F960A008A9DBF /* NoteResponse.swift */, ); path = Datas; sourceTree = ""; @@ -275,6 +301,9 @@ 165400FD2C69F218008A9DBF /* APIResponseWineClassResponse.swift */, 1F205A362C6A71BC00E80659 /* APIResponseLoginResponse.swift */, 1654010C2C6C7FBB008A9DBF /* APIResponseMemberResponse.swift */, + 1654014D2C6F9582008A9DBF /* APIResponseNoteResponse.swift */, + 1F8F99F42C6F40F400EAEF6C /* APIResponseWineSearchResponse.swift */, + 1F8F99FB2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift */, ); path = APIResponseModels; sourceTree = ""; @@ -380,6 +409,7 @@ 165400F02C69DE22008A9DBF /* CommunityAPI.swift */, 165400F22C69DE2D008A9DBF /* CommentsAPI.swift */, 165401082C6BA644008A9DBF /* MemberInfoAPI.swift */, + 1F8F99F22C6F386B00EAEF6C /* SearchAPI.swift */, ); path = APIs; sourceTree = ""; @@ -451,6 +481,9 @@ 16B97D052C4C0CF800D8B453 /* WineStoreListViewController.swift */, 16B97D072C4C0D8100D8B453 /* WineOrderViewController.swift */, 1F3CEAD52C669FD2002A4BC0 /* WineListCollectionViewCell.swift */, + 1FBD19522C6CFABB005C16A8 /* WineShopListCollectionViewCell.swift */, + 1FBD19542C6D2BF7005C16A8 /* ReviewListViewController.swift */, + 1FBD19562C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift */, ); path = Search; sourceTree = ""; @@ -490,9 +523,9 @@ 16B97CF92C4BFB4700D8B453 /* Community */ = { isa = PBXGroup; children = ( + 5E2219402C69D5D0005849FB /* CommunityMainViewController.swift */, 5E22193C2C69D5D0005849FB /* CommunityInfoViewController.swift */, 5E22193F2C69D5D0005849FB /* CommunityListViewController.swift */, - 5E2219402C69D5D0005849FB /* CommunityMainViewController.swift */, 5E22193B2C69D5D0005849FB /* CreateNewCommViewController.swift */, 5E22193E2C69D5D0005849FB /* CustomCollectionViewCell.swift */, 5E2219392C69D5D0005849FB /* CustomCommentsCollectionView.swift */, @@ -553,6 +586,15 @@ path = TasteTest; sourceTree = ""; }; + 1F8F99F62C6F52A100EAEF6C /* Search */ = { + isa = PBXGroup; + children = ( + 1F8F99F72C6F52C600EAEF6C /* WineSearchResponse.swift */, + 1F8F99F92C6F538300EAEF6C /* WineInfoResponse.swift */, + ); + path = Search; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -577,6 +619,8 @@ 5E2219692C69DEEA005849FB /* Toast */, 5E2219702C6B5B5B005849FB /* Cosmos */, 165401152C6E3858008A9DBF /* CardSlider */, + 5E22197A2C6BB56F005849FB /* SDWebImage */, + 5E22197C2C6BB56F005849FB /* SDWebImageMapKit */, ); productName = "Drink-EG"; productReference = 16B97CD02C4BEB0900D8B453 /* Drink-EG.app */; @@ -614,6 +658,7 @@ 5E2219682C69DEEA005849FB /* XCRemoteSwiftPackageReference "Toast-Swift" */, 5E22196F2C6B5B5B005849FB /* XCRemoteSwiftPackageReference "Cosmos" */, 165401142C6E3858008A9DBF /* XCRemoteSwiftPackageReference "cardslider" */, + 5E2219792C6BB56F005849FB /* XCRemoteSwiftPackageReference "SDWebImage" */, ); productRefGroup = 16B97CD12C4BEB0900D8B453 /* Products */; projectDirPath = ""; @@ -654,15 +699,19 @@ 165400E22C69D6B9008A9DBF /* CookiePlugin.swift in Sources */, 1F598F0F2C5CBE70000CE79F /* FirstTasteTestViewController.swift in Sources */, 5E2219562C69D5E7005849FB /* ChooseTasteViewController.swift in Sources */, + 1F8F99F82C6F52C600EAEF6C /* WineSearchResponse.swift in Sources */, 165400F62C69EF89008A9DBF /* WineNewsRequest.swift in Sources */, + 1654014E2C6F9582008A9DBF /* APIResponseNoteResponse.swift in Sources */, 5E2219552C69D5E7005849FB /* CustomSlider.swift in Sources */, 1654010B2C6BACDC008A9DBF /* SelectionManager.swift in Sources */, 16752F9D2C5A7FB90001907D /* HexCode.swift in Sources */, 165401192C6E555A008A9DBF /* CardSliderViewController.swift in Sources */, 1F598F0B2C5CBD9E000CE79F /* EnterTasteTestViewController.swift in Sources */, 165401212C6E56BD008A9DBF /* RatingView.swift in Sources */, + 1F8F99FA2C6F538300EAEF6C /* WineInfoResponse.swift in Sources */, 5E22196E2C6B2EA0005849FB /* RatingViewController.swift in Sources */, 1F205A432C6B66EB00E80659 /* TasteTestThirdCollectionViewCell.swift in Sources */, + 1FBD19572C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift in Sources */, 5E23147F2C5901BB004E2013 /* (null) in Sources */, 16B97D162C4C0F6400D8B453 /* SavingVideoViewController.swift in Sources */, 165400F82C69EFBD008A9DBF /* WineNewsResponse.swift in Sources */, @@ -683,6 +732,7 @@ 165401232C6E57BC008A9DBF /* CardSliderCell.swift in Sources */, 1654010D2C6C7FBB008A9DBF /* APIResponseMemberResponse.swift in Sources */, 1654011B2C6E5661008A9DBF /* CardTitleview.swift in Sources */, + 1F8F99F52C6F40F400EAEF6C /* APIResponseWineSearchResponse.swift in Sources */, 165401072C6BA5D8008A9DBF /* MemberInfoRequest.swift in Sources */, 1F205A372C6A71BC00E80659 /* APIResponseLoginResponse.swift in Sources */, 165400FA2C69F15D008A9DBF /* APIResponseWineNewsResponse.swift in Sources */, @@ -692,6 +742,7 @@ 5E2219432C69D5D0005849FB /* ModalViewController.swift in Sources */, 165400FC2C69F1A3008A9DBF /* WineClassRequest.swift in Sources */, 165401002C69F251008A9DBF /* WineClassResponse.swift in Sources */, + 165401502C6F960A008A9DBF /* NoteResponse.swift in Sources */, 5E2219482C69D5D0005849FB /* CommunityListViewController.swift in Sources */, 5E2219492C69D5D0005849FB /* CommunityMainViewController.swift in Sources */, 16B97CD42C4BEB0900D8B453 /* AppDelegate.swift in Sources */, @@ -704,6 +755,8 @@ 16B97CD62C4BEB0900D8B453 /* SceneDelegate.swift in Sources */, 16B97D082C4C0D8100D8B453 /* WineOrderViewController.swift in Sources */, 1F205A3B2C6B343300E80659 /* ThirdNationTasteTestViewController.swift in Sources */, + 1F8F99FC2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift in Sources */, + 1FBD19532C6CFABB005C16A8 /* WineShopListCollectionViewCell.swift in Sources */, 1F3CEAD62C669FD2002A4BC0 /* WineListCollectionViewCell.swift in Sources */, 165401042C69FA13008A9DBF /* APIResponseString.swift in Sources */, 165400E12C69D6B9008A9DBF /* BasicAPI.swift in Sources */, @@ -723,6 +776,7 @@ 16B97CFE2C4BFC2300D8B453 /* HomeViewController.swift in Sources */, 1F205A332C69FE9800E80659 /* JoinNLoginRequest.swift in Sources */, 1F205A3D2C6B34A300E80659 /* ThirdVarietyTasteTestViewController.swift in Sources */, + 1FBD19552C6D2BF7005C16A8 /* ReviewListViewController.swift in Sources */, 1F8DE5792C4D5A4D00961A59 /* SettingMainController.swift in Sources */, 165400ED2C69DDF2008A9DBF /* WineNewsAPI.swift in Sources */, 5E2219532C69D5E7005849FB /* NoteInfoViewController.swift in Sources */, @@ -731,6 +785,7 @@ 1F598F032C581A7D000CE79F /* StartLoginCollectionViewCell.swift in Sources */, 5E2219452C69D5D0005849FB /* CommunityInfoViewController.swift in Sources */, 1F598EFB2C5814F9000CE79F /* EnterLoginViewController.swift in Sources */, + 1F8F99F32C6F386B00EAEF6C /* SearchAPI.swift in Sources */, 16B97D022C4BFC9800D8B453 /* SearchHomeViewController.swift in Sources */, 5E2219732C6B661A005849FB /* CheckNoteViewController.swift in Sources */, 1654014C2C6F41B0008A9DBF /* ContentView.swift in Sources */, @@ -998,6 +1053,14 @@ minimumVersion = 25.0.1; }; }; + 5E2219792C6BB56F005849FB /* XCRemoteSwiftPackageReference "SDWebImage" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SDWebImage/SDWebImage.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.19.6; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1036,6 +1099,16 @@ package = 5E22196F2C6B5B5B005849FB /* XCRemoteSwiftPackageReference "Cosmos" */; productName = Cosmos; }; + 5E22197A2C6BB56F005849FB /* SDWebImage */ = { + isa = XCSwiftPackageProductDependency; + package = 5E2219792C6BB56F005849FB /* XCRemoteSwiftPackageReference "SDWebImage" */; + productName = SDWebImage; + }; + 5E22197C2C6BB56F005849FB /* SDWebImageMapKit */ = { + isa = XCSwiftPackageProductDependency; + package = 5E2219792C6BB56F005849FB /* XCRemoteSwiftPackageReference "SDWebImage" */; + productName = SDWebImageMapKit; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 16B97CC82C4BEB0900D8B453 /* Project object */; diff --git a/Drink-EG/Drink-EG.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Drink-EG/Drink-EG.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 838c2c4..220ff9b 100644 --- a/Drink-EG/Drink-EG.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Drink-EG/Drink-EG.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,10 +1,10 @@ { - "originHash" : "ae843fcd9fde0e0eb90792d861b014bf16f661547950eb4147c039184b74fb38", + "originHash" : "a8561a89e8f67830f69988d3a168bbd94d5d7088705bdbb1ebac5fe0c3ef0104", "pins" : [ { "identity" : "alamofire", "kind" : "remoteSourceControl", - "location" : "https://github.com/Alamofire/Alamofire", + "location" : "https://github.com/Alamofire/Alamofire.git", "state" : { "revision" : "f455c2975872ccd2d9c81594c658af65716e9b9a", "version" : "5.9.1" @@ -31,7 +31,7 @@ { "identity" : "kakao-ios-sdk", "kind" : "remoteSourceControl", - "location" : "https://github.com/kakao/kakao-ios-sdk", + "location" : "https://github.com/kakao/kakao-ios-sdk.git", "state" : { "revision" : "66b3bddc2657e8ccb7a16fa0264aac99c57be09b", "version" : "2.22.5" @@ -64,6 +64,15 @@ "version" : "6.7.1" } }, + { + "identity" : "sdwebimage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SDWebImage/SDWebImage.git", + "state" : { + "revision" : "5191b801aca999b704eb93f118f91468b4570571", + "version" : "5.19.6" + } + }, { "identity" : "snapkit", "kind" : "remoteSourceControl", diff --git a/Drink-EG/Drink-EG/Resources/APIs/SearchAPI.swift b/Drink-EG/Drink-EG/Resources/APIs/SearchAPI.swift new file mode 100644 index 0000000..fb8617f --- /dev/null +++ b/Drink-EG/Drink-EG/Resources/APIs/SearchAPI.swift @@ -0,0 +1,71 @@ +// +// SearchAPI.swift +// Drink-EG +// +// Created by 이현주 on 8/16/24. +// + +import Foundation +import Moya + +// JWT 토큰을 받을 수 있도록 BasicAPI 정의 +/// 기능 하나 당 API 1개씩 만들기 +/// - API 명세서 기준으로 1 명세서 당 1 API enum 정의하기 +/// - 변경을 한 번 더 해보자. + +enum SearchAPI { + case getWineName(wineName: String) + case getWineInfo(wineId: Int) + case getWineReview(wineId: Int) +} + +extension SearchAPI: TargetType { + var baseURL: URL { + /// 기본 URL 작성 + return URL(string: "https://drinkeg.com/")! + + } + + var path: String { + /// 기본 URL + path 로 URL 구성 + switch self { + /// 동일한 path는 한 case로 처리 가능 + case .getWineName: + return "wine" + case .getWineInfo(let wineId): + return "wine/\(wineId)" + case .getWineReview(let wineId): + return "wine/review/\(wineId)" + } + } + + var method: Moya.Method { + /// 각 case 별로 적합한 method 배정 + switch self { + case .getWineName, .getWineInfo, .getWineReview: + return .get + } + } + + var task: Task { + switch self { + case .getWineName(let wineName): + return .requestParameters(parameters: ["searchName": wineName], encoding: URLEncoding.queryString) + case .getWineInfo, .getWineReview: + return .requestPlain + } + } + + // API 호출 시, header에 token 넣어서 전달 + var headers: [String : String]? { + let jwtToken = "jwt_token_here" + return [ + "Authorization": "Bearer \(jwtToken)", + "Content-type": "application/json" + ] + } + + var validationType: ValidationType { + return .successCodes + } +} diff --git a/Drink-EG/Drink-EG/Resources/APIs/TastingNoteAPI.swift b/Drink-EG/Drink-EG/Resources/APIs/TastingNoteAPI.swift index dc2da85..61ff252 100644 --- a/Drink-EG/Drink-EG/Resources/APIs/TastingNoteAPI.swift +++ b/Drink-EG/Drink-EG/Resources/APIs/TastingNoteAPI.swift @@ -16,41 +16,90 @@ import Moya enum TastingNoteAPI { case getAllNotes case getWineName(wineName: String) - + case getNoteID(noteId: Int) + case postNewNote(wineId: Int, color: String, sugarContent: Int, acidity: Int, tannin: Int, body: Int, alcohol: Int, scentAroma: [String], scentTaste: [String], scentFinish: [String], satisfaction: Int, memo: String) + case patchNote(wineId: Int, color: String, sugarContent: Int, acidity: Int, tannin: Int, body: Int, alcohol: Int, scentAroma: [String], scentTaste: [String], scentFinish: [String], satisfaction: Int, review: String) + case deleteNote(noteId: Int) } extension TastingNoteAPI: TargetType { var baseURL: URL { /// 기본 URL 작성 - return URL(string: "https://drinkeg.com/tasting-note/")! + return URL(string: "https://drinkeg.com/")! + } var path: String { /// 기본 URL + path 로 URL 구성 switch self { /// 동일한 path는 한 case로 처리 가능 - case .getWineName(let wineName): - return "\(wineName)" + case .getWineName: + return "wine" case .getAllNotes: - return "all-note" + return "tasting-note/all-note" + case .getNoteID(let noteId): + return "tasting-note/\(noteId)" + case .postNewNote: + return "tasting-note/new-note" + case .patchNote(let wineId, let color, let sugarContent, let acidity, let tannin, let body, let alcohol, let scentAroma, let scentTaste, let scentFinish, let satisfaction, let review): + return "wine-note/\(wineId)" + case .deleteNote(let noteId): + return "tasting-note/\(noteId)" } } var method: Moya.Method { /// 각 case 별로 적합한 method 배정 switch self { - case .getWineName: - return .get - case .getAllNotes: + case .getWineName, .getAllNotes, .getNoteID: return .get + case .postNewNote: + return .post + case .patchNote: + return .patch + case .deleteNote: + return .delete } } var task: Task { switch self { case .getWineName(let wineName): - return .requestParameters(parameters: ["wineName": wineName], encoding: JSONEncoding.default) - case .getAllNotes: + return .requestParameters(parameters: ["searchName": wineName], encoding: URLEncoding.queryString) + case .getAllNotes, .getNoteID: + return .requestPlain + case .postNewNote(let wineId, let color, let sugarContent, let acidity, let tannin, let body, let alcohol, let scentAroma, let scentTaste, let scentFinish, let satisfaction, let review): + let parameters: [String: Any] = [ + "wineId": wineId, + "color": color, + "sugarContent": sugarContent, + "acidity": acidity, + "tannin": tannin, + "body": body, + "alcohol": alcohol, + "scentAroma": scentAroma, + "scentTaste": scentTaste, + "scentFinish": scentFinish, + "satisfaction": satisfaction, + "review": review + ] + return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) + case .patchNote(_, let color, let sugarContent, let acidity, let tannin, let body, let alcohol, let scentAroma, let scentTaste, let scentFinish, let satisfaction, let review): + let parameters: [String: Any] = [ + "color": color, + "sugarContent": sugarContent, + "acidity": acidity, + "tannin": tannin, + "body": body, + "alcohol": alcohol, + "scentAroma": scentAroma, + "scentTaste": scentTaste, + "scentFinish": scentFinish, + "satisfaction": satisfaction, + "review": review + ] + return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) + case .deleteNote: return .requestPlain } } diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/1.imageset/1.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/1.imageset/1.png deleted file mode 100644 index 6e81d85..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/1.imageset/1.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/2.imageset/1 2.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/2.imageset/1 2.png deleted file mode 100644 index 6e81d85..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/2.imageset/1 2.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/2.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/2.imageset/Contents.json deleted file mode 100644 index 02f75fb..0000000 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/2.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "1 2.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/1.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Contents.json similarity index 70% rename from Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/1.imageset/Contents.json rename to Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Contents.json index 38ee28b..8735ddf 100644 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/1.imageset/Contents.json +++ b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "1.png", + "filename" : "Group 415.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Group 415@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "Group 415@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415.png new file mode 100644 index 0000000..5410de5 Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415@2x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415@2x.png new file mode 100644 index 0000000..4d65c22 Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415@2x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415@3x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415@3x.png new file mode 100644 index 0000000..e8b69fd Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad1.imageset/Group 415@3x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/green.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Contents.json similarity index 70% rename from Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/green.imageset/Contents.json rename to Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Contents.json index a6a471f..8735ddf 100644 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/green.imageset/Contents.json +++ b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "green.png", + "filename" : "Group 415.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Group 415@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "Group 415@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415.png new file mode 100644 index 0000000..5410de5 Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415@2x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415@2x.png new file mode 100644 index 0000000..4d65c22 Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415@2x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415@3x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415@3x.png new file mode 100644 index 0000000..e8b69fd Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 415@3x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/blue.imageset/blue.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/blue.imageset/blue.png deleted file mode 100644 index 6304b13..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/blue.imageset/blue.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/green.imageset/green.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/green.imageset/green.png deleted file mode 100644 index 3062d8f..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/green.imageset/green.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/orange.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/orange.imageset/Contents.json deleted file mode 100644 index 724afb0..0000000 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/orange.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "orange.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/orange.imageset/orange.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/orange.imageset/orange.png deleted file mode 100644 index da3bdd0..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/orange.imageset/orange.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/red.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/red.imageset/Contents.json deleted file mode 100644 index 1dd4189..0000000 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/red.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "red.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/red.imageset/red.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/red.imageset/red.png deleted file mode 100644 index fbba1b5..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/red.imageset/red.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/yellow.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/yellow.imageset/Contents.json deleted file mode 100644 index 788ea10..0000000 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/yellow.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "yellow.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/yellow.imageset/yellow.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/yellow.imageset/yellow.png deleted file mode 100644 index ece37f3..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/yellow.imageset/yellow.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/blue.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Contents.json similarity index 72% rename from Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/blue.imageset/Contents.json rename to Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Contents.json index ecd0aa4..df240cf 100644 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/blue.imageset/Contents.json +++ b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "blue.png", + "filename" : "Vector.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Vector@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "Vector@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector.png new file mode 100644 index 0000000..87443fb Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector@2x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector@2x.png new file mode 100644 index 0000000..31ab7eb Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector@2x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector@3x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector@3x.png new file mode 100644 index 0000000..79a125f Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_location.imageset/Vector@3x.png differ diff --git "a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/Contents.json" "b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/Contents.json" index e381391..0985671 100644 --- "a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/Contents.json" +++ "b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/Contents.json" @@ -11,7 +11,7 @@ "scale" : "2x" }, { - "filename" : "화이트.png", + "filename" : "Rectangle 111.png", "idiom" : "universal", "scale" : "3x" } diff --git "a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/\355\231\224\354\235\264\355\212\270.png" "b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/Rectangle 111.png" similarity index 100% rename from "Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/\355\231\224\354\235\264\355\212\270.png" rename to "Drink-EG/Drink-EG/Resources/Assets.xcassets/Kind/\355\231\224\354\235\264\355\212\270.imageset/Rectangle 111.png" diff --git a/Drink-EG/Drink-EG/Sources/Datas/NoteResponse.swift b/Drink-EG/Drink-EG/Sources/Datas/NoteResponse.swift new file mode 100644 index 0000000..36a7a48 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Datas/NoteResponse.swift @@ -0,0 +1,30 @@ +// +// NoteResponse.swift +// Drink-EG +// +// Created by 김도연 on 8/16/24. +// + +import Foundation + +struct NoteResponse : Codable { + let noteId : Int + let wineId : Int + let name : String + let picture : String + let color : String + let sugarContent : Int + let acidity : Int + let tannin : Int + let body : Int + let alcohol : Int + let scentAroma : [String] + let scentTaste : [String] + let scentFinish : [String] + let satisfaction : Double + let review : String? +} + +struct ResponseWrap: Codable { + let result: NoteResponse +} diff --git a/Drink-EG/Drink-EG/Sources/Datas/Search/WineInfoResponse.swift b/Drink-EG/Drink-EG/Sources/Datas/Search/WineInfoResponse.swift new file mode 100644 index 0000000..5113b8e --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Datas/Search/WineInfoResponse.swift @@ -0,0 +1,26 @@ +// +// WineInfoResponse.swift +// Drink-EG +// +// Created by 이현주 on 8/16/24. +// + +import Foundation + +struct WineInfo: Decodable { + let wineId: Int + let name: String + let imageUrl: String? + let price: Int + let sort: String + let area: String + let sugarContent: Int + let acidity: Int + let tannin: Int + let body: Int + let alcohol: Int + let scentAroma: [String] + let scentTaste: [String] + let scentFinish: [String] + let rating: Double +} diff --git a/Drink-EG/Drink-EG/Sources/Datas/Search/WineSearchResponse.swift b/Drink-EG/Drink-EG/Sources/Datas/Search/WineSearchResponse.swift new file mode 100644 index 0000000..66a7f49 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Datas/Search/WineSearchResponse.swift @@ -0,0 +1,16 @@ +// +// WineSearchResponse.swift +// Drink-EG +// +// Created by 이현주 on 8/16/24. +// + +import Foundation + +struct Wine: Decodable { + let wineId: Int + let name: String + let imageUrl: String? + let rating: Double + let price: Int +} diff --git a/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseNoteResponse.swift b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseNoteResponse.swift new file mode 100644 index 0000000..dd919ca --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseNoteResponse.swift @@ -0,0 +1,15 @@ +// +// APIResponseNoteResponse.swift +// Drink-EG +// +// Created by 김도연 on 8/16/24. +// + +import Foundation + +struct APIResponseNoteResponse : Codable { + let isSuccess : Bool + let code : String + let message : String + let result : NoteResponse +} diff --git a/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseWineInfoResponse.swift b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseWineInfoResponse.swift new file mode 100644 index 0000000..a99d304 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseWineInfoResponse.swift @@ -0,0 +1,15 @@ +// +// APIResponseWineInfoResponse.swift +// Drink-EG +// +// Created by 이현주 on 8/16/24. +// + +import Foundation + +struct APIResponseWineInfoResponse: Decodable { + let isSuccess: Bool + let code: String + let message: String + let result: WineInfo +} diff --git a/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseWineSearchResponse.swift b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseWineSearchResponse.swift new file mode 100644 index 0000000..fc148b0 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseWineSearchResponse.swift @@ -0,0 +1,15 @@ +// +// APIResponseWineSearchResponse.swift +// Drink-EG +// +// Created by 이현주 on 8/16/24. +// + +import Foundation + +struct APIResponseWineSearchResponse: Decodable { + let isSuccess: Bool + let code: String + let message: String + let result: [Wine] +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/AddNewNoteViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/AddNewNoteViewController.swift index c940314..7422010 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/AddNewNoteViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/AddNewNoteViewController.swift @@ -9,16 +9,16 @@ import Foundation import UIKit import SnapKit import Moya - +import SDWebImage class AddNewNoteViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate { - let provider = MoyaProvider() + let provider = MoyaProvider(plugins: [CookiePlugin()]) let tastingnoteLabel = UILabel() let suggestionTableView = UITableView() - var suggestion: [String] = [] - var allSuggestion: [String] = ["19 Crhnes", "John Kosovich", "CNDULE", "Orange", "Watermelon", "Strawberry"] + + var wineResults: [Wine] = [] lazy var wineSearchBar: UISearchBar = { let s = UISearchBar() @@ -48,7 +48,6 @@ class AddNewNoteViewController: UIViewController, UITableViewDataSource, UITable override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white - setupAPI() setupView() setupLabel() setuptastingnoteLabelConstraints() @@ -116,29 +115,22 @@ class AddNewNoteViewController: UIViewController, UITableViewDataSource, UITable } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { - filterSuggestions(with: searchText) - } - - func filterSuggestions(with query: String) { - if query.isEmpty { - suggestion = [] + if searchText.isEmpty { + wineResults = [] + suggestionTableView.reloadData() } else { - suggestion = allSuggestion.filter { $0.lowercased().contains(query.lowercased()) } + fetchWineSuggestion(with: searchText) } - suggestionTableView.reloadData() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return suggestion.count + return wineResults.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomSuggestionCell - let imageName = "Loxton" - let image = UIImage(named: imageName)! - cell.backgroundColor = UIColor(hex: "E5E5E5") - cell.layer.cornerRadius = 10 - cell.configure(image: image, text: suggestion[indexPath.row], isSelected: false) + let wine = wineResults[indexPath.row] + cell.configure(with: wine, isSelected: false) return cell } @@ -151,26 +143,35 @@ class AddNewNoteViewController: UIViewController, UITableViewDataSource, UITable } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let selectedSuggestion = suggestion[indexPath.row] - wineSearchBar.text = selectedSuggestion - suggestion = [] + let selectedWine = wineResults[indexPath.row] + wineSearchBar.text = selectedWine.name + wineResults = [] suggestionTableView.reloadData() + + // 다음 화면으로 이동 let nextVC = WriteNoteViewController() + nextVC.selectedWineName = selectedWine.name + nextVC.selectedWineImage = selectedWine.imageUrl + nextVC.selectedWineId = selectedWine.wineId navigationController?.pushViewController(nextVC, animated: true) } - - func setupAPI() { - provider.request(.getWineName(wineName: "19 Crhnes")) { result in + + func fetchWineSuggestion(with query: String) { + provider.request(.getWineName(wineName: query)) { result in switch result { case .success(let response): do { - let data = try response.mapJSON() - print(data) + let responseData = try JSONDecoder().decode(APIResponseWineSearchResponse.self, from: response.data) + self.wineResults = responseData.result + self.suggestionTableView.reloadData() } catch { - print(error) + print("Failed to decode response: \(error)") } case.failure(let error): - print("Error: \(error)") + print("Error: \(error.localizedDescription)") + if let response = error.response { + print("Response Body: \(String(data: response.data, encoding: .utf8) ?? "")") + } } } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/ChooseTasteViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/ChooseTasteViewController.swift index b3269bc..653749e 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/ChooseTasteViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/ChooseTasteViewController.swift @@ -11,8 +11,6 @@ import SnapKit class ChooseTasteViewController: UIViewController { - var dataList: [RadarChartData] = [] - let colorView = UIView() let colorBox = UIView() let colorLabel = UILabel() @@ -32,7 +30,12 @@ class ChooseTasteViewController: UIViewController { let nextButton = UIButton() let scrollView = UIScrollView() let contentView = UIView() + + var dataList: [RadarChartData] = [] var receivedColor = "" + var selectedWineId: Int? + var selectedWineImage: String? + var selectedWineName: String? override func viewDidLoad() { super.viewDidLoad() @@ -67,13 +70,6 @@ class ChooseTasteViewController: UIViewController { setupNextButtonConstraints() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - self.navigationController?.setNavigationBarHidden(false, animated: animated) - self.navigationController?.navigationBar.barTintColor = UIColor.red // 네비게이션 바 배경색 - self.navigationController?.navigationBar.tintColor = UIColor.red // 네비게이션 아이템 색상 - } - func setupNavigationBarButton() { navigationItem.hidesBackButton = true let backArrow = UIImage(systemName: "chevron.backward") @@ -98,7 +94,7 @@ class ChooseTasteViewController: UIViewController { contentView.snp.makeConstraints { make in make.edges.equalTo(scrollView) make.width.equalTo(scrollView) - make.height.greaterThanOrEqualTo(1374) + make.height.equalTo(UIScreen.main.bounds.height * 1.6) } } @@ -139,7 +135,11 @@ class ChooseTasteViewController: UIViewController { wineImageView.contentMode = .scaleAspectFit wineImageView.layer.cornerRadius = 10 wineImageView.layer.masksToBounds = true - wineImageView.image = UIImage(named: "SampleImage") + if let imageUrl = selectedWineImage, let url = URL(string: imageUrl) { + wineImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) + } else { + wineImageView.image = UIImage(named: "Loxton") + } } func setupWineImageViewConstraints() { @@ -154,8 +154,7 @@ class ChooseTasteViewController: UIViewController { func setupWineName() { wineView.addSubview(wineName) - wineName.text = "19 Crhnes" - + wineName.text = selectedWineName ?? "" } func setupWineNameConstraints() { @@ -256,6 +255,7 @@ class ChooseTasteViewController: UIViewController { func setupTasteOptions() { let array = ["레드베리", "체리", "딸기", "자두", "우드", "바닐라", "훈제", "민트", "너트", "라임", "자몽", "아카시아", "시가", "흙", "가죽", "직접추가"] + let fontSize = UIScreen.main.bounds.width * 0.04 for i in 0.. Void) = {} - private var quantity: Int = 0 { + private var quantity: Int = 1 { didSet { updateNumLabel() } @@ -21,6 +21,8 @@ class CartListCollectionViewCell: UICollectionViewCell { private let CheckImage = UIImage(named: "icon_cartCheck_fill") private let nCheckImage = UIImage(named: "icon_cartCheck_nfill") private let CheckButton = UIButton(type: .custom) + private var shop = "PODO" + private var price = 27000 private let imageView: UIImageView = { let iv = UIImageView() @@ -39,44 +41,7 @@ class CartListCollectionViewCell: UICollectionViewCell { return l1 }() - private let marketNprice: UILabel = { - let l2 = UILabel() - - let firstImageAttachment = NSTextAttachment() - firstImageAttachment.image = UIImage(named: "icon_market") - - let firstImageOffsetY: CGFloat = -2.0 // 텍스트와 이미지의 정렬을 맞추기 위해 조정합니다. - firstImageAttachment.bounds = CGRect(x: 0, y: firstImageOffsetY, width: 12, height: 12) // 이미지의 크기를 설정합니다. - - let secondImageAttachment = NSTextAttachment() - secondImageAttachment.image = UIImage(named: "Vector") - - let secondImageOffsetY: CGFloat = -2.0 // 이미지와 텍스트의 정렬을 맞추기 위해 조정 - secondImageAttachment.bounds = CGRect(x: 0, y: secondImageOffsetY, width: 1, height: 12) - - let completeText = NSMutableAttributedString(string: "") - - // 첫 번째 이미지 추가 - let firstAttachmentString = NSAttributedString(attachment: firstImageAttachment) - completeText.append(firstAttachmentString) - - // 매장 텍스트 추가 - let textBeforeSecondImage = NSAttributedString(string: " PODO ", attributes: [.font: UIFont.systemFont(ofSize: 16)]) - completeText.append(textBeforeSecondImage) - - // 두 번째 이미지 추가 - let secondAttachmentString = NSAttributedString(attachment: secondImageAttachment) - completeText.append(secondAttachmentString) - - // 가격 텍스트 추가 - let textAfterSecondImage = NSAttributedString(string: " 25,000 ₩", attributes: [.font: UIFont.systemFont(ofSize: 16)]) - completeText.append(textAfterSecondImage) - - l2.attributedText = completeText - l2.font = .boldSystemFont(ofSize: 12) - l2.textColor = UIColor(hex: "#767676") - return l2 - }() + let marketNprice = UILabel() private let score: UILabel = { let l3 = UILabel() @@ -183,6 +148,41 @@ class CartListCollectionViewCell: UICollectionViewCell { } } + private func configureMarketNPlace() { + let firstImageAttachment = NSTextAttachment() + firstImageAttachment.image = UIImage(named: "icon_market") + + let firstImageOffsetY: CGFloat = -2.0 // 텍스트와 이미지의 정렬을 맞추기 위해 조정합니다. + firstImageAttachment.bounds = CGRect(x: 0, y: firstImageOffsetY, width: 12, height: 12) // 이미지의 크기를 설정합니다. + + let secondImageAttachment = NSTextAttachment() + secondImageAttachment.image = UIImage(named: "Vector") + + let secondImageOffsetY: CGFloat = -2.0 // 이미지와 텍스트의 정렬을 맞추기 위해 조정 + secondImageAttachment.bounds = CGRect(x: 0, y: secondImageOffsetY, width: 1, height: 12) + + let completeText = NSMutableAttributedString(string: "") + + // 첫 번째 이미지 추가 + let firstAttachmentString = NSAttributedString(attachment: firstImageAttachment) + completeText.append(firstAttachmentString) + + // 매장 텍스트 추가 + let textBeforeSecondImage = NSAttributedString(string: " \(shop) ", attributes: [.font: UIFont.boldSystemFont(ofSize: 12)]) + completeText.append(textBeforeSecondImage) + + // 두 번째 이미지 추가 + let secondAttachmentString = NSAttributedString(attachment: secondImageAttachment) + completeText.append(secondAttachmentString) + + // 가격 텍스트 추가 + let textAfterSecondImage = NSAttributedString(string: " \(price * quantity) ₩", attributes: [.font: UIFont.boldSystemFont(ofSize: 12)]) + completeText.append(textAfterSecondImage) + + marketNprice.attributedText = completeText + marketNprice.textColor = UIColor(hex: "#767676") + } + override init(frame: CGRect) { super.init(frame: frame) setupUI() @@ -195,6 +195,7 @@ class CartListCollectionViewCell: UICollectionViewCell { //레이아웃까지 private func setupUI() { configureCheckButton() + configureMarketNPlace() self.contentView.addSubview(imageView) self.contentView.addSubview(name) diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift index 756de97..51107ce 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift @@ -33,7 +33,7 @@ class HomeViewController: UIViewController { let firstLine = UILabel() let NoteLabel = UILabel() - private var AdContents: [String] = ["1", "2"] + private var AdContents: [String] = ["ad1", "ad2"] private var RecomContents: [String] = ["Red Label", "Castello Monaci", "Loxton"] override func viewDidLoad() { @@ -49,16 +49,16 @@ class HomeViewController: UIViewController { super.viewDidLayoutSubviews() // 버튼 하단에 노란색으로 칠하는 layer 추가 - let yellowLayer = CALayer() - yellowLayer.frame = CGRect(x: 0, y: 72, width: goToNoteButton.frame.width, height: goToNoteButton.frame.height - 72) - yellowLayer.backgroundColor = UIColor(hue: 0.1528, saturation: 0.16, brightness: 1, alpha: 0.8).cgColor + let Layer = CALayer() + Layer.frame = CGRect(x: 0, y: 72, width: goToNoteButton.frame.width, height: goToNoteButton.frame.height - 72) + Layer.backgroundColor = UIColor(hue: 0.0417, saturation: 0.19, brightness: 1, alpha: 0.8).cgColor // 버튼에 layer 추가 - goToNoteButton.layer.addSublayer(yellowLayer) + goToNoteButton.layer.addSublayer(Layer) //layer 위에 label 추가 let titleLabel = UILabel() - titleLabel.text = "테이스팅 노트 바로가기" + titleLabel.text = "테이스팅 노트 작성하기" titleLabel.textColor = .black titleLabel.font = UIFont.boldSystemFont(ofSize: 16) titleLabel.textAlignment = .left @@ -253,8 +253,8 @@ class HomeViewController: UIViewController { } @objc private func noteButtonTapped() { - let noteListViewController = NoteListViewController() - navigationController?.pushViewController(noteListViewController, animated: true) + let addNewNoteViewController = AddNewNoteViewController() + navigationController?.pushViewController(addNewNoteViewController, animated: true) } lazy var AdImageCollectionView: UICollectionView = { @@ -353,7 +353,9 @@ extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelega if collectionView.tag == 2 { selectedWine = RecomContents[indexPath.item] let wineInfoViewController = WineInfoViewController() - wineInfoViewController.wine = selectedWine +// wineInfoViewController.name.text = selectedWine.name +// wineInfoViewController.wineImage = selectedWine.imageUrl +// wineInfoViewController.wineId = selectedWine.wineId navigationController?.pushViewController(wineInfoViewController, animated: true) } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/RecomCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/VCs/Main/RecomCollectionViewCell.swift index c7e3b32..ca6ff06 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/RecomCollectionViewCell.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Main/RecomCollectionViewCell.swift @@ -31,8 +31,7 @@ class RecomCollectionViewCell: UICollectionViewCell { private let view: UIView = { let v = UIView() - v.backgroundColor = UIColor(hue: 55/360, saturation: 16/100, brightness: 100/100, alpha: 1.0) - v.alpha = 0.85 + v.backgroundColor = UIColor(hue: 0.0417, saturation: 0.19, brightness: 1, alpha: 0.7) return v }() diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift index 8178546..1a12701 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift @@ -6,15 +6,23 @@ // import UIKit +import SnapKit + +protocol StoreListDelegate: AnyObject { + func didSelectStore(_ store: String) +} class ShoppingCartListViewController: UIViewController { + var selectedStore: String? + private var CartContents: [String] = ["Red Label", "Castello Monaci", "Loxton", "Samos", "Vendredi"] private var itemsSelectedState: [Bool] = [] private let allCheckImage = UIImage(named: "icon_cartCheck_fill") private let nAllCheckImage = UIImage(named: "icon_cartCheck_nfill") private let allCheckButton = UIButton(type: .custom) + private let allCheckLabel = UILabel() private let label: UILabel = { let l = UILabel() @@ -25,14 +33,6 @@ class ShoppingCartListViewController: UIViewController { return l }() - private let allCheckLabel: UILabel = { - let l = UILabel() - l.text = "전체 선택 (1/3)" - l.font = .boldSystemFont(ofSize: 14) - l.textColor = UIColor(hex: "#767676") - return l - }() - private let checkDeleteButton: UIButton = { let b = UIButton(type: .system) b.setTitle("선택 삭제", for: .normal) @@ -85,9 +85,21 @@ class ShoppingCartListViewController: UIViewController { setupUI() } + func didSelectStore(_ store: String) { + self.selectedStore = store + updateStoreInCart() + } + + func updateStoreInCart() { + // 여기서 장바구니 셀의 매장 이름을 변경하는 코드를 작성합니다. + + cartListCollectionView.reloadData() + } + private func setupUI() { configureAllCheckButton() + configureAllCheckLabel() view.addSubview(label) label.snp.makeConstraints { make in @@ -122,7 +134,7 @@ class ShoppingCartListViewController: UIViewController { view.addSubview(cartListCollectionView) cartListCollectionView.snp.makeConstraints { make in - make.top.equalTo(allCheckLabel.snp.bottom).offset(20) + make.top.equalTo(allCheckLabel.snp.bottom).offset(10) make.centerX.equalToSuperview() make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) make.bottom.equalTo(buyButton.snp.top).offset(-20) @@ -142,26 +154,15 @@ class ShoppingCartListViewController: UIViewController { // 버튼이 클릭될 때마다, 버튼 이미지를 변환 if sender.isSelected { sender.setImage(allCheckImage?.withRenderingMode(.alwaysOriginal), for: .selected) - updateAllItemsSelection(isSelected: true) } else { sender.setImage(nAllCheckImage?.withRenderingMode(.alwaysOriginal), for: .normal) - updateAllItemsSelection(isSelected: false) } } - private func updateAllItemsSelection(isSelected: Bool) { - // 모든 항목의 선택 상태를 변경 - itemsSelectedState = Array(repeating: isSelected, count: itemsSelectedState.count) - - // 모든 셀을 업데이트 - for section in 0.. CGSize { return CGSize(width: collectionView.frame.width, height: 120) } diff --git a/Drink-EG/Drink-EG/Sources/VCs/NoteInfoViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/NoteInfoViewController.swift index e075624..0ff76cc 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/NoteInfoViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/NoteInfoViewController.swift @@ -19,10 +19,15 @@ class NoteInfoViewController: UIViewController { let chooseColorView = UIView() let chooseColorLabel = UILabel() let chooseColorButtons = [UIButton(), UIButton(), UIButton(), UIButton(), UIButton(), UIButton()] - var dataList: [RadarChartData] = [] let scrollView = UIScrollView() let contentView = UIView() + var selectedWineId: Int? + var selectedWineImage: String? + var selectedWineName: String? + var dataList: [RadarChartData] = [] + + override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white @@ -58,7 +63,7 @@ class NoteInfoViewController: UIViewController { contentView.snp.makeConstraints { make in make.edges.equalTo(scrollView) make.width.equalTo(scrollView) - make.height.greaterThanOrEqualTo(860) + make.height.equalTo(UIScreen.main.bounds.height) } } @@ -102,7 +107,7 @@ class NoteInfoViewController: UIViewController { make.top.equalTo(wineView.snp.bottom).offset(10) make.centerX.equalTo(contentView.safeAreaLayoutGuide.snp.centerX) make.leading.equalTo(wineView.snp.leading) - make.height.greaterThanOrEqualTo(349) + make.height.equalTo(UIScreen.main.bounds.height * 0.45) } } @@ -119,7 +124,7 @@ class NoteInfoViewController: UIViewController { make.top.equalTo(tastingnoteLabel.snp.bottom).offset(32) make.centerX.equalTo(view.safeAreaLayoutGuide.snp.centerX) make.leading.equalTo(tastingnoteLabel.snp.leading) - make.height.greaterThanOrEqualTo(83) + make.height.equalTo(UIScreen.main.bounds.height * 0.12) } } @@ -128,7 +133,11 @@ class NoteInfoViewController: UIViewController { wineImageView.contentMode = .scaleAspectFit wineImageView.layer.cornerRadius = 10 wineImageView.layer.masksToBounds = true - wineImageView.image = UIImage(named: "SampleImage") + if let imageUrl = selectedWineImage, let url = URL(string: imageUrl) { + wineImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) + } else { + wineImageView.image = UIImage(named: "Loxton") + } } func setupWineImageViewConstraints() { @@ -143,7 +152,7 @@ class NoteInfoViewController: UIViewController { func setupWineName() { wineView.addSubview(wineName) - wineName.text = "19 Crhnes" + wineName.text = selectedWineName ?? "" } @@ -169,7 +178,7 @@ class NoteInfoViewController: UIViewController { make.top.equalTo(pentagonChart.snp.bottom).offset(10) make.centerX.equalTo(wineView.snp.centerX) make.leading.equalTo(pentagonChart.snp.leading) - make.height.greaterThanOrEqualTo(317) + make.height.equalTo(UIScreen.main.bounds.height * 0.21) } } @@ -211,7 +220,7 @@ class NoteInfoViewController: UIViewController { let button = chooseColorButtons[i] button.snp.makeConstraints{ make in make.top.equalTo(chooseColorLabel.snp.bottom).offset(10) - make.width.height.equalTo(40) // 수정 필요 + make.width.height.equalTo(chooseColorView.snp.height).multipliedBy(0.22) // 수정 필요 if i == 0 { make.leading.equalTo(chooseColorView.snp.leading).offset(19) } else { @@ -231,6 +240,10 @@ class NoteInfoViewController: UIViewController { vc.dataList = dataList vc.receivedColor = buttonColor! + vc.selectedWineId = selectedWineId + vc.selectedWineImage = selectedWineImage + vc.selectedWineName = selectedWineName + navigationController?.pushViewController(vc, animated: true) } diff --git a/Drink-EG/Drink-EG/Sources/VCs/NoteListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/NoteListViewController.swift index 43f48b9..cc8ba2d 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/NoteListViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/NoteListViewController.swift @@ -84,17 +84,33 @@ class NewNoteFooter: UICollectionReusableView { } } +struct Note: Decodable { + let noteId: Int + let name: String + let imageUrl: String +} + +struct AllNotesResponse: Decodable { + let isSuccess: Bool + let code: String + let message: String + let result: [Note] +} + // NoteListViewController는 사용자가 작성한 테이스팅 노트를 확인 및 새로 작성할 수 있는 뷰 class NoteListViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, NewNoteFooterDelegate { - let provider = MoyaProvider() + let provider = MoyaProvider(plugins: [CookiePlugin()]) let noteListLabel = UILabel() // 노트 보관함 Label var noteListGrid: UICollectionView! // 테이스팅 노트를 보관할 CollectionView let images = ["Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci", "Castello Monaci"] + var apiResult: [[String: String]] = [] + var cellCount: Int = 0 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + self.navigationController?.setNavigationBarHidden(true, animated: animated) setupAPI() } @@ -149,22 +165,15 @@ class NoteListViewController: UIViewController, UICollectionViewDelegate, UIColl layout.minimumInteritemSpacing = 22 layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) layout.footerReferenceSize = CGSize(width: view.frame.width, height: 60) + noteListGrid = UICollectionView(frame: .zero, collectionViewLayout: layout) noteListGrid.backgroundColor = .clear noteListGrid.layer.cornerRadius = 36 noteListGrid.layer.maskedCorners = CACornerMask(arrayLiteral: .layerMaxXMinYCorner) noteListGrid.layer.borderWidth = 1 - noteListGrid.layer.borderColor = UIColor.white.cgColor - - let shadowPath = UIBezierPath(roundedRect: noteListGrid.bounds, cornerRadius: 36) - noteListGrid.layer.shadowPath = shadowPath.cgPath - noteListGrid.layer.shadowColor = UIColor(red: 0.98, green: 0.451, blue: 0.357, alpha: 0.2).cgColor - noteListGrid.layer.shadowOpacity = 1 - noteListGrid.layer.shadowRadius = 20 - noteListGrid.layer.shadowOffset = CGSize(width: 4, height: -14) - noteListGrid.layer.masksToBounds = false - + noteListGrid.layer.borderColor = UIColor.clear.cgColor + noteListGrid.dataSource = self noteListGrid.delegate = self noteListGrid.register(NoteCollectionViewCell.self, forCellWithReuseIdentifier: "cell") @@ -182,18 +191,26 @@ class NoteListViewController: UIViewController, UICollectionViewDelegate, UIColl make.top.equalTo(noteListLabel.snp.bottom).offset(35) } } + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { // CollectionView Cell 개수를 설정하는 함수 - return 7 + return cellCount } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // 재사용 가능한 셀을 가져와서 NoteCollectionViewCell로 캐스팅 let cell = noteListGrid.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! NoteCollectionViewCell - cell.imageView.image = UIImage(named: "Castello Monaci") - cell.nameLabel.text = "와인 이름\n1999" + + let wineData = apiResult[indexPath.row] + + cell.nameLabel.text = wineData["name"] cell.nameLabel.numberOfLines = 2 cell.nameLabel.font = UIFont(name: "Pretendard-Bold", size: 14) cell.backgroundColor = .clear + if let imageUrl = wineData["imageUrl"], let url = URL(string: imageUrl) { + cell.imageView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder")) + } else { + cell.imageView.image = UIImage(named: "placeholder") + } return cell } @@ -210,6 +227,113 @@ class NoteListViewController: UIViewController, UICollectionViewDelegate, UIColl return CGSize(width: width, height: height) } + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let selectedNoteId = apiResult[indexPath.row]["noteId"] // noteId 가져오기 + guard let noteId = Int(selectedNoteId ?? "") else { return } + + fetchNoteDetails(noteId: noteId) + } + + func fetchNoteDetails(noteId: Int) { + provider.request(TastingNoteAPI.getNoteID(noteId: noteId)) { result in + switch result { + case .success(let response): + do { + // JSON 데이터를 문자열로 변환하여 출력 + if let jsonString = String(data: response.data, encoding: .utf8) { + print("Response JSON String: \(jsonString)") + } + + // ResponseWrap 구조체로 디코딩 + let noteResponse = try JSONDecoder().decode(ResponseWrap.self, from: response.data) + self.handleNoteData(noteResponse.result) + } catch { + print("Failed to decode response: \(error)") + } + case .failure(let error): + print("Request failed: \(error)") + } + } + } + + func handleNoteData(_ data: NoteResponse) { + let scentData: [String: [String]] = [ + "scentAroma": data.scentAroma.map { $0.unescapedString }, + "scentTaste": data.scentTaste.map { $0.unescapedString }, + "scentFinish": data.scentFinish.map { $0.unescapedString } + ] + + let dataList: [RadarChartData] = [ + RadarChartData(type: .acid, value: data.acidity), + RadarChartData(type: .tannin, value: data.tannin), + RadarChartData(type: .alcohol, value: data.alcohol), + RadarChartData(type: .bodied, value: data.body), + RadarChartData(type: .sweetness, value: data.sugarContent) + ] + + let nextVC = CheckNoteViewController() + nextVC.reviewString = data.review?.unescapedString ?? "" + nextVC.value = data.satisfaction + nextVC.dataList = dataList + nextVC.selectedOptions = scentData + nextVC.selectedWineName = data.name + nextVC.selectedWineImage = data.picture + + self.navigationController?.pushViewController(nextVC, animated: true) + } + +// func handleNoteDetailsResponse(_ response: Response) { +// do { +// if let jsonData = try response.mapJSON() as? [String: Any] { +// // 응답 데이터를 콘솔에 출력 +// print("Response JSON: \(jsonData)") +// +// if let resultData = jsonData["result"] as? [String: Any] { +// let scentAroma = (resultData["scentAroma"] as? [String] ?? []).map { $0.unescapedString } +// let scentTaste = (resultData["scentTaste"] as? [String] ?? []).map { $0.unescapedString } +// let scentFinish = (resultData["scentFinish"] as? [String] ?? []).map { $0.unescapedString } +// +// let review = (resultData["review"] as? String ?? "").unescapedString +// let satisfaction = resultData["satisfaction"] as? Int ?? 0 +// let sugarContent = resultData["sugarContent"] as? Int ?? 0 +// let acidity = resultData["acidity"] as? Int ?? 0 +// let tannin = resultData["tannin"] as? Int ?? 0 +// let alcohol = resultData["alcohol"] as? Int ?? 0 +// let body = resultData["body"] as? Int ?? 0 +// let wineName = resultData["name"] as? String ?? "" +// let wineImageUrl = resultData["picture"] as? String ?? "" +// +// let scentData: [String: [String]] = [ +// "scentAroma": scentAroma, +// "scentTaste": scentTaste, +// "scentFinish": scentFinish +// ] +// +// let dataList: [RadarChartData] = [ +// RadarChartData(type: .acid, value: acidity), +// RadarChartData(type: .tannin, value: tannin), +// RadarChartData(type: .alcohol, value: alcohol), +// RadarChartData(type: .bodied, value: body), +// RadarChartData(type: .sweetness, value: sugarContent) +// ] +// +// let nextVC = CheckNoteViewController() +// nextVC.reviewString = review +// nextVC.value = Double(satisfaction) +// nextVC.dataList = dataList +// nextVC.selectedOptions = scentData +// nextVC.selectedWineName = wineName +// nextVC.selectedWineImage = wineImageUrl +// +// self.navigationController?.pushViewController(nextVC, animated: true) +// } +// } +// } catch { +// print("Failed to map data: \(error)") +// } +// } + + // MARK: "새로 적기" 버튼에 관한 UI func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if kind == UICollectionView.elementKindSectionFooter { @@ -231,7 +355,15 @@ class NoteListViewController: UIViewController, UICollectionViewDelegate, UIColl switch result { case .success(let response): do { - let data = try response.mapJSON() + let data = try response.map(AllNotesResponse.self) + self.cellCount = data.result.count + for note in data.result { + let wineData: [String: String] = ["noteId": "\(note.noteId)", "name": note.name, "imageUrl": note.imageUrl] + self.apiResult.append(wineData) + } + print(self.apiResult) + print(self.cellCount) + self.noteListGrid.reloadData() print("User Data: \(data)") } catch { print("Failed to map data: \(error)") @@ -242,3 +374,11 @@ class NoteListViewController: UIViewController, UICollectionViewDelegate, UIColl } } } + +extension String { + var unescapedString: String { + var mutableString = NSMutableString(string: self) + CFStringTransform(mutableString, nil, "Any-Hex/Java" as NSString, true) + return mutableString as String + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListCollectionViewCell.swift new file mode 100644 index 0000000..9d6af5b --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListCollectionViewCell.swift @@ -0,0 +1,97 @@ +// +// ReviewListCollectionViewCell.swift +// Drink-EG +// +// Created by 이현주 on 8/15/24. +// + +import UIKit +import SnapKit + +class ReviewListCollectionViewCell: UICollectionViewCell { + + var score = 4.5 + private let scoreLabel = UILabel() + + private let name: UILabel = { + let l = UILabel() + l.font = .boldSystemFont(ofSize: 16) + l.textColor = .black + l.numberOfLines = 1 // 한 줄로 표시 + l.adjustsFontSizeToFitWidth = true // 텍스트가 레이블 너비에 맞도록 크기 조정 + l.minimumScaleFactor = 0.5 // 텍스트 크기가 최소 50% 까지 줄어들 수 있음 + return l + }() + + private let stick: UIView = { + let v = UIView() + v.backgroundColor = UIColor(hex: "#FA735B") + return v + }() + + private let content: UILabel = { + let l = UILabel() + l.font = .boldSystemFont(ofSize: 12) + l.textColor = UIColor(hex: "767676") + l.text = "맛있어요." + l.numberOfLines = 0 + return l + }() + + private func configureScore() { + scoreLabel.text = "★ \(score)" + scoreLabel.font = .boldSystemFont(ofSize: 14) + scoreLabel.textColor = UIColor(hex: "#FB5133") + } + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //레이아웃까지 + private func setupUI() { + configureScore() + + self.contentView.addSubview(name) + self.contentView.addSubview(stick) + self.contentView.addSubview(scoreLabel) + self.contentView.addSubview(content) + self.contentView.backgroundColor = UIColor(hex: "F8F8FA") + self.contentView.layer.borderWidth = 0 + self.contentView.layer.cornerRadius = 10 + self.contentView.layer.masksToBounds = true + + stick.snp.makeConstraints { make in + make.top.bottom.equalToSuperview().inset(13) + make.leading.equalToSuperview().offset(94) + make.width.equalTo(1) + } + + name.snp.makeConstraints { make in + make.top.equalToSuperview().offset(15) + make.centerX.equalTo(contentView.snp.leading).offset(47) + make.width.lessThanOrEqualTo(70) + } + + content.snp.makeConstraints { make in + make.top.equalToSuperview().offset(13) + make.leading.equalTo(stick.snp.trailing).offset(22) + make.width.lessThanOrEqualTo(234) + make.height.lessThanOrEqualTo(88) + } + + scoreLabel.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(14) + make.centerX.equalTo(name) + } + } + + func configure(name: String) { + self.name.text = name + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListViewController.swift new file mode 100644 index 0000000..a4880b6 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListViewController.swift @@ -0,0 +1,148 @@ +// +// ReviewListViewController.swift +// Drink-EG +// +// Created by 이현주 on 8/15/24. +// + +import UIKit + +class ReviewListViewController: UIViewController { + + private var ReviewContents: [String] = ["lhj1024", "dyk1234", "leeeSh0101", "hoooyeon56"] + + var score = 4.5 + private let scoreLabel = UILabel() + + private let label: UILabel = { + let l = UILabel() + l.text = "다른유저 리뷰" + l.font = .systemFont(ofSize: 28, weight: UIFont.Weight(700)) + l.textColor = .black + l.numberOfLines = 0 + return l + }() + + private let stick: UIView = { + let s = UIView() + s.backgroundColor = UIColor(hex: "FA735B") + s.layer.borderWidth = 0 + return s + }() + + private let name: UILabel = { + let l = UILabel() + l.text = "Red Label" + l.font = .boldSystemFont(ofSize: 22) + l.textColor = .black + return l + }() + + private let image: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "Red Label") + i.layer.cornerRadius = 10 + i.layer.masksToBounds = true + return i + }() + + lazy var reviewListCollectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + layout.sectionInset = UIEdgeInsets(top: 30, left: 0, bottom: 40, right: 0) + + let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) + cv.register(ReviewListCollectionViewCell.self, forCellWithReuseIdentifier: "ReviewListCollectionViewCell") + cv.translatesAutoresizingMaskIntoConstraints = false + cv.showsVerticalScrollIndicator = false + cv.delegate = self + cv.dataSource = self + + cv.decelerationRate = .fast + cv.backgroundColor = UIColor(hex: "#E5E5E5") + cv.layer.cornerRadius = 25 + cv.layer.maskedCorners = CACornerMask(arrayLiteral: .layerMinXMinYCorner, .layerMaxXMinYCorner) + + return cv + }() + + + override func viewDidLoad() { + super.viewDidLoad() + + self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) + + view.backgroundColor = .white + setupUI() + } + + private func setupUI() { + configureScore() + + view.addSubview(label) + label.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(20) + make.leading.equalTo(view.safeAreaLayoutGuide).offset(27) + } + + view.addSubview(stick) + stick.snp.makeConstraints { make in + make.top.equalTo(label.snp.bottom).offset(31) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) + make.height.equalTo(1.5) + } + + view.addSubview(image) + image.snp.makeConstraints { make in + make.top.equalTo(stick.snp.bottom).offset(17) + make.leading.equalTo(stick) + make.width.lessThanOrEqualTo(110) + make.height.lessThanOrEqualTo(140) + } + + view.addSubview(name) + name.snp.makeConstraints { make in + make.top.equalTo(image) + make.leading.equalTo(image.snp.trailing).offset(16) + } + + view.addSubview(scoreLabel) + scoreLabel.snp.makeConstraints { make in + make.centerY.equalTo(name) + make.trailing.equalTo(view.safeAreaLayoutGuide).inset(20) + } + + view.addSubview(reviewListCollectionView) + reviewListCollectionView.snp.makeConstraints { make in + make.top.equalTo(image.snp.bottom).offset(22) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalTo(view.safeAreaLayoutGuide) + } + } + + private func configureScore() { + scoreLabel.text = "★ \(score)" + scoreLabel.font = .boldSystemFont(ofSize: 14) + scoreLabel.textColor = UIColor(hex: "#FA735B") + } + +} + +extension ReviewListViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return ReviewContents.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ReviewListCollectionViewCell", for: indexPath) as! ReviewListCollectionViewCell + + cell.configure(name: ReviewContents[indexPath.item]) + + return cell + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: collectionView.frame.width - 32, height: 110) + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift index e358e42..9bb448f 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift @@ -7,12 +7,14 @@ import UIKit import SnapKit +import Moya +import SDWebImage class SearchHomeViewController : UIViewController, UISearchBarDelegate { - var selectedWine: String? - var suggestion: [String] = [] - var allSuggestion: [String] = ["Castello Monaci", "Dos Copas", "Loxton", "Red Label", "Samos", "Vendredi"] + let provider = MoyaProvider(plugins: [CookiePlugin()]) + + var wineResults: [Wine] = [] lazy var searchBar: UISearchBar = { let s = UISearchBar() @@ -120,46 +122,63 @@ class SearchHomeViewController : UIViewController, UISearchBarDelegate { func filterSuggestions(with query: String) { if query.isEmpty { - suggestion = [] + wineResults = [] + WineListCollectionView.reloadData() } else { - suggestion = allSuggestion.filter { $0.lowercased().contains(query.lowercased()) } + fetchWineSuggestion(with: query) } - WineListCollectionView.reloadData() } } extension SearchHomeViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return suggestion.count + return wineResults.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WineListCollectionViewCell", for: indexPath) as! WineListCollectionViewCell - cell.configure(imageName: suggestion[indexPath.item]) + let wine = wineResults[indexPath.row] + cell.configure(wine: wine) return cell } - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { -// let wineInfoViewController = WineInfoViewController() -// navigationController?.pushViewController(wineInfoViewController, animated: true) - selectedWine = suggestion[indexPath.item] - let wineInfoViewController = WineInfoViewController() -// wineInfoViewController.modalPresentationStyle = .fullScreen - wineInfoViewController.wine = selectedWine - self.present(wineInfoViewController, animated: true) - } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: collectionView.frame.width, height: 94) } - private func collectionView(_ collectionView: UICollectionView, didSelectRowAt indexPath: IndexPath) { - let selectedSuggestion = suggestion[indexPath.row] - searchBar.text = selectedSuggestion - suggestion = [] + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let selectedWine = wineResults[indexPath.row] + searchBar.text = selectedWine.name + wineResults = [] WineListCollectionView.reloadData() + + let wineInfoViewController = WineInfoViewController() + wineInfoViewController.name.text = selectedWine.name + wineInfoViewController.wineImage = selectedWine.imageUrl + wineInfoViewController.wineId = selectedWine.wineId + navigationController?.pushViewController(wineInfoViewController, animated: true) + } + + func fetchWineSuggestion(with query: String) { + provider.request(.getWineName(wineName: query)) { result in + switch result { + case .success(let response): + do { + let responseData = try JSONDecoder().decode(APIResponseWineSearchResponse.self, from: response.data) + self.wineResults = responseData.result + self.WineListCollectionView.reloadData() + } catch { + print("Failed to decode response: \(error)") + } + case.failure(let error): + print("Error: \(error.localizedDescription)") + if let response = error.response { + print("Response Body: \(String(data: response.data, encoding: .utf8) ?? "")") + } + } + } } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift index cf8e029..b291ffd 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift @@ -7,17 +7,31 @@ import UIKit import SnapKit +import SDWebImage +import Moya class WineInfoViewController: UIViewController { - var wine: String? + let provider = MoyaProvider(plugins: [CookiePlugin()]) + + var wineImage: String? + var wineId: Int? + + var sweetness: Int = 0 + var acid: Int = 0 + var tannin: Int = 0 + var bodied: Int = 0 + var alcohol: Int = 0 + var aroma: String = "" + var taste: String = "" + var finish: String = "" let pentagonChart = PolygonChartView() - var dataList: [RadarChartData] = [RadarChartData(type: .sweetness, value: 8), - RadarChartData(type: .acid, value: 6), - RadarChartData(type: .tannin, value: 2), - RadarChartData(type: .bodied, value: 6), - RadarChartData(type: .alcohol, value: 4)] + lazy var dataList: [RadarChartData] = [RadarChartData(type: .sweetness, value: sweetness), + RadarChartData(type: .acid, value: acid), + RadarChartData(type: .tannin, value: tannin), + RadarChartData(type: .bodied, value: bodied), + RadarChartData(type: .alcohol, value: alcohol)] func setupPentagonChart() { pentagonChart.backgroundColor = .clear @@ -34,6 +48,21 @@ class WineInfoViewController: UIViewController { return l }() + let scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.isDirectionalLockEnabled = true + scrollView.showsVerticalScrollIndicator = false + scrollView.translatesAutoresizingMaskIntoConstraints = false + return scrollView + }() + + let contentView: UIView = { + let contentView = UIView() + contentView.translatesAutoresizingMaskIntoConstraints = false + contentView.backgroundColor = .clear + return contentView + }() + private let infoView: UIView = { let v = UIView() v.backgroundColor = UIColor(hex: "#E5E5E5") @@ -42,30 +71,31 @@ class WineInfoViewController: UIViewController { return v }() - private lazy var imageView: UIImageView = { + lazy var imageView: UIImageView = { let iv = UIImageView() - if let wine = wine { - iv.image = UIImage(named: wine) - } iv.layer.cornerRadius = 10 iv.layer.masksToBounds = true + if let imageUrl = wineImage, let url = URL(string: imageUrl) { + iv.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) + } else { + iv.image = UIImage(named: "Loxton") + } return iv }() - private lazy var name: UILabel = { + lazy var name: UILabel = { let l = UILabel() - if let wine = wine { - l.text = wine - } l.font = .boldSystemFont(ofSize: 18) l.textColor = .black l.numberOfLines = 0 + l.adjustsFontSizeToFitWidth = true // 텍스트가 레이블 너비에 맞도록 크기 조정 + l.minimumScaleFactor = 0.5 return l }() private let specInfo: UILabel = { let l = UILabel() - l.text = "종류: 레드 와인\n품종: 쉬라 100%\n생산지: 호주, South Australia" + l.text = "종류: 레드 와인\n생산지: 호주, South Australia" l.font = .systemFont(ofSize: 12) l.textColor = .black l.numberOfLines = 0 @@ -105,28 +135,158 @@ class WineInfoViewController: UIViewController { return l }() + private let explainEntireView: UIView = { + let v = UIView() + v.backgroundColor = .clear + v.layer.cornerRadius = 10 + v.layer.masksToBounds = true + v.layer.borderWidth = 2 + v.layer.borderColor = UIColor(hex: "#E5E5E5")?.cgColor + return v + }() + + private func createLabel(text: String) -> UILabel { + let l = UILabel() + l.font = .boldSystemFont(ofSize: 18) + l.textColor = .black + l.text = text + return l + } + + private var AromaLabel: UILabel { + return createLabel(text: "Aroma") + } + + private var TasteLabel: UILabel { + return createLabel(text: "Taste") + } + + private var FinishLabel: UILabel { + return createLabel(text: "Finish") + } + + private func createButton(title: String) -> UIButton { + let v = UIButton(type: .system) + v.layer.cornerRadius = 18 + v.layer.masksToBounds = true + v.backgroundColor = UIColor(hex: "#FBCBC4") + v.layer.borderWidth = 2 + v.layer.borderColor = UIColor(hue: 0.025, saturation: 0.63, brightness: 0.98, alpha: 0.7).cgColor + + v.setTitle(title, for: .normal) + v.sizeToFit() + v.contentEdgeInsets = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 20) + v.titleLabel?.font = .boldSystemFont(ofSize: 16) + v.setTitleColor(.black, for: .normal) + + return v + } + + private var Aroma: UIButton { + return createButton(title: aroma) + } + + private var Taste: UIButton { + return createButton(title: taste) + } + + private var Finish: UIButton { + return createButton(title: finish) + } + + private let goToReviewButton: UIButton = { + let b = UIButton(type: .system) + b.setTitle("다른 유저 리뷰 보기", for: .normal) + b.setTitleColor(UIColor(hex: "#FA735B"), for: .normal) + b.titleLabel?.font = .boldSystemFont(ofSize: 18) + b.contentHorizontalAlignment = .center + + b.backgroundColor = .white + b.layer.cornerRadius = 25 + b.layer.masksToBounds = true + b.layer.borderWidth = 2 + b.layer.borderColor = UIColor(hex: "#FA735B")?.cgColor + b.addTarget(self, action: #selector(reviewButtonTapped), for: .touchUpInside) + + return b + }() + + @objc private func reviewButtonTapped() { + let reviewListViewController = ReviewListViewController() + navigationController?.pushViewController(reviewListViewController, animated: true) + } + + private let goToShopButton: UIButton = { + let b = UIButton(type: .system) + b.setTitle("판매처 보기", for: .normal) + b.setTitleColor(.white, for: .normal) + b.titleLabel?.font = .boldSystemFont(ofSize: 18) + b.contentHorizontalAlignment = .center + + b.backgroundColor = UIColor(hex: "#FA735B") + b.layer.cornerRadius = 25 + b.layer.masksToBounds = true + b.addTarget(self, action: #selector(shopButtonTapped), for: .touchUpInside) + + return b + }() + + @objc private func shopButtonTapped() { + let wineStoreListViewController = WineStoreListViewController() + navigationController?.pushViewController(wineStoreListViewController, animated: true) + } + override func viewDidLoad() { super.viewDidLoad() self.navigationController?.navigationBar.tintColor = .black + self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) + view.backgroundColor = .white - setupUI() + getWineInfo { [weak self] isSuccess in + if isSuccess { + self?.setupUI() + } else { + print("데이터를 받아오는데 실패했습니다. 다시 시도해주세요.") + } + } } private func setupUI() { + setupPentagonChart() + //MARK: - UI Constraint + // Title Label view.addSubview(label) label.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(20) make.leading.equalTo(view.safeAreaLayoutGuide).offset(27) } - view.addSubview(infoView) + // 하단 전체 스크롤뷰 + view.addSubview(scrollView) + scrollView.snp.makeConstraints { make in + make.top.equalTo(label.snp.bottom).offset(10) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) + } + + // 스크롤뷰 내부 + scrollView.addSubview(contentView) + contentView.snp.makeConstraints { make in + make.edges.equalTo(scrollView.contentLayoutGuide) + make.height.greaterThanOrEqualTo(scrollView.snp.height).priority(.low) + make.width.equalTo(scrollView.frameLayoutGuide) + make.bottom.equalToSuperview().inset(20) + } + + // 상단 와인 정보 + contentView.addSubview(infoView) infoView.snp.makeConstraints { make in - make.top.equalTo(label.snp.bottom).offset(20) - make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(14) + make.top.equalToSuperview().offset(10) + make.leading.trailing.equalToSuperview().inset(14) make.height.lessThanOrEqualTo(101) } @@ -141,6 +301,8 @@ class WineInfoViewController: UIViewController { name.snp.makeConstraints { make in make.top.equalToSuperview().offset(11) make.leading.equalTo(imageView.snp.trailing).offset(20) + make.width.lessThanOrEqualTo(220) + make.height.lessThanOrEqualTo(40) } infoView.addSubview(specInfo) @@ -162,7 +324,8 @@ class WineInfoViewController: UIViewController { make.width.height.equalTo(22) } - view.addSubview(tastingNoteView) + // 스크롤뷰 하단 테이스팅 노트 + contentView.addSubview(tastingNoteView) tastingNoteView.snp.makeConstraints { make in make.top.equalTo(infoView.snp.bottom).offset(10.5) make.leading.trailing.equalTo(infoView) @@ -178,9 +341,114 @@ class WineInfoViewController: UIViewController { tastingNoteView.addSubview(pentagonChart) pentagonChart.snp.makeConstraints{ make in make.top.equalTo(represent.snp.bottom).offset(29) - make.centerX.equalTo(view.safeAreaLayoutGuide.snp.centerX) + make.centerX.equalToSuperview() make.width.equalTo(353) make.height.equalTo(309) } + + // 아로마~등 정보 뷰 + contentView.addSubview(explainEntireView) + explainEntireView.snp.makeConstraints { make in + make.top.equalTo(tastingNoteView.snp.bottom).offset(10.5) + make.leading.trailing.equalTo(tastingNoteView) + make.height.greaterThanOrEqualTo(116) + } + + explainEntireView.addSubview(AromaLabel) + AromaLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(23) + make.leading.equalToSuperview().offset(33) + } + + + + explainEntireView.addSubview(TasteLabel) + TasteLabel.snp.makeConstraints { make in + make.top.equalTo(AromaLabel) + make.centerX.equalToSuperview() + } + + explainEntireView.addSubview(FinishLabel) + FinishLabel.snp.makeConstraints { make in + make.top.equalTo(TasteLabel) + make.trailing.equalToSuperview().inset(33) + } + + explainEntireView.addSubview(Aroma) + explainEntireView.addSubview(Taste) + explainEntireView.addSubview(Finish) + + Aroma.snp.makeConstraints { make in + make.top.equalTo(AromaLabel.snp.bottom).offset(7) + make.centerX.equalTo(AromaLabel) + } + + Taste.snp.makeConstraints { make in + make.top.equalTo(Aroma) + make.centerX.equalTo(TasteLabel) + } + + Finish.snp.makeConstraints { make in + make.top.equalTo(Taste) + make.centerX.equalTo(FinishLabel) + } + + // StackView 정의 + // TODO : 함수 분리 + let stackView = UIStackView(arrangedSubviews: [goToReviewButton, goToShopButton]) + stackView.axis = .horizontal + stackView.distribution = .fillProportionally + stackView.spacing = 9 + + + contentView.addSubview(stackView) + stackView.snp.makeConstraints { make in + make.top.equalTo(explainEntireView.snp.bottom).offset(30) + make.leading.trailing.equalTo(explainEntireView) + make.height.greaterThanOrEqualTo(50) + make.bottom.equalToSuperview().inset(20) + } + + goToReviewButton.snp.makeConstraints { make in + make.width.equalTo(goToShopButton) + } + } +} + +extension WineInfoViewController { + func getWineInfo(completion: @escaping (Bool) -> Void) { + provider.request(.getWineInfo(wineId: self.wineId ?? 1)) { result in + switch result { + case .success(let response): + do { + let responseData = try JSONDecoder().decode(APIResponseWineInfoResponse.self, from: response.data) +// self.handleResponseData() + self.sweetness = responseData.result.sugarContent + self.acid = responseData.result.acidity + self.alcohol = responseData.result.alcohol + self.bodied = responseData.result.body + self.tannin = responseData.result.tannin + self.aroma = responseData.result.scentAroma[0] + self.taste = responseData.result.scentTaste[0] + self.taste = responseData.result.scentFinish[0] + let scoreString: String = String(responseData.result.rating) + self.score.text = scoreString + completion(true) + } catch { + print("Failed to decode response: \(error)") + completion(false) + } + case.failure(let error): + print("Error: \(error.localizedDescription)") + if let response = error.response { + print("Response Body: \(String(data: response.data, encoding: .utf8) ?? "")") + } + completion(false) + } + } + } + + func handleResponseData(_ data: WineInfo) { + } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineListCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineListCollectionViewCell.swift index b9c904e..3de6e3a 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/WineListCollectionViewCell.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineListCollectionViewCell.swift @@ -6,6 +6,8 @@ // import UIKit +import SnapKit +import SDWebImage class WineListCollectionViewCell: UICollectionViewCell { @@ -25,6 +27,8 @@ class WineListCollectionViewCell: UICollectionViewCell { l1.font = .boldSystemFont(ofSize: 18) l1.textColor = .black l1.numberOfLines = 0 + l1.adjustsFontSizeToFitWidth = true // 텍스트가 레이블 너비에 맞도록 크기 조정 + l1.minimumScaleFactor = 0.5 return l1 }() @@ -91,6 +95,8 @@ class WineListCollectionViewCell: UICollectionViewCell { name.snp.makeConstraints { make in make.top.equalToSuperview().offset(16) make.leading.equalTo(imageView.snp.trailing).offset(18) + make.width.lessThanOrEqualTo(220) + make.height.lessThanOrEqualTo(55) } price.snp.makeConstraints { make in @@ -110,12 +116,13 @@ class WineListCollectionViewCell: UICollectionViewCell { } } - func configure(imageName: String) { - if let image = UIImage(named: imageName) { - self.name.text = imageName - price.text = "165,000 ₩" - score.text = "4.5" - imageView.image = image - } + func configure(wine: Wine) { + let imageURL = URL(string: wine.imageUrl!) + imageView.sd_setImage(with: imageURL, placeholderImage: UIImage(named: "placeholder")) + name.text = wine.name + let priceString: String = String(wine.price) + price.text = priceString + let scoreString: String = String(wine.rating) + score.text = scoreString } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift index 947dfc7..03ff646 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift @@ -5,4 +5,297 @@ // Created by 김도연 on 7/21/24. // -import Foundation +import UIKit +import SnapKit + +class WineOrderViewController: UIViewController { + + private var quantity: Int = 0 { + didSet { + updateNumLabel() + } + } + + var shop: String? + var score = 4.5 + private let scoreLabel = UILabel() + private let shopName = UILabel() + + private let label: UILabel = { + let l = UILabel() + l.text = "판매처" + l.font = .systemFont(ofSize: 28, weight: UIFont.Weight(700)) + l.textColor = .black + l.numberOfLines = 0 + return l + }() + + private let stick: UIView = { + let s = UIView() + s.backgroundColor = UIColor(hex: "FA735B") + s.layer.borderWidth = 0 + return s + }() + + private let name: UILabel = { + let l = UILabel() + l.text = "Red Label" + l.font = .boldSystemFont(ofSize: 22) + l.textColor = .black + return l + }() + + private let image: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "Red Label") + i.layer.cornerRadius = 10 + i.layer.masksToBounds = true + return i + }() + + private let infoView: UIView = { + let v = UIView() + v.backgroundColor = UIColor(hex: "#EDEDED") + v.layer.cornerRadius = 10 + v.layer.masksToBounds = true + v.layer.borderWidth = 1.5 + v.layer.borderColor = UIColor(hex: "#D9D9D9")?.cgColor + return v + }() + + private let distance: UILabel = { + let l2 = UILabel() + + let imageAttachment = NSTextAttachment() + imageAttachment.image = UIImage(named: "icon_location") + + let imageOffsetY: CGFloat = -2.0 // 텍스트와 이미지의 정렬을 맞추기 위해 조정합니다. + imageAttachment.bounds = CGRect(x: 0, y: imageOffsetY, width: 10, height: 14) // 이미지의 크기를 설정합니다. + + let completeText = NSMutableAttributedString(string: "") + + let attachmentString = NSAttributedString(attachment: imageAttachment) + completeText.append(attachmentString) + + // 매장 텍스트 추가 + let text = NSAttributedString(string: " 2.3 km", attributes: [.font: UIFont.boldSystemFont(ofSize: 12)]) + completeText.append(text) + l2.attributedText = completeText + l2.textColor = UIColor(hex: "#FF7A6D") + return l2 + }() + + private let address: UILabel = { + let l3 = UILabel() + l3.text = "서울특별시 마포구 와우산로 94" + l3.textColor = UIColor(hex: "#767676") + l3.font = UIFont.boldSystemFont(ofSize: 14) + return l3 + }() + + let price: UILabel = { + let l4 = UILabel() + l4.text = "25,000 ₩" + l4.textColor = UIColor(hex: "#767676") + l4.font = UIFont.boldSystemFont(ofSize: 12) + return l4 + }() + + private let changeNumButton: UIButton = { + let b = UIButton(type: .custom) + b.backgroundColor = .clear + b.setImage(UIImage(named: "ChangeNumButton")?.withRenderingMode(.alwaysOriginal), for: .normal) + b.addTarget(self, action: #selector(changeNumButtonTapped), for: .touchUpInside) + b.adjustsImageWhenHighlighted = false + return b + }() + + private let NumLabel: UILabel = { + let l = UILabel() + l.text = "1" + l.font = UIFont.boldSystemFont(ofSize: 12) + l.textAlignment = .center + l.textColor = .black + + return l + }() + + private func updateNumLabel() { + let label = "\(quantity)" + NumLabel.text = label + } + + @objc func changeNumButtonTapped(_ sender: UIButton, forEvent event: UIEvent) { + // 터치 이벤트를 가져옵니다. + if let touch = event.allTouches?.first { + let location = touch.location(in: sender) + let buttonWidth = sender.bounds.width + + if location.x < buttonWidth * 0.3 { + // 버튼의 왼쪽 30% 영역을 클릭한 경우 + decreaseQuantity() + } else if location.x > buttonWidth * 0.7 { + // 버튼의 오른쪽 30% 영역을 클릭한 경우 + increaseQuantity() + } + } + } + + private func decreaseQuantity() { + quantity = max(quantity - 1, 1) + } + + private func increaseQuantity() { + quantity += 1 + } + + private let goToCartButton: UIButton = { + let b = UIButton(type: .system) + b.setTitle("장바구니 담기", for: .normal) + b.setTitleColor(UIColor(hex: "#FA735B"), for: .normal) + b.titleLabel?.font = .boldSystemFont(ofSize: 18) + b.contentHorizontalAlignment = .center + + b.backgroundColor = .white + b.layer.cornerRadius = 25 + b.layer.masksToBounds = true + b.layer.borderWidth = 2 + b.layer.borderColor = UIColor(hex: "#FA735B")?.cgColor + + return b + }() + + private let goToBuyButton: UIButton = { + let b = UIButton(type: .system) + b.setTitle("구매하기", for: .normal) + b.setTitleColor(.white, for: .normal) + b.titleLabel?.font = .boldSystemFont(ofSize: 18) + b.contentHorizontalAlignment = .center + + b.backgroundColor = UIColor(hex: "#FA735B") + b.layer.cornerRadius = 25 + b.layer.masksToBounds = true + + return b + }() + + override func viewDidLoad() { + super.viewDidLoad() + + self.navigationController?.isNavigationBarHidden = false + self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) + self.navigationController?.navigationBar.tintColor = .black + + view.backgroundColor = .white + setupUI() + } + + private func setupUI() { + configureScore() + configureShopName() + + view.addSubview(label) + label.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(20) + make.leading.equalTo(view.safeAreaLayoutGuide).offset(27) + } + + view.addSubview(stick) + stick.snp.makeConstraints { make in + make.top.equalTo(label.snp.bottom).offset(31) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) + make.height.equalTo(1.5) + } + + view.addSubview(image) + image.snp.makeConstraints { make in + make.top.equalTo(stick).offset(21) + make.leading.equalTo(view.safeAreaLayoutGuide).offset(17) + make.width.lessThanOrEqualTo(80) + make.height.equalTo(image.snp.width) + } + + view.addSubview(name) + name.snp.makeConstraints { make in + make.top.equalTo(image.snp.top) + make.leading.equalTo(image.snp.trailing).offset(22) + } + + view.addSubview(scoreLabel) + scoreLabel.snp.makeConstraints { make in + make.centerY.equalTo(name) + make.leading.equalTo(name.snp.trailing).offset(18) + } + + view.addSubview(infoView) + infoView.snp.makeConstraints { make in + make.top.equalTo(image.snp.bottom).offset(18) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) + make.height.greaterThanOrEqualTo(120) + } + + infoView.addSubview(shopName) + shopName.snp.makeConstraints { make in + make.top.equalToSuperview().offset(15) + make.leading.equalToSuperview().offset(17) + } + + infoView.addSubview(distance) + distance.snp.makeConstraints { make in + make.centerY.equalTo(shopName) + make.leading.equalTo(shopName.snp.trailing).offset(13) + } + + infoView.addSubview(address) + address.snp.makeConstraints { make in + make.top.equalTo(shopName.snp.bottom).offset(13) + make.leading.equalTo(shopName) + } + + infoView.addSubview(price) + price.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(13) + make.trailing.equalToSuperview().inset(17) + } + + view.addSubview(changeNumButton) + changeNumButton.snp.makeConstraints { make in + make.top.equalTo(infoView.snp.bottom).offset(16) + make.trailing.equalTo(infoView.snp.trailing).inset(10) + } + + changeNumButton.addSubview(NumLabel) + NumLabel.snp.makeConstraints { make in + make.centerX.centerY.equalToSuperview() + } + + let stackView = UIStackView(arrangedSubviews: [goToCartButton, goToBuyButton]) + stackView.axis = .horizontal + stackView.distribution = .fillProportionally + stackView.spacing = 9 + + view.addSubview(stackView) + stackView.snp.makeConstraints { make in + make.bottom.equalTo(view.safeAreaLayoutGuide).inset(53) + make.leading.trailing.equalTo(infoView) + make.height.greaterThanOrEqualTo(50) + } + + goToCartButton.snp.makeConstraints { make in + make.width.equalTo(goToBuyButton) + } + } + + private func configureScore() { + scoreLabel.text = "★ \(score)" + scoreLabel.font = .boldSystemFont(ofSize: 14) + scoreLabel.textColor = UIColor(hex: "#FA735B") + } + + private func configureShopName() { + shopName.text = shop + shopName.font = .boldSystemFont(ofSize: 18) + shopName.textColor = .black + shopName.numberOfLines = 0 + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineShopListCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineShopListCollectionViewCell.swift new file mode 100644 index 0000000..2a8f776 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineShopListCollectionViewCell.swift @@ -0,0 +1,104 @@ +// +// WineShopListCollectionViewCell.swift +// Drink-EG +// +// Created by 이현주 on 8/14/24. +// + +import UIKit +import SnapKit + +class WineShopListCollectionViewCell: UICollectionViewCell { + + let shopName: UILabel = { + let l1 = UILabel() + l1.font = .boldSystemFont(ofSize: 18) + l1.textColor = .black + l1.numberOfLines = 0 + return l1 + }() + + private let distance: UILabel = { + let l2 = UILabel() + + let imageAttachment = NSTextAttachment() + imageAttachment.image = UIImage(named: "icon_location") + + let imageOffsetY: CGFloat = -2.0 // 텍스트와 이미지의 정렬을 맞추기 위해 조정합니다. + imageAttachment.bounds = CGRect(x: 0, y: imageOffsetY, width: 10, height: 14) // 이미지의 크기를 설정합니다. + + let completeText = NSMutableAttributedString(string: "") + + let attachmentString = NSAttributedString(attachment: imageAttachment) + completeText.append(attachmentString) + + // 매장 텍스트 추가 + let text = NSAttributedString(string: " 2.3 km", attributes: [.font: UIFont.boldSystemFont(ofSize: 12)]) + completeText.append(text) + l2.attributedText = completeText + l2.textColor = UIColor(hex: "#FF7A6D") + return l2 + }() + + private let address: UILabel = { + let l3 = UILabel() + l3.text = "서울특별시 마포구 와우산로 94" + l3.textColor = UIColor(hex: "#767676") + l3.font = UIFont.boldSystemFont(ofSize: 14) + return l3 + }() + + let price: UILabel = { + let l4 = UILabel() + l4.text = "25,000 ₩" + l4.textColor = UIColor(hex: "#767676") + l4.font = UIFont.boldSystemFont(ofSize: 12) + return l4 + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + + self.contentView.addSubview(shopName) + self.contentView.addSubview(distance) + self.contentView.addSubview(address) + self.contentView.addSubview(price) + self.contentView.backgroundColor = UIColor(hex: "EDEDED") + self.contentView.layer.borderWidth = 1.5 + self.contentView.layer.borderColor = UIColor(hex: "D9D9D9")?.cgColor + self.contentView.layer.cornerRadius = 10 + self.contentView.layer.masksToBounds = true + + shopName.snp.makeConstraints { make in + make.top.equalToSuperview().offset(15) + make.leading.equalToSuperview().offset(17) + } + + distance.snp.makeConstraints { make in + make.centerY.equalTo(shopName) + make.leading.equalTo(shopName.snp.trailing).offset(13) + } + + address.snp.makeConstraints { make in + make.top.equalTo(shopName.snp.bottom).offset(13) + make.leading.equalTo(shopName) + } + + price.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(13) + make.trailing.equalToSuperview().inset(17) + } + } + + func configure(name: String) { + self.shopName.text = name + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift index 9c0268c..7464c32 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift @@ -9,6 +9,12 @@ import SnapKit import UIKit class WineStoreListViewController: UIViewController { + + weak var delegate: StoreListDelegate? + var selectedShop: String? + + private var WineShopContents: [String] = ["PODO", "루바토 와인", "버건디", "와인나우", "보데가 와인"] + private let label: UILabel = { let l = UILabel() l.text = "근처 판매처" @@ -52,12 +58,28 @@ class WineStoreListViewController: UIViewController { return l3 }() + lazy var wineShopListCollectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + + let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) + cv.register(WineShopListCollectionViewCell.self, forCellWithReuseIdentifier: "WineShopListCollectionViewCell") + cv.translatesAutoresizingMaskIntoConstraints = false + cv.showsVerticalScrollIndicator = false + cv.delegate = self + cv.dataSource = self + + cv.decelerationRate = .fast + cv.backgroundColor = .clear + cv.layer.cornerRadius = 10 + + return cv + }() + override func viewDidLoad() { super.viewDidLoad() self.navigationController?.isNavigationBarHidden = false - self.navigationController?.navigationBar.backIndicatorImage = UIImage(named:"icon_back") - self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named:"icon_back") self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) self.navigationController?.navigationBar.tintColor = .black @@ -68,7 +90,7 @@ class WineStoreListViewController: UIViewController { private func setupUI() { view.addSubview(label) label.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).offset(30) + make.top.equalTo(view.safeAreaLayoutGuide).offset(20) make.leading.equalTo(view.safeAreaLayoutGuide).offset(27) } @@ -97,5 +119,48 @@ class WineStoreListViewController: UIViewController { make.centerY.equalTo(name) make.leading.equalTo(name.snp.trailing).offset(13) } + + view.addSubview(wineShopListCollectionView) + wineShopListCollectionView.snp.makeConstraints { make in + make.top.equalTo(wineInfo.snp.bottom).offset(76) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(15) + make.bottom.equalTo(view.safeAreaLayoutGuide).inset(15) + } + } +} + +extension WineStoreListViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return WineShopContents.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WineShopListCollectionViewCell", for: indexPath) as! WineShopListCollectionViewCell + + cell.configure(name: WineShopContents[indexPath.item]) + + return cell + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + + if let previousViewController = navigationController?.viewControllers.dropLast().last { + if previousViewController is WineInfoViewController { + let selectedCell = collectionView.cellForItem(at: indexPath) as! WineShopListCollectionViewCell + selectedShop = WineShopContents[indexPath.item] + let wineOrderViewController = WineOrderViewController() + wineOrderViewController.shop = selectedShop + navigationController?.pushViewController(wineOrderViewController, animated: true) + } else if previousViewController is ShoppingCartListViewController { + let selectedCell = collectionView.cellForItem(at: indexPath) as! WineShopListCollectionViewCell + delegate?.didSelectStore(selectedCell.shopName.text ?? "") + navigationController?.popViewController(animated: true) // 장바구니 화면으로 돌아가기 + } + } + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: collectionView.frame.width, height: 120) } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift index bbe00dc..29690bb 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift @@ -9,6 +9,7 @@ import Foundation import UIKit import SnapKit import Moya +import SDWebImage class CheckNoteViewController: UIViewController { var wine: String? @@ -19,6 +20,9 @@ class CheckNoteViewController: UIViewController { var reviewString: String = "" var value: Double = 0.0 + var selectedWineName: String? + var selectedWineImage: String? + func setupPentagonChart() { pentagonChart.backgroundColor = .clear pentagonChart.dataList = dataList @@ -41,7 +45,7 @@ class CheckNoteViewController: UIViewController { contentView.snp.makeConstraints { make in make.edges.equalTo(scrollView) make.width.equalTo(scrollView) - make.height.greaterThanOrEqualTo(1000) + make.height.equalTo(UIScreen.main.bounds.height * 1.3) } } @@ -55,8 +59,10 @@ class CheckNoteViewController: UIViewController { private lazy var imageView: UIImageView = { let iv = UIImageView() - if let wine = wine { - iv.image = UIImage(named: wine) + if let imageUrlString = selectedWineImage, let imageUrl = URL(string: imageUrlString) { + iv.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: "Loxton")) + } else { + iv.image = UIImage(named: "Loxton") } iv.layer.cornerRadius = 10 iv.layer.masksToBounds = true @@ -65,12 +71,10 @@ class CheckNoteViewController: UIViewController { private lazy var name: UILabel = { let l = UILabel() - if let wine = wine { - l.text = wine - } + l.text = selectedWineName ?? "" l.font = .boldSystemFont(ofSize: 18) l.textColor = .black - l.numberOfLines = 0 + l.numberOfLines = 2 return l }() @@ -204,7 +208,7 @@ class CheckNoteViewController: UIViewController { func setupButton() { tasteView.addSubview(aromaButton) - aromaButton.setTitle(selectedOptions["Aroma"]?[0], for: .normal) + aromaButton.setTitle(selectedOptions["scentAroma"]?[0], for: .normal) aromaButton.titleLabel?.font = UIFont(name: "Pretendard-SemiBold", size: 16) aromaButton.setTitleColor(.black, for: .normal) aromaButton.backgroundColor = UIColor(hex: "FBCBC4") @@ -212,7 +216,7 @@ class CheckNoteViewController: UIViewController { aromaButton.layer.cornerRadius = 10 tasteView.addSubview(tasteButton) - tasteButton.setTitle(selectedOptions["Taste"]?[0], for: .normal) + tasteButton.setTitle(selectedOptions["scentTaste"]?[0], for: .normal) tasteButton.titleLabel?.font = UIFont(name: "Pretendard-SemiBold", size: 16) tasteButton.setTitleColor(.black, for: .normal) tasteButton.backgroundColor = UIColor(hex: "FBCBC4") @@ -220,7 +224,7 @@ class CheckNoteViewController: UIViewController { tasteButton.layer.cornerRadius = 10 tasteView.addSubview(finishButton) - finishButton.setTitle(selectedOptions["Finish"]?[0], for: .normal) + finishButton.setTitle(selectedOptions["scentFinish"]?[0], for: .normal) finishButton.titleLabel?.font = UIFont(name: "Pretendard-SemiBold", size: 16) finishButton.setTitleColor(.black, for: .normal) finishButton.backgroundColor = UIColor(hex: "FBCBC4") @@ -232,6 +236,7 @@ class CheckNoteViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white + print(selectedOptions) setupView() setupUI() } @@ -246,7 +251,7 @@ class CheckNoteViewController: UIViewController { infoView.snp.makeConstraints { make in make.top.equalTo(contentView.safeAreaLayoutGuide).offset(50) make.leading.trailing.equalTo(contentView.safeAreaLayoutGuide).inset(14) - make.height.lessThanOrEqualTo(101) + make.height.equalTo(UIScreen.main.bounds.height * 0.09) } infoView.addSubview(imageView) @@ -260,6 +265,7 @@ class CheckNoteViewController: UIViewController { name.snp.makeConstraints { make in make.top.equalToSuperview().offset(11) make.leading.equalTo(imageView.snp.trailing).offset(20) + // make.trailing.equalTo(score.snp.leading).offset(-10) } infoView.addSubview(specInfo) @@ -283,7 +289,7 @@ class CheckNoteViewController: UIViewController { contentView.addSubview(tastingNoteView) tastingNoteView.snp.makeConstraints { make in - make.top.equalTo(infoView.snp.bottom).offset(10.5) + make.top.equalTo(infoView.snp.bottom).offset(29) make.leading.trailing.equalTo(infoView) make.bottom.greaterThanOrEqualTo(414) } @@ -298,14 +304,14 @@ class CheckNoteViewController: UIViewController { pentagonChart.snp.makeConstraints{ make in make.top.equalTo(represent.snp.bottom).offset(29) make.centerX.equalTo(view.safeAreaLayoutGuide.snp.centerX) - make.width.equalTo(353) - make.height.equalTo(309) + make.width.equalTo(UIScreen.main.bounds.width * 0.89) + make.height.equalTo(pentagonChart.snp.width).multipliedBy(0.87) } tastingNoteView.addSubview(tasteView) tasteView.snp.makeConstraints { make in make.top.equalTo(pentagonChart.snp.bottom).offset(41.55) - make.leading.equalTo(tastingNoteView.snp.leading) + make.leading.equalTo(tastingNoteView.snp.leading).offset(15) make.centerX.equalTo(tastingNoteView.snp.centerX) make.height.greaterThanOrEqualTo(116) } @@ -344,6 +350,7 @@ class CheckNoteViewController: UIViewController { make.top.equalTo(finishLabel.snp.bottom).offset(7) make.centerX.equalTo(finishLabel.snp.centerX) make.leading.equalTo(tasteButton.snp.trailing).offset(53) + make.trailing.equalTo(tasteView.snp.trailing).offset(-9) } tastingNoteView.addSubview(vectorView) diff --git a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSuggestionCell.swift b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSuggestionCell.swift index c6694ad..45eabce 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSuggestionCell.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSuggestionCell.swift @@ -8,6 +8,7 @@ import Foundation import UIKit import SnapKit +import SDWebImage class CustomSuggestionCell: UITableViewCell { @@ -37,6 +38,7 @@ class CustomSuggestionCell: UITableViewCell { // 라벨 설정 suggestionLabel.font = UIFont(name: "Pretendard-SemiBold", size: 18) suggestionLabel.textColor = .black + suggestionLabel.numberOfLines = 2 // 선택된 상태를 나타내는 이미지 (체크박스 같은 용도) selectionIndicator.contentMode = .scaleAspectFill @@ -51,19 +53,21 @@ class CustomSuggestionCell: UITableViewCell { suggestionLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(suggestionImageView.snp.trailing).offset(25) + make.trailing.equalToSuperview().offset(-25) make.width.greaterThanOrEqualTo(82) } selectionIndicator.snp.makeConstraints { make in make.centerY.equalToSuperview() - make.trailing.equalToSuperview().offset(-35) + make.trailing.equalToSuperview().offset(-5) make.width.height.greaterThanOrEqualTo(22) } } - - func configure(image: UIImage, text: String, isSelected: Bool) { - suggestionImageView.image = image - suggestionLabel.text = text + + func configure(with wine: Wine, isSelected: Bool) { + let imageURL = URL(string: wine.imageUrl!) + suggestionImageView.sd_setImage(with: imageURL, placeholderImage: UIImage(named: "placeholder")) + suggestionLabel.text = wine.name selectionIndicator.image = isSelected ? UIImage(systemName: "checkmark.circle.fill") : UIImage(systemName: "circle") selectionIndicator.tintColor = isSelected ? .systemOrange : .lightGray } diff --git a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift index 0e92b95..41afdf5 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift @@ -13,9 +13,6 @@ import Cosmos class RatingViewController: UIViewController { - var selectedOptions: [String: [String]] = [:] - var dataList: [RadarChartData] = [] - let tastingnoteLabel = UILabel() let scrollView = UIScrollView() let contentView = UIView() @@ -30,7 +27,16 @@ class RatingViewController: UIViewController { let reviewLabel = UILabel() let reviewText = UITextField() let completeButton = UIButton() + + var selectedOptions: [String: [String]] = [:] + var dataList: [RadarChartData] = [] var value: Double = 0.0 + var receivedColor = "" + var selectedWineId: Int? + var selectedWineName: String? + var selectedWineImage: String? + + let provider = MoyaProvider(plugins: [CookiePlugin()]) override func viewDidLoad() { super.viewDidLoad() @@ -153,7 +159,7 @@ class RatingViewController: UIViewController { button.layer.borderWidth = 2 button.layer.borderColor = UIColor(hex: "FA8D7B")?.cgColor button.layer.cornerRadius = 10 - + let titleSize = button.titleLabel!.intrinsicContentSize @@ -325,7 +331,6 @@ class RatingViewController: UIViewController { func setupRatingButtonConstraints() { ratingButton.snp.makeConstraints { make in make.top.equalTo(ratingLabel.snp.bottom).offset(5) - make.leading.equalTo(ratingLabel.snp.leading).offset(68) make.centerX.equalTo(contentView.snp.centerX) } } @@ -403,10 +408,14 @@ class RatingViewController: UIViewController { @objc func completeButtonTapped() { let nextVC = CheckNoteViewController() + postNewNoteAPI() + patchNoteAPI(wineId: selectedWineId!) nextVC.dataList = dataList nextVC.selectedOptions = selectedOptions nextVC.reviewString = reviewText.text ?? "" nextVC.value = value + nextVC.selectedWineName = selectedWineName + nextVC.selectedWineImage = selectedWineImage navigationController?.pushViewController(nextVC, animated: true) } @@ -418,4 +427,121 @@ class RatingViewController: UIViewController { make.height.greaterThanOrEqualTo(60) } } + + func postNewNoteAPI() { + let wineId = selectedWineId + let color = receivedColor + let satisfaction = Int(value) + let memo = reviewText.text ?? "" + let scentAroma = selectedOptions["Aroma"] ?? [] + let scentTaste = selectedOptions["Taste"] ?? [] + let scentFinish = selectedOptions["Finish"] ?? [] + + var sugarContent: Int? + var acidity: Int? + var tannin: Int? + var bodied: Int? + var alcohol: Int? + + for data in dataList { + switch data.type { + case .sweetness: + sugarContent = data.value + case .acid: + acidity = data.value + case .tannin: + tannin = data.value + case .bodied: + bodied = data.value + case .alcohol: + alcohol = data.value + } + } + + provider.request(.postNewNote( + wineId: wineId!, + color: color, + sugarContent: sugarContent ?? 0, + acidity: acidity ?? 0, + tannin: tannin ?? 0, + body: bodied ?? 0, + alcohol: alcohol ?? 0, + scentAroma: scentAroma, + scentTaste: scentTaste, + scentFinish: scentFinish, + satisfaction: satisfaction, + memo: memo)) { result in + switch result { + case .success(let response): + print("Note successfully posted with response: \(response)") + // Navigate to the next screen + let nextVC = CheckNoteViewController() + nextVC.dataList = self.dataList + nextVC.selectedOptions = self.selectedOptions + nextVC.reviewString = memo + nextVC.value = self.value + self.navigationController?.pushViewController(nextVC, animated: true) + case .failure(let error): + print("Failed to post note: \(error)") + } + } + } + + func patchNoteAPI(wineId: Int) { + let color = receivedColor + let satisfaction = Int(value) + let review = reviewText.text ?? "" + let scentAroma = selectedOptions["Aroma"] ?? [] + let scentTaste = selectedOptions["Taste"] ?? [] + let scentFinish = selectedOptions["Finish"] ?? [] + + var sugarContent: Int? + var acidity: Int? + var tannin: Int? + var bodied: Int? + var alcohol: Int? + + for data in dataList { + switch data.type { + case .sweetness: + sugarContent = data.value + case .acid: + acidity = data.value + case .tannin: + tannin = data.value + case .bodied: + bodied = data.value + case .alcohol: + alcohol = data.value + } + } + + provider.request(.patchNote( + wineId: wineId, + color: color, + sugarContent: sugarContent ?? 0, + acidity: acidity ?? 0, + tannin: tannin ?? 0, + body: bodied ?? 0, + alcohol: alcohol ?? 0, + scentAroma: scentAroma, + scentTaste: scentTaste, + scentFinish: scentFinish, + satisfaction: satisfaction, + review: review)) { result in + switch result { + case .success(let response): + print("Note successfully patched with response: \(response)") + // 수정이 성공하면 다음 화면으로 이동 + let nextVC = CheckNoteViewController() + nextVC.dataList = self.dataList + nextVC.selectedOptions = self.selectedOptions + nextVC.reviewString = review + nextVC.value = self.value + self.navigationController?.pushViewController(nextVC, animated: true) + case .failure(let error): + print("Failed to patch note: \(error)") + } + } + } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/WriteNoteViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/WriteNoteViewController.swift index c19228b..2e34d2a 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/WriteNoteViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/WriteNoteViewController.swift @@ -10,9 +10,14 @@ class WriteNoteViewController: UIViewController { let wineName = UILabel() let showPentagonButton = UIButton() let categories = ["당도", "산도", "타닌", "바디", "알코올"] + var categoryLabels: [UILabel] = [] var categorySliders: [UISlider] = [] var selectedValues: [CharacteristicType: Int] = [:] + var selectedWineName: String? + var selectedWineImage: String? + var selectedWineId: Int? + let scrollView = UIScrollView() let contentView = UIView() @@ -51,7 +56,7 @@ class WriteNoteViewController: UIViewController { contentView.snp.makeConstraints { make in make.edges.equalTo(scrollView) make.width.equalTo(scrollView) - make.height.greaterThanOrEqualTo(916) + make.height.equalTo(UIScreen.main.bounds.height * 1.1) } } @@ -103,7 +108,11 @@ class WriteNoteViewController: UIViewController { wineImageView.contentMode = .scaleAspectFit wineImageView.layer.cornerRadius = 10 wineImageView.layer.masksToBounds = true - wineImageView.image = UIImage(named: "SampleImage") + if let imageUrl = selectedWineImage, let url = URL(string: imageUrl) { + wineImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) + } else { + wineImageView.image = UIImage(named: "Loxton") + } } func setupWineImageViewConstraints() { @@ -118,7 +127,8 @@ class WriteNoteViewController: UIViewController { func setupWineName() { wineView.addSubview(wineName) - wineName.text = "19 Crhnes" + wineName.text = selectedWineName ?? "" + wineName.numberOfLines = 2 wineName.font = UIFont(name: "Pretendard-SemiBold", size: 18) } @@ -142,7 +152,7 @@ class WriteNoteViewController: UIViewController { make.top.equalTo(wineView.snp.bottom).offset(10) make.centerX.equalTo(wineView.snp.centerX) make.leading.equalTo(wineView.snp.leading) - make.height.greaterThanOrEqualTo(482) + make.height.equalTo(UIScreen.main.bounds.height * 0.6) } } @@ -169,18 +179,22 @@ class WriteNoteViewController: UIViewController { } func setupConstraints() { + let labelHeight: CGFloat = UIScreen.main.bounds.height * 0.05 + let verticalSpacing: CGFloat = (UIScreen.main.bounds.height * 0.6 - labelHeight * CGFloat(categories.count)) / CGFloat(categories.count + 1) + + for i in 0..", for: .normal) @@ -232,14 +234,16 @@ class WriteNoteViewController: UIViewController { } } - // NoteInfoViewController로 값 전달 let polygonVC = NoteInfoViewController() - var dataList: [RadarChartData] = [] + var dataList: [RadarChartData] = [] // 각각의 value를 전달 for (type, value) in selectedValues { dataList.append(RadarChartData(type: type, value: value)) } polygonVC.dataList = dataList + polygonVC.selectedWineId = selectedWineId + polygonVC.selectedWineImage = selectedWineImage + polygonVC.selectedWineName = selectedWineName navigationController?.pushViewController(polygonVC, animated: true) } }