diff --git a/.DS_Store b/.DS_Store index b5327cc..7e219d7 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 2aff4ab..6774469 100644 --- a/Drink-EG/Drink-EG.xcodeproj/project.pbxproj +++ b/Drink-EG/Drink-EG.xcodeproj/project.pbxproj @@ -56,6 +56,26 @@ 16C19AA62C70B67200E93FD0 /* ShoppingListManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AA52C70B67200E93FD0 /* ShoppingListManager.swift */; }; 16C19AA92C70B8D500E93FD0 /* UserWineData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AA82C70B8D500E93FD0 /* UserWineData.swift */; }; 16C19AAB2C7194D200E93FD0 /* LoginResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AAA2C7194D200E93FD0 /* LoginResponse.swift */; }; + 16C19AB02C73A3B100E93FD0 /* AppleLoginResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AAF2C73A3B100E93FD0 /* AppleLoginResponse.swift */; }; + 16C19AB22C73A3FD00E93FD0 /* MemberResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AB12C73A3FD00E93FD0 /* MemberResponse.swift */; }; + 16C19ABD2C73AB6300E93FD0 /* MyPageSuggestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AB42C73AB6300E93FD0 /* MyPageSuggestViewController.swift */; }; + 16C19ABE2C73AB6300E93FD0 /* MyPageQnaViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AB52C73AB6300E93FD0 /* MyPageQnaViewController.swift */; }; + 16C19ABF2C73AB6300E93FD0 /* MyPageNoticeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AB62C73AB6300E93FD0 /* MyPageNoticeViewController.swift */; }; + 16C19AC02C73AB6300E93FD0 /* MyPageBusinessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AB72C73AB6300E93FD0 /* MyPageBusinessViewController.swift */; }; + 16C19AC12C73AB6300E93FD0 /* MyPageOrderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AB82C73AB6300E93FD0 /* MyPageOrderViewController.swift */; }; + 16C19AC22C73AB6300E93FD0 /* MypageInfoBottomViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AB92C73AB6300E93FD0 /* MypageInfoBottomViewController.swift */; }; + 16C19AC32C73AB6300E93FD0 /* MyPageSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19ABA2C73AB6300E93FD0 /* MyPageSettingsViewController.swift */; }; + 16C19AC42C73AB6300E93FD0 /* WishListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19ABB2C73AB6300E93FD0 /* WishListViewController.swift */; }; + 16C19AC52C73AB6300E93FD0 /* MypageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19ABC2C73AB6300E93FD0 /* MypageViewController.swift */; }; + 16C19ACA2C73ACD700E93FD0 /* NewNoteFooterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AC92C73ACD700E93FD0 /* NewNoteFooterDelegate.swift */; }; + 16C19ACC2C73ACFF00E93FD0 /* NoteCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19ACB2C73ACFF00E93FD0 /* NoteCollectionViewCell.swift */; }; + 16C19ACE2C73AD3000E93FD0 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19ACD2C73AD3000E93FD0 /* String.swift */; }; + 16C19AD22C73AE0200E93FD0 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AD12C73AE0200E93FD0 /* UIView.swift */; }; + 16C19AD42C73AE1C00E93FD0 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AD32C73AE1C00E93FD0 /* CustomButton.swift */; }; + 16C19AD62C73AE3900E93FD0 /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AD52C73AE3900E93FD0 /* UIConstants.swift */; }; + 16C19AD82C73AE5E00E93FD0 /* WineClassCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19AD72C73AE5E00E93FD0 /* WineClassCell.swift */; }; + 16C19ADC2C73AE8D00E93FD0 /* CarouselLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19ADB2C73AE8D00E93FD0 /* CarouselLayout.swift */; }; + 16C19ADE2C73AF6000E93FD0 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C19ADD2C73AF6000E93FD0 /* UserDefaults.swift */; }; 1F205A312C68BB5200E80659 /* CartListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F205A302C68BB5200E80659 /* CartListCollectionViewCell.swift */; }; 1F205A332C69FE9800E80659 /* JoinNLoginRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F205A322C69FE9800E80659 /* JoinNLoginRequest.swift */; }; 1F205A372C6A71BC00E80659 /* APIResponseLoginResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F205A362C6A71BC00E80659 /* APIResponseLoginResponse.swift */; }; @@ -78,7 +98,6 @@ 1F598F0F2C5CBE70000CE79F /* FirstTasteTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F598F0E2C5CBE70000CE79F /* FirstTasteTestViewController.swift */; }; 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 */; }; @@ -86,6 +105,8 @@ 1F8F99FC2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99FB2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift */; }; 1F8F99FE2C6FACF600EAEF6C /* WineReviewResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99FD2C6FACF600EAEF6C /* WineReviewResponse.swift */; }; 1F8F9A002C6FADBE00EAEF6C /* APIResponseWineReviewResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8F99FF2C6FADBE00EAEF6C /* APIResponseWineReviewResponse.swift */; }; + 1F8FECA32C71D9EE00704491 /* ExViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8FECA22C71D9EE00704491 /* ExViewController.swift */; }; + 1F8FECA52C71E0A700704491 /* CustomPickerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8FECA42C71E0A700704491 /* CustomPickerButton.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 */; }; @@ -100,7 +121,7 @@ 5E2219352C69D592005849FB /* Pretendard-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5E22192C2C69D592005849FB /* Pretendard-ExtraLight.otf */; }; 5E2219372C69D5AE005849FB /* UIColorToHexCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2219362C69D5AE005849FB /* UIColorToHexCode.swift */; }; 5E2219412C69D5D0005849FB /* CustomTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2219382C69D5D0005849FB /* CustomTableViewCell.swift */; }; - 5E2219422C69D5D0005849FB /* CustomCommentsCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2219392C69D5D0005849FB /* CustomCommentsCollectionView.swift */; }; + 5E2219422C69D5D0005849FB /* CustomCommentsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2219392C69D5D0005849FB /* CustomCommentsCollectionViewCell.swift */; }; 5E2219432C69D5D0005849FB /* ModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E22193A2C69D5D0005849FB /* ModalViewController.swift */; }; 5E2219442C69D5D0005849FB /* CreateNewCommViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E22193B2C69D5D0005849FB /* CreateNewCommViewController.swift */; }; 5E2219452C69D5D0005849FB /* CommunityInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E22193C2C69D5D0005849FB /* CommunityInfoViewController.swift */; }; @@ -155,12 +176,6 @@ 1654010E2C6E2B4B008A9DBF /* MyCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCollectionViewController.swift; sourceTree = ""; }; 165401102C6E2B79008A9DBF /* WineNewsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WineNewsViewController.swift; sourceTree = ""; }; 165401122C6E2BAA008A9DBF /* WineKnowledgeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WineKnowledgeViewController.swift; sourceTree = ""; }; - 165401182C6E555A008A9DBF /* CardSliderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CardSliderViewController.swift; path = ../../../../../../../../Downloads/CardSliderViewController.swift; sourceTree = ""; }; - 1654011A2C6E5661008A9DBF /* CardTitleview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CardTitleview.swift; path = ../../../../../../../../Downloads/CardTitleview.swift; sourceTree = ""; }; - 1654011C2C6E5681008A9DBF /* CardsLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CardsLayout.swift; path = ../../../../../../../../Downloads/CardsLayout.swift; sourceTree = ""; }; - 1654011E2C6E56A9008A9DBF /* UIViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UIViewExtension.swift; path = ../../../../../../../../Downloads/UIViewExtension.swift; sourceTree = ""; }; - 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 = ""; }; @@ -187,6 +202,26 @@ 16C19AA52C70B67200E93FD0 /* ShoppingListManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShoppingListManager.swift; sourceTree = ""; }; 16C19AA82C70B8D500E93FD0 /* UserWineData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserWineData.swift; sourceTree = ""; }; 16C19AAA2C7194D200E93FD0 /* LoginResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginResponse.swift; sourceTree = ""; }; + 16C19AAF2C73A3B100E93FD0 /* AppleLoginResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleLoginResponse.swift; sourceTree = ""; }; + 16C19AB12C73A3FD00E93FD0 /* MemberResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberResponse.swift; sourceTree = ""; }; + 16C19AB42C73AB6300E93FD0 /* MyPageSuggestViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyPageSuggestViewController.swift; sourceTree = ""; }; + 16C19AB52C73AB6300E93FD0 /* MyPageQnaViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyPageQnaViewController.swift; sourceTree = ""; }; + 16C19AB62C73AB6300E93FD0 /* MyPageNoticeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyPageNoticeViewController.swift; sourceTree = ""; }; + 16C19AB72C73AB6300E93FD0 /* MyPageBusinessViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyPageBusinessViewController.swift; sourceTree = ""; }; + 16C19AB82C73AB6300E93FD0 /* MyPageOrderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyPageOrderViewController.swift; sourceTree = ""; }; + 16C19AB92C73AB6300E93FD0 /* MypageInfoBottomViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MypageInfoBottomViewController.swift; sourceTree = ""; }; + 16C19ABA2C73AB6300E93FD0 /* MyPageSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyPageSettingsViewController.swift; sourceTree = ""; }; + 16C19ABB2C73AB6300E93FD0 /* WishListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WishListViewController.swift; sourceTree = ""; }; + 16C19ABC2C73AB6300E93FD0 /* MypageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MypageViewController.swift; sourceTree = ""; }; + 16C19AC92C73ACD700E93FD0 /* NewNoteFooterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NewNoteFooterDelegate.swift; path = "Drink-EG/Sources/Protocols/NewNoteFooterDelegate.swift"; sourceTree = SOURCE_ROOT; }; + 16C19ACB2C73ACFF00E93FD0 /* NoteCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteCollectionViewCell.swift; sourceTree = ""; }; + 16C19ACD2C73AD3000E93FD0 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; + 16C19AD12C73AE0200E93FD0 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; + 16C19AD32C73AE1C00E93FD0 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = ""; }; + 16C19AD52C73AE3900E93FD0 /* UIConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIConstants.swift; sourceTree = ""; }; + 16C19AD72C73AE5E00E93FD0 /* WineClassCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WineClassCell.swift; sourceTree = ""; }; + 16C19ADB2C73AE8D00E93FD0 /* CarouselLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselLayout.swift; sourceTree = ""; }; + 16C19ADD2C73AF6000E93FD0 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = ""; }; 1F205A302C68BB5200E80659 /* CartListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartListCollectionViewCell.swift; sourceTree = ""; }; 1F205A322C69FE9800E80659 /* JoinNLoginRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinNLoginRequest.swift; sourceTree = ""; }; 1F205A362C6A71BC00E80659 /* APIResponseLoginResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIResponseLoginResponse.swift; sourceTree = ""; }; @@ -209,7 +244,6 @@ 1F598F0E2C5CBE70000CE79F /* FirstTasteTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstTasteTestViewController.swift; sourceTree = ""; }; 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 = ""; }; @@ -217,6 +251,8 @@ 1F8F99FB2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIResponseWineInfoResponse.swift; sourceTree = ""; }; 1F8F99FD2C6FACF600EAEF6C /* WineReviewResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WineReviewResponse.swift; sourceTree = ""; }; 1F8F99FF2C6FADBE00EAEF6C /* APIResponseWineReviewResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIResponseWineReviewResponse.swift; sourceTree = ""; }; + 1F8FECA22C71D9EE00704491 /* ExViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExViewController.swift; sourceTree = ""; }; + 1F8FECA42C71E0A700704491 /* CustomPickerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPickerButton.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 = ""; }; @@ -231,7 +267,7 @@ 5E22192C2C69D592005849FB /* Pretendard-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-ExtraLight.otf"; sourceTree = ""; }; 5E2219362C69D5AE005849FB /* UIColorToHexCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColorToHexCode.swift; sourceTree = ""; }; 5E2219382C69D5D0005849FB /* CustomTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTableViewCell.swift; sourceTree = ""; }; - 5E2219392C69D5D0005849FB /* CustomCommentsCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomCommentsCollectionView.swift; sourceTree = ""; }; + 5E2219392C69D5D0005849FB /* CustomCommentsCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomCommentsCollectionViewCell.swift; sourceTree = ""; }; 5E22193A2C69D5D0005849FB /* ModalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModalViewController.swift; sourceTree = ""; }; 5E22193B2C69D5D0005849FB /* CreateNewCommViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateNewCommViewController.swift; sourceTree = ""; }; 5E22193C2C69D5D0005849FB /* CommunityInfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommunityInfoViewController.swift; sourceTree = ""; }; @@ -243,7 +279,7 @@ 5E22194B2C69D5E7005849FB /* NoteListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NoteListViewController.swift; path = ../NoteListViewController.swift; sourceTree = ""; }; 5E22194C2C69D5E7005849FB /* CustomSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSlider.swift; sourceTree = ""; }; 5E22194D2C69D5E7005849FB /* ChooseTasteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChooseTasteViewController.swift; path = ../ChooseTasteViewController.swift; sourceTree = ""; }; - 5E22194F2C69D5E7005849FB /* PolygonChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PolygonChartView.swift; path = ../PolygonChartView.swift; sourceTree = ""; }; + 5E22194F2C69D5E7005849FB /* PolygonChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PolygonChartView.swift; sourceTree = ""; }; 5E2219502C69D5E7005849FB /* AddNewNoteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddNewNoteViewController.swift; path = ../AddNewNoteViewController.swift; sourceTree = ""; }; 5E2219512C69D5E7005849FB /* CustomSuggestionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSuggestionCell.swift; sourceTree = ""; }; 5E2219522C69D5E7005849FB /* WriteNoteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WriteNoteViewController.swift; path = ../WriteNoteViewController.swift; sourceTree = ""; }; @@ -282,6 +318,7 @@ 1654014F2C6F960A008A9DBF /* NoteResponse.swift */, 165401522C6FC5AB008A9DBF /* RecommendWineResponse.swift */, 165401542C6FC5CD008A9DBF /* HomeResponse.swift */, + 16C19AD52C73AE3900E93FD0 /* UIConstants.swift */, ); path = Datas; sourceTree = ""; @@ -291,6 +328,7 @@ children = ( 165400F52C69EF89008A9DBF /* WineNewsRequest.swift */, 165400F72C69EFBD008A9DBF /* WineNewsResponse.swift */, + 16C19AB12C73A3FD00E93FD0 /* MemberResponse.swift */, ); path = WineNews; sourceTree = ""; @@ -317,23 +355,11 @@ 1F8F99F42C6F40F400EAEF6C /* APIResponseWineSearchResponse.swift */, 1F8F99FB2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift */, 1F8F99FF2C6FADBE00EAEF6C /* APIResponseWineReviewResponse.swift */, + 16C19AAF2C73A3B100E93FD0 /* AppleLoginResponse.swift */, ); path = APIResponseModels; sourceTree = ""; }; - 165401172C6E5545008A9DBF /* CustomCardSlider */ = { - isa = PBXGroup; - children = ( - 165401182C6E555A008A9DBF /* CardSliderViewController.swift */, - 1654011A2C6E5661008A9DBF /* CardTitleview.swift */, - 1654011C2C6E5681008A9DBF /* CardsLayout.swift */, - 1654011E2C6E56A9008A9DBF /* UIViewExtension.swift */, - 165401202C6E56BD008A9DBF /* RatingView.swift */, - 165401222C6E57BC008A9DBF /* CardSliderCell.swift */, - ); - path = CustomCardSlider; - sourceTree = ""; - }; 165401482C6F415F008A9DBF /* CardSliderSwiftUI */ = { isa = PBXGroup; children = ( @@ -398,6 +424,9 @@ children = ( 16752F9C2C5A7FB90001907D /* HexCode.swift */, 5E2219362C69D5AE005849FB /* UIColorToHexCode.swift */, + 16C19ACD2C73AD3000E93FD0 /* String.swift */, + 16C19AD12C73AE0200E93FD0 /* UIView.swift */, + 16C19ADD2C73AF6000E93FD0 /* UserDefaults.swift */, ); path = Extensions; sourceTree = ""; @@ -441,9 +470,9 @@ 16B97CF02C4BF3F100D8B453 /* Sources */ = { isa = PBXGroup; children = ( - 165400F42C69EEE6008A9DBF /* Datas */, 16B97CF42C4BF40900D8B453 /* Cells */, - 16B97CF32C4BF40100D8B453 /* Protocols */, + 165400F42C69EEE6008A9DBF /* Datas */, + 16C19ACF2C73AD5000E93FD0 /* Protocols */, 16B97CF22C4BF3FC00D8B453 /* Models */, 16B97CF12C4BF3F700D8B453 /* VCs */, ); @@ -453,10 +482,9 @@ 16B97CF12C4BF3F700D8B453 /* VCs */ = { isa = PBXGroup; children = ( + 16B97CFC2C4BFBD300D8B453 /* Main */, 1F598EF02C581376000CE79F /* TasteTest */, 1F598EEF2C58136B000CE79F /* Login */, - 16B97CF52C4BFAEC00D8B453 /* Default */, - 16B97CFC2C4BFBD300D8B453 /* Main */, 16B97CF62C4BFAFD00D8B453 /* Search */, 16B97CF72C4BFB0900D8B453 /* TastingNote */, 16B97CF82C4BFB2400D8B453 /* WineClass */, @@ -469,35 +497,33 @@ 16B97CF22C4BF3FC00D8B453 /* Models */ = { isa = PBXGroup; children = ( + 16C19AAE2C73A39A00E93FD0 /* Managers */, 165401052C69FA97008A9DBF /* APIResponseModels */, - 1654010A2C6BACDC008A9DBF /* SelectionManager.swift */, - 16C19AA52C70B67200E93FD0 /* ShoppingListManager.swift */, + 165401482C6F415F008A9DBF /* CardSliderSwiftUI */, + 5E22194F2C69D5E7005849FB /* PolygonChartView.swift */, + 5E22194C2C69D5E7005849FB /* CustomSlider.swift */, + 1F8FECA42C71E0A700704491 /* CustomPickerButton.swift */, + 16C19AD32C73AE1C00E93FD0 /* CustomButton.swift */, + 16C19ADB2C73AE8D00E93FD0 /* CarouselLayout.swift */, ); path = Models; sourceTree = ""; }; - 16B97CF32C4BF40100D8B453 /* Protocols */ = { - isa = PBXGroup; - children = ( - 165401172C6E5545008A9DBF /* CustomCardSlider */, - ); - path = Protocols; - sourceTree = ""; - }; 16B97CF42C4BF40900D8B453 /* Cells */ = { isa = PBXGroup; children = ( + 5E2219392C69D5D0005849FB /* CustomCommentsCollectionViewCell.swift */, + 5E2219382C69D5D0005849FB /* CustomTableViewCell.swift */, + 5E22193E2C69D5D0005849FB /* CustomCollectionViewCell.swift */, + 16C19AC82C73AC9000E93FD0 /* Search */, + 16C19AC72C73AC4000E93FD0 /* TasteTest */, + 16C19AC62C73AC1C00E93FD0 /* Main */, + 16C19AD02C73ADC900E93FD0 /* TastingNote */, + 16C19ADA2C73AE7200E93FD0 /* WineClass */, ); path = Cells; sourceTree = ""; }; - 16B97CF52C4BFAEC00D8B453 /* Default */ = { - isa = PBXGroup; - children = ( - ); - path = Default; - sourceTree = ""; - }; 16B97CF62C4BFAFD00D8B453 /* Search */ = { isa = PBXGroup; children = ( @@ -505,10 +531,8 @@ 16B97D032C4C0CD700D8B453 /* WineInfoViewController.swift */, 16B97D052C4C0CF800D8B453 /* WineStoreListViewController.swift */, 16B97D072C4C0D8100D8B453 /* WineOrderViewController.swift */, - 1F3CEAD52C669FD2002A4BC0 /* WineListCollectionViewCell.swift */, - 1FBD19522C6CFABB005C16A8 /* WineShopListCollectionViewCell.swift */, 1FBD19542C6D2BF7005C16A8 /* ReviewListViewController.swift */, - 1FBD19562C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift */, + 1F8FECA22C71D9EE00704491 /* ExViewController.swift */, ); path = Search; sourceTree = ""; @@ -523,9 +547,6 @@ 5E22194D2C69D5E7005849FB /* ChooseTasteViewController.swift */, 5E22196D2C6B2EA0005849FB /* RatingViewController.swift */, 5E2219722C6B661A005849FB /* CheckNoteViewController.swift */, - 5E22194C2C69D5E7005849FB /* CustomSlider.swift */, - 5E2219512C69D5E7005849FB /* CustomSuggestionCell.swift */, - 5E22194F2C69D5E7005849FB /* PolygonChartView.swift */, ); path = TastingNote; sourceTree = ""; @@ -533,7 +554,6 @@ 16B97CF82C4BFB2400D8B453 /* WineClass */ = { isa = PBXGroup; children = ( - 165401482C6F415F008A9DBF /* CardSliderSwiftUI */, 16B97D112C4C0F2400D8B453 /* WineClassMainViewController.swift */, 16B97D132C4C0F4100D8B453 /* ClassVideoViewController.swift */, 16B97D152C4C0F6400D8B453 /* SavingVideoViewController.swift */, @@ -552,9 +572,6 @@ 5E22193C2C69D5D0005849FB /* CommunityInfoViewController.swift */, 5E22193F2C69D5D0005849FB /* CommunityListViewController.swift */, 5E22193B2C69D5D0005849FB /* CreateNewCommViewController.swift */, - 5E22193E2C69D5D0005849FB /* CustomCollectionViewCell.swift */, - 5E2219392C69D5D0005849FB /* CustomCommentsCollectionView.swift */, - 5E2219382C69D5D0005849FB /* CustomTableViewCell.swift */, 5E22193A2C69D5D0005849FB /* ModalViewController.swift */, 5E22193D2C69D5D0005849FB /* SearchCommunityViewController.swift */, ); @@ -564,7 +581,15 @@ 16B97CFB2C4BFB5E00D8B453 /* Settings */ = { isa = PBXGroup; children = ( - 1F8DE5782C4D5A4D00961A59 /* SettingMainController.swift */, + 16C19AB72C73AB6300E93FD0 /* MyPageBusinessViewController.swift */, + 16C19AB92C73AB6300E93FD0 /* MypageInfoBottomViewController.swift */, + 16C19AB62C73AB6300E93FD0 /* MyPageNoticeViewController.swift */, + 16C19AB82C73AB6300E93FD0 /* MyPageOrderViewController.swift */, + 16C19AB52C73AB6300E93FD0 /* MyPageQnaViewController.swift */, + 16C19ABA2C73AB6300E93FD0 /* MyPageSettingsViewController.swift */, + 16C19AB42C73AB6300E93FD0 /* MyPageSuggestViewController.swift */, + 16C19ABC2C73AB6300E93FD0 /* MypageViewController.swift */, + 16C19ABB2C73AB6300E93FD0 /* WishListViewController.swift */, ); path = Settings; sourceTree = ""; @@ -576,8 +601,6 @@ 16B97CFF2C4BFC7300D8B453 /* ShoppingCartListViewController.swift */, 1F8DE5762C4D4ED700961A59 /* MainTabBarViewController.swift */, 1F598EE92C5227C5000CE79F /* AdImageCollectionViewCell.swift */, - 1F598EEB2C524D2E000CE79F /* RecomCollectionViewCell.swift */, - 1F205A302C68BB5200E80659 /* CartListCollectionViewCell.swift */, ); path = Main; sourceTree = ""; @@ -590,6 +613,70 @@ path = ShoppingCart; sourceTree = ""; }; + 16C19AAE2C73A39A00E93FD0 /* Managers */ = { + isa = PBXGroup; + children = ( + 1654010A2C6BACDC008A9DBF /* SelectionManager.swift */, + 16C19AA52C70B67200E93FD0 /* ShoppingListManager.swift */, + ); + path = Managers; + sourceTree = ""; + }; + 16C19AC62C73AC1C00E93FD0 /* Main */ = { + isa = PBXGroup; + children = ( + 1F598F022C581A7D000CE79F /* StartLoginCollectionViewCell.swift */, + 1F598EEB2C524D2E000CE79F /* RecomCollectionViewCell.swift */, + 1F205A302C68BB5200E80659 /* CartListCollectionViewCell.swift */, + ); + path = Main; + sourceTree = ""; + }; + 16C19AC72C73AC4000E93FD0 /* TasteTest */ = { + isa = PBXGroup; + children = ( + 1F205A3E2C6B37BF00E80659 /* TasteTestFirstCollectionViewCell.swift */, + 1F205A402C6B540600E80659 /* TasteTestSecondCollectionViewCell.swift */, + 1F205A422C6B66EB00E80659 /* TasteTestThirdCollectionViewCell.swift */, + ); + path = TasteTest; + sourceTree = ""; + }; + 16C19AC82C73AC9000E93FD0 /* Search */ = { + isa = PBXGroup; + children = ( + 1F3CEAD52C669FD2002A4BC0 /* WineListCollectionViewCell.swift */, + 1FBD19522C6CFABB005C16A8 /* WineShopListCollectionViewCell.swift */, + 1FBD19562C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift */, + ); + path = Search; + sourceTree = ""; + }; + 16C19ACF2C73AD5000E93FD0 /* Protocols */ = { + isa = PBXGroup; + children = ( + 16C19AC92C73ACD700E93FD0 /* NewNoteFooterDelegate.swift */, + ); + path = Protocols; + sourceTree = ""; + }; + 16C19AD02C73ADC900E93FD0 /* TastingNote */ = { + isa = PBXGroup; + children = ( + 16C19ACB2C73ACFF00E93FD0 /* NoteCollectionViewCell.swift */, + 5E2219512C69D5E7005849FB /* CustomSuggestionCell.swift */, + ); + path = TastingNote; + sourceTree = ""; + }; + 16C19ADA2C73AE7200E93FD0 /* WineClass */ = { + isa = PBXGroup; + children = ( + 16C19AD72C73AE5E00E93FD0 /* WineClassCell.swift */, + ); + path = WineClass; + sourceTree = ""; + }; 1F598EEF2C58136B000CE79F /* Login */ = { isa = PBXGroup; children = ( @@ -597,7 +684,6 @@ 1F598EFC2C58150E000CE79F /* JoinViewController.swift */, 1F598EFE2C58151B000CE79F /* SelectLoginViewController.swift */, 1F598F002C581573000CE79F /* LoginViewController.swift */, - 1F598F022C581A7D000CE79F /* StartLoginCollectionViewCell.swift */, ); path = Login; sourceTree = ""; @@ -611,9 +697,6 @@ 1F205A382C6B33F700E80659 /* ThirdKindTasteTestViewController.swift */, 1F205A3A2C6B343300E80659 /* ThirdNationTasteTestViewController.swift */, 1F205A3C2C6B34A300E80659 /* ThirdVarietyTasteTestViewController.swift */, - 1F205A3E2C6B37BF00E80659 /* TasteTestFirstCollectionViewCell.swift */, - 1F205A402C6B540600E80659 /* TasteTestSecondCollectionViewCell.swift */, - 1F205A422C6B66EB00E80659 /* TasteTestThirdCollectionViewCell.swift */, 1F205A442C6B707C00E80659 /* WhatsURNameViewController.swift */, ); path = TasteTest; @@ -726,22 +809,29 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 16C19AB22C73A3FD00E93FD0 /* MemberResponse.swift in Sources */, 16B97D042C4C0CD700D8B453 /* WineInfoViewController.swift in Sources */, + 16C19AC22C73AB6300E93FD0 /* MypageInfoBottomViewController.swift in Sources */, 1F205A392C6B33F700E80659 /* ThirdKindTasteTestViewController.swift in Sources */, 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 */, + 16C19ACC2C73ACFF00E93FD0 /* NoteCollectionViewCell.swift in Sources */, 1654014E2C6F9582008A9DBF /* APIResponseNoteResponse.swift in Sources */, 5E2219552C69D5E7005849FB /* CustomSlider.swift in Sources */, + 16C19ADC2C73AE8D00E93FD0 /* CarouselLayout.swift in Sources */, + 16C19ABE2C73AB6300E93FD0 /* MyPageQnaViewController.swift in Sources */, 1654010B2C6BACDC008A9DBF /* SelectionManager.swift in Sources */, + 16C19AC42C73AB6300E93FD0 /* WishListViewController.swift in Sources */, 16752F9D2C5A7FB90001907D /* HexCode.swift in Sources */, 1F598F0B2C5CBD9E000CE79F /* EnterTasteTestViewController.swift in Sources */, 1F8F99FA2C6F538300EAEF6C /* WineInfoResponse.swift in Sources */, 5E22196E2C6B2EA0005849FB /* RatingViewController.swift in Sources */, 1F205A432C6B66EB00E80659 /* TasteTestThirdCollectionViewCell.swift in Sources */, 1FBD19572C6DDBAB005C16A8 /* ReviewListCollectionViewCell.swift in Sources */, + 16C19AC52C73AB6300E93FD0 /* MypageViewController.swift in Sources */, 5E23147F2C5901BB004E2013 /* (null) in Sources */, 16B97D162C4C0F6400D8B453 /* SavingVideoViewController.swift in Sources */, 165400F82C69EFBD008A9DBF /* WineNewsResponse.swift in Sources */, @@ -750,8 +840,11 @@ 1F205A412C6B540600E80659 /* TasteTestSecondCollectionViewCell.swift in Sources */, 5E2219542C69D5E7005849FB /* NoteListViewController.swift in Sources */, 1F8DE5772C4D4ED800961A59 /* MainTabBarViewController.swift in Sources */, + 1F8FECA52C71E0A700704491 /* CustomPickerButton.swift in Sources */, 1F598EFD2C58150E000CE79F /* JoinViewController.swift in Sources */, + 1F8FECA32C71D9EE00704491 /* ExViewController.swift in Sources */, 165400E32C69D6B9008A9DBF /* CallMoyaExample.swift in Sources */, + 16C19ACA2C73ACD700E93FD0 /* NewNoteFooterDelegate.swift in Sources */, 165400E72C69DDBE008A9DBF /* TastingNoteAPI.swift in Sources */, 1654010F2C6E2B4B008A9DBF /* MyCollectionViewController.swift in Sources */, 16B97CEC2C4BF37E00D8B453 /* Constant.swift in Sources */, @@ -761,7 +854,9 @@ 16C19AAB2C7194D200E93FD0 /* LoginResponse.swift in Sources */, 1F8F99F52C6F40F400EAEF6C /* APIResponseWineSearchResponse.swift in Sources */, 165401072C6BA5D8008A9DBF /* MemberInfoRequest.swift in Sources */, + 16C19AD22C73AE0200E93FD0 /* UIView.swift in Sources */, 1F205A372C6A71BC00E80659 /* APIResponseLoginResponse.swift in Sources */, + 16C19AC12C73AB6300E93FD0 /* MyPageOrderViewController.swift in Sources */, 165400FA2C69F15D008A9DBF /* APIResponseWineNewsResponse.swift in Sources */, 1F205A452C6B707C00E80659 /* WhatsURNameViewController.swift in Sources */, 5E2219582C69D5E7005849FB /* PolygonChartView.swift in Sources */, @@ -782,6 +877,7 @@ 1F8F99FE2C6FACF600EAEF6C /* WineReviewResponse.swift in Sources */, 165400F32C69DE2D008A9DBF /* CommentsAPI.swift in Sources */, 16B97CD62C4BEB0900D8B453 /* SceneDelegate.swift in Sources */, + 16C19ACE2C73AD3000E93FD0 /* String.swift in Sources */, 16B97D082C4C0D8100D8B453 /* WineOrderViewController.swift in Sources */, 1F205A3B2C6B343300E80659 /* ThirdNationTasteTestViewController.swift in Sources */, 1F8F99FC2C6F53A300EAEF6C /* APIResponseWineInfoResponse.swift in Sources */, @@ -792,9 +888,11 @@ 165401112C6E2B79008A9DBF /* WineNewsViewController.swift in Sources */, 165400E52C69DDB6008A9DBF /* LoginAPI.swift in Sources */, 5E2219412C69D5D0005849FB /* CustomTableViewCell.swift in Sources */, + 16C19AD82C73AE5E00E93FD0 /* WineClassCell.swift in Sources */, 1F598F012C581573000CE79F /* LoginViewController.swift in Sources */, - 5E2219422C69D5D0005849FB /* CustomCommentsCollectionView.swift in Sources */, + 5E2219422C69D5D0005849FB /* CustomCommentsCollectionViewCell.swift in Sources */, 16B97D122C4C0F2400D8B453 /* WineClassMainViewController.swift in Sources */, + 16C19AD42C73AE1C00E93FD0 /* CustomButton.swift in Sources */, 1F205A3F2C6B37BF00E80659 /* TasteTestFirstCollectionViewCell.swift in Sources */, 16C19AA92C70B8D500E93FD0 /* UserWineData.swift in Sources */, 165400EB2C69DDD9008A9DBF /* WineClassBookmarkAPI.swift in Sources */, @@ -807,23 +905,29 @@ 1F205A332C69FE9800E80659 /* JoinNLoginRequest.swift in Sources */, 1F205A3D2C6B34A300E80659 /* ThirdVarietyTasteTestViewController.swift in Sources */, 1FBD19552C6D2BF7005C16A8 /* ReviewListViewController.swift in Sources */, - 1F8DE5792C4D5A4D00961A59 /* SettingMainController.swift in Sources */, + 16C19AC32C73AB6300E93FD0 /* MyPageSettingsViewController.swift in Sources */, 165401552C6FC5CD008A9DBF /* HomeResponse.swift in Sources */, + 16C19ADE2C73AF6000E93FD0 /* UserDefaults.swift in Sources */, 165400ED2C69DDF2008A9DBF /* WineNewsAPI.swift in Sources */, 1F8F9A002C6FADBE00EAEF6C /* APIResponseWineReviewResponse.swift in Sources */, + 16C19AB02C73A3B100E93FD0 /* AppleLoginResponse.swift in Sources */, 5E2219532C69D5E7005849FB /* NoteInfoViewController.swift in Sources */, 165400FE2C69F218008A9DBF /* APIResponseWineClassResponse.swift in Sources */, 16B97D142C4C0F4100D8B453 /* ClassVideoViewController.swift in Sources */, + 16C19ABD2C73AB6300E93FD0 /* MyPageSuggestViewController.swift in Sources */, 165401572C6FC618008A9DBF /* APIResponseHomeResponse.swift in Sources */, 1F598F032C581A7D000CE79F /* StartLoginCollectionViewCell.swift in Sources */, 5E2219452C69D5D0005849FB /* CommunityInfoViewController.swift in Sources */, 1F598EFB2C5814F9000CE79F /* EnterLoginViewController.swift in Sources */, + 16C19ABF2C73AB6300E93FD0 /* MyPageNoticeViewController.swift in Sources */, 1F8F99F32C6F386B00EAEF6C /* SearchAPI.swift in Sources */, 16C19AA62C70B67200E93FD0 /* ShoppingListManager.swift in Sources */, 16B97D022C4BFC9800D8B453 /* SearchHomeViewController.swift in Sources */, + 16C19AD62C73AE3900E93FD0 /* UIConstants.swift in Sources */, 5E2219732C6B661A005849FB /* CheckNoteViewController.swift in Sources */, 1654014C2C6F41B0008A9DBF /* ContentView.swift in Sources */, 5E2219442C69D5D0005849FB /* CreateNewCommViewController.swift in Sources */, + 16C19AC02C73AB6300E93FD0 /* MyPageBusinessViewController.swift in Sources */, 5E2219472C69D5D0005849FB /* CustomCollectionViewCell.swift in Sources */, 5E22195B2C69D5E7005849FB /* WriteNoteViewController.swift in Sources */, 165401132C6E2BAA008A9DBF /* WineKnowledgeViewController.swift in Sources */, diff --git a/Drink-EG/Drink-EG/Resources/APIs/LoginAPI.swift b/Drink-EG/Drink-EG/Resources/APIs/LoginAPI.swift index d322e66..502d540 100644 --- a/Drink-EG/Drink-EG/Resources/APIs/LoginAPI.swift +++ b/Drink-EG/Drink-EG/Resources/APIs/LoginAPI.swift @@ -11,6 +11,7 @@ import Moya enum LoginAPI { case postLogin(data: JoinNLoginRequest) case postRegister(data : JoinNLoginRequest) + case postAppleLogin(identityTokenString: String) } extension LoginAPI: TargetType { @@ -27,6 +28,8 @@ extension LoginAPI: TargetType { return "/login" case .postRegister: return "/join" + case .postAppleLogin: + return"/login/apple" } } @@ -37,6 +40,8 @@ extension LoginAPI: TargetType { return .post case .postRegister: return .post + case .postAppleLogin: + return .post } } @@ -44,17 +49,16 @@ extension LoginAPI: TargetType { switch self { case .postLogin(let data), .postRegister(let data) : return .requestJSONEncodable(data) + case .postAppleLogin(let identityTokenString) : + return .requestParameters(parameters: ["identityToken" : identityTokenString], encoding: JSONEncoding.default) } } // API 호출 시, header에 token 넣어서 전달 var headers: [String : String]? { - switch self { - case .postLogin, .postRegister: - return [ - "Content-type": "application/json" - ] - } + return [ + "Content-type": "application/json" + ] } var validationType: ValidationType { diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 416.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 416.png deleted file mode 100644 index 5410de5..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/AdSampleImage/ad2.imageset/Group 416.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Contents.json index a56311d..0462fa7 100644 --- a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Contents.json +++ b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Contents.json @@ -6,12 +6,12 @@ "scale" : "1x" }, { - "filename" : "Rectangle 112 (1).png", + "filename" : "Rectangle 112@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "Rectangle 112 (2).png", + "filename" : "Rectangle 112@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112 (1).png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112 (1).png deleted file mode 100644 index db82690..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112 (1).png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112 (2).png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112 (2).png deleted file mode 100644 index 4857f1c..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112 (2).png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112.png index 7c0977d..0c436d4 100644 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112.png and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112@2x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112@2x.png new file mode 100644 index 0000000..01d36ac Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112@2x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112@3x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112@3x.png new file mode 100644 index 0000000..760c13b Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/HomeGoToTastingNote.imageset/Rectangle 112@3x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_check_fill.imageset/Group 432.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_check_fill.imageset/Group 432.png deleted file mode 100644 index b8fd8b7..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/icon_check_fill.imageset/Group 432.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Contents.json b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Contents.json new file mode 100644 index 0000000..df240cf --- /dev/null +++ b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Vector.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Vector@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Vector@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector.png new file mode 100644 index 0000000..782ec6a Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector@2x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector@2x.png new file mode 100644 index 0000000..44fa0f3 Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector@2x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector@3x.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector@3x.png new file mode 100644 index 0000000..ef91458 Binary files /dev/null and b/Drink-EG/Drink-EG/Resources/Assets.xcassets/Icon/pickerView.imageset/Vector@3x.png differ diff --git a/Drink-EG/Drink-EG/Resources/Assets.xcassets/LaunchLogo.imageset/Group 374.png b/Drink-EG/Drink-EG/Resources/Assets.xcassets/LaunchLogo.imageset/Group 374.png deleted file mode 100644 index 0bdb73e..0000000 Binary files a/Drink-EG/Drink-EG/Resources/Assets.xcassets/LaunchLogo.imageset/Group 374.png and /dev/null differ diff --git a/Drink-EG/Drink-EG/Resources/Extensions/String.swift b/Drink-EG/Drink-EG/Resources/Extensions/String.swift new file mode 100644 index 0000000..c0eba27 --- /dev/null +++ b/Drink-EG/Drink-EG/Resources/Extensions/String.swift @@ -0,0 +1,16 @@ +// +// String.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import UIKit + +extension String { + var unescapedString: String { + let mutableString = NSMutableString(string: self) + CFStringTransform(mutableString, nil, "Any-Hex/Java" as NSString, true) + return mutableString as String + } +} diff --git a/Drink-EG/Drink-EG/Resources/Extensions/UIView.swift b/Drink-EG/Drink-EG/Resources/Extensions/UIView.swift new file mode 100644 index 0000000..c9db4bf --- /dev/null +++ b/Drink-EG/Drink-EG/Resources/Extensions/UIView.swift @@ -0,0 +1,37 @@ +// +// UIView.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import UIKit + +extension UIView { + + func applyTopShadow(shadowColor: UIColor = .black, shadowOpacity: Float = 0.25, shadowRadius: CGFloat = 5, shadowOffset: CGSize = CGSize(width: 0, height: -3)) { + // 그림자 색상 + self.layer.shadowColor = shadowColor.cgColor + + // 그림자 투명도 + self.layer.shadowOpacity = shadowOpacity + + // 그림자 퍼짐 정도 + self.layer.shadowRadius = shadowRadius + + // 그림자 오프셋 (상단에만 그림자가 보이도록 설정) + self.layer.shadowOffset = shadowOffset + + // 레이아웃이 완료된 후에 shadowPath 설정 + DispatchQueue.main.async { + let shadowPath = UIBezierPath() + shadowPath.move(to: CGPoint(x: 0, y: 0)) + shadowPath.addLine(to: CGPoint(x: self.bounds.width, y: 0)) + shadowPath.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height / 4)) + shadowPath.addLine(to: CGPoint(x: 0, y: self.bounds.height / 4)) + shadowPath.close() + + self.layer.shadowPath = shadowPath.cgPath + } + } +} diff --git a/Drink-EG/Drink-EG/Resources/Extensions/UserDefaults.swift b/Drink-EG/Drink-EG/Resources/Extensions/UserDefaults.swift new file mode 100644 index 0000000..34b4403 --- /dev/null +++ b/Drink-EG/Drink-EG/Resources/Extensions/UserDefaults.swift @@ -0,0 +1,28 @@ +// +// UserDefaults.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import UIKit + +extension UserDefaults { + private enum Keys { + static let comments = "comments" + } + + func saveComments(_ comments: [Comment]) { + if let encoded = try? JSONEncoder().encode(comments) { + self.set(encoded, forKey: Keys.comments) + } + } + + func loadComments() -> [Comment] { + if let savedData = self.data(forKey: Keys.comments), + let savedComments = try? JSONDecoder().decode([Comment].self, from: savedData) { + return savedComments + } + return [] + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Community/CustomCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/CustomCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/Community/CustomCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/CustomCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/Community/CustomCommentsCollectionView.swift b/Drink-EG/Drink-EG/Sources/Cells/CustomCommentsCollectionViewCell.swift similarity index 97% rename from Drink-EG/Drink-EG/Sources/VCs/Community/CustomCommentsCollectionView.swift rename to Drink-EG/Drink-EG/Sources/Cells/CustomCommentsCollectionViewCell.swift index 97cc3a3..5349d05 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Community/CustomCommentsCollectionView.swift +++ b/Drink-EG/Drink-EG/Sources/Cells/CustomCommentsCollectionViewCell.swift @@ -1,6 +1,6 @@ import UIKit -class CustomCommentsCollectionView: UITableViewCell { +class CustomCommentsCollectionViewCell: UITableViewCell { let profileImageView = UIImageView() let nameLabel = UILabel() let dateLabel = UILabel() diff --git a/Drink-EG/Drink-EG/Sources/VCs/Community/CustomTableViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/CustomTableViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/Community/CustomTableViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/CustomTableViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/CartListCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/Main/CartListCollectionViewCell.swift similarity index 82% rename from Drink-EG/Drink-EG/Sources/VCs/Main/CartListCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/Main/CartListCollectionViewCell.swift index ecdd392..1670e93 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/CartListCollectionViewCell.swift +++ b/Drink-EG/Drink-EG/Sources/Cells/Main/CartListCollectionViewCell.swift @@ -7,42 +7,49 @@ import UIKit import SnapKit +import SDWebImage protocol CartListCollectionViewCellDelegate: AnyObject { func checkButtonTapped(on cell: CartListCollectionViewCell, isSelected: Bool) + func deleteButtonTapped(on cell: CartListCollectionViewCell) + func quantityChanged(in cell: CartListCollectionViewCell) + func didTapChangeStoreButton(on cell: CartListCollectionViewCell) } class CartListCollectionViewCell: UICollectionViewCell { weak var delegate: CartListCollectionViewCellDelegate? - var changeMarketButtonAction : (() -> Void) = {} var quantity: Int = 1 { didSet { updateNumLabel() + configureMarketNPlace(self.shop, self.price, self.quantity) } } + //이전 수량을 저장 + var previousQuantity: Int = 1 private let CheckImage = UIImage(named: "icon_cartCheck_fill") private let nCheckImage = UIImage(named: "icon_cartCheck_nfill") let CheckButton = UIButton(type: .custom) var shop = "PODO" var price = 0 + var wineImage: String? private let imageView: UIImageView = { let iv = UIImageView() - iv.image = UIImage(named: "Loxton") iv.layer.cornerRadius = 10 iv.layer.masksToBounds = true return iv }() - private let name: UILabel = { + let name: UILabel = { let l1 = UILabel() l1.text = "Loxton" l1.font = .boldSystemFont(ofSize: 18) l1.textColor = .black - l1.numberOfLines = 0 + l1.numberOfLines = 2 + l1.lineBreakMode = .byTruncatingTail // 생략 부호(...)가 꼬리에 위치하도록 설정 return l1 }() @@ -62,7 +69,7 @@ class CartListCollectionViewCell: UICollectionViewCell { }() @objc private func changeMarketButtonTapped() { - changeMarketButtonAction() + delegate?.didTapChangeStoreButton(on: self) } private let changeNumButton: UIButton = { @@ -86,6 +93,7 @@ class CartListCollectionViewCell: UICollectionViewCell { private func updateNumLabel() { let label = "\(quantity)" NumLabel.text = label + delegate?.quantityChanged(in: self) // 수량 변경 시 delegate 호출 } @objc func changeNumButtonTapped(_ sender: UIButton, forEvent event: UIEvent) { @@ -105,10 +113,12 @@ class CartListCollectionViewCell: UICollectionViewCell { } private func decreaseQuantity() { + previousQuantity = quantity quantity = max(quantity - 1, 1) } private func increaseQuantity() { + previousQuantity = quantity quantity += 1 } @@ -120,9 +130,14 @@ class CartListCollectionViewCell: UICollectionViewCell { b.setImage(image, for: .normal) b.tintColor = UIColor(hex: "999999") b.backgroundColor = .clear + b.addTarget(self, action: #selector(deleteButtonTapped), for: .touchUpInside) return b }() + @objc private func deleteButtonTapped() { + delegate?.deleteButtonTapped(on: self) // 델리게이트 호출 + } + func configureCheckButton() { CheckButton.setImage(nCheckImage?.withRenderingMode(.alwaysOriginal), for: .normal) CheckButton.backgroundColor = .clear @@ -147,7 +162,7 @@ class CartListCollectionViewCell: UICollectionViewCell { delegate?.checkButtonTapped(on: self, isSelected: sender.isSelected) } - private func configureMarketNPlace(_ shopName: String, _ priceInt: Int, _ count: Int) { + func configureMarketNPlace(_ shopName: String, _ priceInt: Int, _ count: Int) { let firstImageAttachment = NSTextAttachment() firstImageAttachment.image = UIImage(named: "icon_market") @@ -222,33 +237,36 @@ class CartListCollectionViewCell: UICollectionViewCell { } name.snp.makeConstraints { make in - make.top.equalTo(imageView) - make.leading.equalTo(imageView.snp.trailing).offset(15) + make.top.equalToSuperview().offset(13) + make.leading.equalTo(imageView.snp.trailing).offset(13) + if UIDevice.current.userInterfaceIdiom == .phone { + make.width.lessThanOrEqualTo(180) //185 + } + make.height.lessThanOrEqualTo(45) } marketNprice.snp.makeConstraints { make in - make.top.equalTo(name.snp.bottom).offset(7) + make.top.equalTo(name.snp.bottom).offset(3) make.leading.equalTo(name) } - changeMarketButton.snp.makeConstraints { make in - make.bottom.equalToSuperview().inset(14) - make.leading.equalToSuperview().offset(213) - make.width.greaterThanOrEqualTo(67) - make.height.greaterThanOrEqualTo(24) - } - changeNumButton.snp.makeConstraints { make in - make.top.equalTo(changeMarketButton) - make.leading.equalTo(changeMarketButton.snp.trailing).offset(6) + make.bottom.equalToSuperview().inset(10) + make.trailing.equalToSuperview().inset(12) make.width.greaterThanOrEqualTo(63) make.height.greaterThanOrEqualTo(26) } + changeMarketButton.snp.makeConstraints { make in + make.top.equalTo(changeNumButton) + make.trailing.equalTo(changeNumButton.snp.leading).offset(-6) + make.width.greaterThanOrEqualTo(67) + make.height.greaterThanOrEqualTo(20) + } + NumLabel.snp.makeConstraints { make in make.centerX.centerY.equalToSuperview() } - deleteButton.snp.makeConstraints { make in make.top.equalToSuperview().offset(20) make.trailing.equalToSuperview().inset(14) @@ -256,9 +274,11 @@ class CartListCollectionViewCell: UICollectionViewCell { } } - func configure1(imageName: String, wineName: String, price: Int, count: Int, shopName: String) { - if let image = UIImage(named: imageName) { - imageView.image = image + func configure1(imageName: String?, wineName: String, price: Int, count: Int, shopName: String) { + if let imageUrl = imageName, let url = URL(string: imageUrl) { + self.imageView.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) + } else { + self.imageView.image = UIImage(named: "Loxton") } self.name.text = wineName @@ -273,4 +293,3 @@ class CartListCollectionViewCell: UICollectionViewCell { CheckButton.isSelected = isSelected } } - diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/RecomCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/Main/RecomCollectionViewCell.swift similarity index 81% rename from Drink-EG/Drink-EG/Sources/VCs/Main/RecomCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/Main/RecomCollectionViewCell.swift index 3b8b43f..e084fb8 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/RecomCollectionViewCell.swift +++ b/Drink-EG/Drink-EG/Sources/Cells/Main/RecomCollectionViewCell.swift @@ -13,17 +13,17 @@ import SDWebImage class RecomCollectionViewCell: UICollectionViewCell { private let imageView: UIImageView = { - let iv = UIImageView() - return iv + let iv = UIImageView() + return iv }() private let label1: UILabel = { let l1 = UILabel() - l1.font = .systemFont(ofSize: 14, weight: .bold) + l1.font = .systemFont(ofSize: 13, weight: .bold) l1.textColor = .black - l1.numberOfLines = 0 - l1.adjustsFontSizeToFitWidth = true - l1.minimumScaleFactor = 0.7 + l1.numberOfLines = 2 + //l1.adjustsFontSizeToFitWidth = true + l1.lineBreakMode = .byTruncatingTail // 생략 부호(...)가 꼬리에 위치하도록 설정 return l1 }() @@ -64,10 +64,10 @@ class RecomCollectionViewCell: UICollectionViewCell { } label1.snp.makeConstraints { make in - make.leading.equalTo(imageView.snp.leading).offset(9) + make.leading.trailing.equalToSuperview().inset(15) make.top.equalTo(view.snp.top).offset(10) - make.width.lessThanOrEqualToSuperview().inset(10) - make.height.lessThanOrEqualTo(30) +// make.width.lessThanOrEqualToSuperview().inset(15) + make.height.lessThanOrEqualTo(35) } view.snp.makeConstraints { make in diff --git a/Drink-EG/Drink-EG/Sources/VCs/Login/StartLoginCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/Main/StartLoginCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/Login/StartLoginCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/Main/StartLoginCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/Search/ReviewListCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/Search/ReviewListCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineListCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/Search/WineListCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/Search/WineListCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/Search/WineListCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineShopListCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/Search/WineShopListCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/Search/WineShopListCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/Search/WineShopListCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/TasteTestFirstCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/TasteTest/TasteTestFirstCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/TasteTest/TasteTestFirstCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/TasteTest/TasteTestFirstCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/TasteTestSecondCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/TasteTest/TasteTestSecondCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/TasteTest/TasteTestSecondCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/TasteTest/TasteTestSecondCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/TasteTestThirdCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/TasteTest/TasteTestThirdCollectionViewCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/TasteTest/TasteTestThirdCollectionViewCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/TasteTest/TasteTestThirdCollectionViewCell.swift diff --git a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSuggestionCell.swift b/Drink-EG/Drink-EG/Sources/Cells/TastingNote/CustomSuggestionCell.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSuggestionCell.swift rename to Drink-EG/Drink-EG/Sources/Cells/TastingNote/CustomSuggestionCell.swift diff --git a/Drink-EG/Drink-EG/Sources/Cells/TastingNote/NoteCollectionViewCell.swift b/Drink-EG/Drink-EG/Sources/Cells/TastingNote/NoteCollectionViewCell.swift new file mode 100644 index 0000000..f8703a4 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Cells/TastingNote/NoteCollectionViewCell.swift @@ -0,0 +1,49 @@ +// +// NoteCollectionViewCell.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import Foundation +import UIKit +import SnapKit +import Moya + +class NoteCollectionViewCell: UICollectionViewCell { // 셀에 이미지와 label을 추가하기 위한 커스텀 셀 + + let imageView = UIImageView() // CollectionView에 image와 label 추가 + let nameLabel = UILabel() + + override init(frame: CGRect) { + super.init(frame: frame) + contentView.addSubview(imageView) + contentView.addSubview(nameLabel) + + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.layer.cornerRadius = 10 + + nameLabel.textAlignment = .center + nameLabel.font = UIFont.systemFont(ofSize: 12) + nameLabel.textColor = .black + nameLabel.numberOfLines = 2 + + imageView.snp.makeConstraints { make in + make.top.leading.trailing.equalToSuperview() + make.height.equalTo(contentView.snp.width) + } + + nameLabel.snp.makeConstraints { make in + make.top.equalTo(imageView.snp.bottom).offset(5) + make.leading.trailing.equalToSuperview() + } + + contentView.layer.cornerRadius = 10 + contentView.layer.masksToBounds = true + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Drink-EG/Drink-EG/Sources/Cells/WineClass/WineClassCell.swift b/Drink-EG/Drink-EG/Sources/Cells/WineClass/WineClassCell.swift new file mode 100644 index 0000000..6d5a8ae --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Cells/WineClass/WineClassCell.swift @@ -0,0 +1,41 @@ +// +// WineClassCell.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import UIKit + +class WineClassCell: UICollectionViewCell { + static let reuseIdentifier = "WineClassCell" + + let imageView = UIImageView() + + override init(frame: CGRect) { + super.init(frame: frame) + + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + contentView.addSubview(imageView) + + imageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + contentView.layer.cornerRadius = UIConstants.cellCornerRadius + contentView.layer.masksToBounds = true + contentView.layer.shadowColor = UIColor.black.cgColor + contentView.layer.shadowOpacity = UIConstants.cellShadowOpacity + contentView.layer.shadowOffset = UIConstants.cellShadowOffset + contentView.layer.shadowRadius = UIConstants.cellShadowRadius + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configure(with image: UIImage) { + imageView.image = image + } +} diff --git a/Drink-EG/Drink-EG/Sources/Datas/UIConstants.swift b/Drink-EG/Drink-EG/Sources/Datas/UIConstants.swift new file mode 100644 index 0000000..94f6b71 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Datas/UIConstants.swift @@ -0,0 +1,27 @@ +// +// UIConstants.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import UIKit + +struct UIConstants { + static let searchBarHeight: CGFloat = 34 + static let searchBarCornerRadius: CGFloat = 8 + static let labelFontSize: CGFloat = 28 + static let titleClassLabelFontSize: CGFloat = 24 + static let labelTopOffset: CGFloat = 10 + static let viewSideInset: CGFloat = 16 + static let classViewHeight: CGFloat = 250 + static let mainClassViewItemSize = CGSize(width: 100, height: 180) + static let mainClassViewSpacing: CGFloat = 20 + static let carouselSpacing: CGFloat = -90 + static let sideItemScale: CGFloat = 0.4 + static let sideItemAlpha: CGFloat = 0.8 + static let cellCornerRadius: CGFloat = 10 + static let cellShadowOpacity: Float = 0.3 + static let cellShadowOffset = CGSize(width: 0, height: 2) + static let cellShadowRadius: CGFloat = 5 +} diff --git a/Drink-EG/Drink-EG/Sources/Datas/WineNews/MemberResponse.swift b/Drink-EG/Drink-EG/Sources/Datas/WineNews/MemberResponse.swift new file mode 100644 index 0000000..d787e3d --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Datas/WineNews/MemberResponse.swift @@ -0,0 +1,21 @@ +// +// MemberResponse.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import Foundation + +struct MemberResponse : Codable { + let id : Int + let name : String + let username : String + let role : String + let isNewbie : Bool + let monthPriceMax : Int + let wineSort : [String] + let wineArea : [String] + let wineVariety : [String] + let region : String +} diff --git a/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseMemberResponse.swift b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseMemberResponse.swift index 516f53f..8dbbd8d 100644 --- a/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseMemberResponse.swift +++ b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/APIResponseMemberResponse.swift @@ -13,16 +13,3 @@ struct APIResponseMemberResponse : Codable { let message : String let result : MemberResponse? } - -struct MemberResponse : Codable { - let id : Int - let name : String - let username : String - let role : String - let isNewbie : Bool - let monthPriceMax : Int - let wineSort : [String] - let wineArea : [String] - let wineVariety : [String] - let region : String -} diff --git a/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/AppleLoginResponse.swift b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/AppleLoginResponse.swift new file mode 100644 index 0000000..5d0704c --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Models/APIResponseModels/AppleLoginResponse.swift @@ -0,0 +1,15 @@ +// +// AppleLoginResponse.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import Foundation + +struct AppleLoginResponse : Codable { + let isSuccess : Bool + let code : String + let message : String + let result : LoginResponse +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/WineClass/CardSliderSwiftUI/ContentView.swift b/Drink-EG/Drink-EG/Sources/Models/CardSliderSwiftUI/ContentView.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/WineClass/CardSliderSwiftUI/ContentView.swift rename to Drink-EG/Drink-EG/Sources/Models/CardSliderSwiftUI/ContentView.swift diff --git a/Drink-EG/Drink-EG/Sources/Models/CarouselLayout.swift b/Drink-EG/Drink-EG/Sources/Models/CarouselLayout.swift new file mode 100644 index 0000000..efc2cad --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Models/CarouselLayout.swift @@ -0,0 +1,203 @@ +// +// CarouselLayout.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import UIKit + +class CarouselLayout: UICollectionViewFlowLayout { + + public var sideItemScale: CGFloat = UIConstants.sideItemScale + public var sideItemAlpha: CGFloat = UIConstants.sideItemAlpha + public var spacing: CGFloat = UIConstants.carouselSpacing + + public var isPagingEnabled: Bool = false + + private var isSetup: Bool = false + + override public func prepare() { + super.prepare() + if isSetup == false { + setupLayout() + isSetup = true + } + } + + private func setupLayout() { + guard let collectionView = self.collectionView else { return } + + let collectionViewSize = collectionView.bounds.size + let xInset = (collectionViewSize.width - self.itemSize.width) / 2 + let yInset = (collectionViewSize.height - self.itemSize.height) / 2 + + self.sectionInset = UIEdgeInsets(top: yInset, left: xInset, bottom: yInset, right: xInset) + let itemWidth = self.itemSize.width + let scaledItemOffset = (itemWidth - (itemWidth * (self.sideItemScale + (1 - self.sideItemScale) / 2))) / 2 + self.minimumLineSpacing = spacing - scaledItemOffset + + self.scrollDirection = .horizontal + } + + public override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { + return true + } + + public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + guard let superAttributes = super.layoutAttributesForElements(in: rect), + let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] + else { return nil } + + return attributes.map({ self.transformLayoutAttributes(attributes: $0) }) + } + + private func transformLayoutAttributes(attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { + guard let collectionView = self.collectionView else { return attributes } + + let collectionCenter = collectionView.frame.size.width / 2 + let contentOffset = collectionView.contentOffset.x + let center = attributes.center.x - contentOffset + + let maxDistance = 8 * (self.itemSize.width + self.minimumLineSpacing) + let distance = min(abs(collectionCenter - center), maxDistance) + let ratio = (maxDistance - distance) / maxDistance + + let alpha = ratio * (1 - self.sideItemAlpha) + self.sideItemAlpha + let scale = ratio * (1 - self.sideItemScale) + self.sideItemScale + + attributes.alpha = alpha + if abs(collectionCenter - center) > maxDistance + 1 { + attributes.alpha = 0 + } + + let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size) + let dist = attributes.frame.midX - visibleRect.midX + var transform = CATransform3DScale(CATransform3DIdentity, scale, scale, 1) + transform = CATransform3DTranslate(transform, 0, 0, -abs(dist / 1000)) + attributes.transform3D = transform + + return attributes + } + + override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { + guard let collectionView = self.collectionView else { + let latestOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) + return latestOffset + } + + let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.frame.width, height: collectionView.frame.height) + guard let rectAttributes = super.layoutAttributesForElements(in: targetRect) else { return .zero } + + var offsetAdjustment = CGFloat.greatestFiniteMagnitude + let horizontalCenter = proposedContentOffset.x + collectionView.frame.width / 2 + + for layoutAttributes in rectAttributes { + let itemHorizontalCenter = layoutAttributes.center.x + if (itemHorizontalCenter - horizontalCenter).magnitude < offsetAdjustment.magnitude { + offsetAdjustment = itemHorizontalCenter - horizontalCenter + } + } + + return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y) + } +} + +//class CarouselLayout: UICollectionViewFlowLayout { +// +// public var sideItemScale: CGFloat = 0.8 // 측면 아이템의 크기 비율 +// public var sideItemAlpha: CGFloat = 0.6 // 측면 아이템의 투명도 +// public var spacing: CGFloat = -80 // 셀 간의 간격 (겹치도록 음수로 설정) +// +// public var isPagingEnabled: Bool = false +// +// private var isSetup: Bool = false +// +// override public func prepare() { +// super.prepare() +// if isSetup == false { +// setupLayout() +// isSetup = true +// } +// } +// +// private func setupLayout() { +// guard let collectionView = self.collectionView else { return } +// +// let collectionViewSize = collectionView.bounds.size +// let xInset = (collectionViewSize.width - self.itemSize.width) / 2 +// let yInset = (collectionViewSize.height - self.itemSize.height) / 2 +// +// self.sectionInset = UIEdgeInsets(top: yInset, left: xInset, bottom: yInset, right: xInset) +// +// // 셀 간의 간격 계산 (절반씩 겹치도록 설정) +// self.minimumLineSpacing = spacing +// +// self.scrollDirection = .horizontal +// } +// +// public override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { +// return true +// } +// +// public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { +// guard let superAttributes = super.layoutAttributesForElements(in: rect), +// let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] +// else { return nil } +// +// return attributes.map({ self.transformLayoutAttributes(attributes: $0) }) +// } +// +// private func transformLayoutAttributes(attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { +// guard let collectionView = self.collectionView else { return attributes } +// +// let collectionCenter = collectionView.frame.size.width / 2 +// let contentOffset = collectionView.contentOffset.x +// let center = attributes.center.x - contentOffset +// +// // 중앙에서 떨어진 거리 계산 +// let maxDistance = collectionView.frame.size.width / 2 +// let distance = min(abs(collectionCenter - center), maxDistance) +// let ratio = (maxDistance - distance) / maxDistance +// +// // 투명도 및 크기 조정 +// let alpha = ratio * (1 - self.sideItemAlpha) + self.sideItemAlpha +// let scale = ratio * (1 - self.sideItemScale) + self.sideItemScale +// +// attributes.alpha = alpha +// attributes.transform3D = CATransform3DMakeScale(scale, scale, 1) +// +// // 3D 효과 추가 (회전 효과) +// let rotationAngle = (1 - ratio) * (.pi / 8) // 최대 22.5도 회전 +// attributes.transform3D = CATransform3DRotate(attributes.transform3D, rotationAngle, 0, 1, 0) +// +// // 중앙에서 멀어지면 투명하게 +// if abs(collectionCenter - center) > maxDistance { +// attributes.alpha = 0 +// } +// +// return attributes +// } +// +// override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { +// guard let collectionView = self.collectionView else { +// let latestOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) +// return latestOffset +// } +// +// let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.frame.width, height: collectionView.frame.height) +// guard let rectAttributes = super.layoutAttributesForElements(in: targetRect) else { return .zero } +// +// var offsetAdjustment = CGFloat.greatestFiniteMagnitude +// let horizontalCenter = proposedContentOffset.x + collectionView.frame.width / 2 +// +// for layoutAttributes in rectAttributes { +// let itemHorizontalCenter = layoutAttributes.center.x +// if abs(itemHorizontalCenter - horizontalCenter) < abs(offsetAdjustment) { +// offsetAdjustment = itemHorizontalCenter - horizontalCenter +// } +// } +// +// return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y) +// } +//} diff --git a/Drink-EG/Drink-EG/Sources/Models/CustomButton.swift b/Drink-EG/Drink-EG/Sources/Models/CustomButton.swift new file mode 100644 index 0000000..4c27b87 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Models/CustomButton.swift @@ -0,0 +1,46 @@ +// +// CustomButton.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import UIKit + +class CustomButton: UIButton { + + override init(frame: CGRect) { + super.init(frame: frame) + setupButton() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupButton() + } + + private func setupButton() { + // 버튼 타이틀 설정 + self.setTitle("내 보관함", for: .normal) + self.setTitleColor(.lightGray, for: .normal) + + // 버튼 배경색 설정 + self.backgroundColor = .white + + // 버튼의 둥근 모서리 설정 + self.layer.cornerRadius = 15 + self.layer.masksToBounds = false + + // 그림자 설정 + self.layer.shadowColor = UIColor.black.cgColor + self.layer.shadowOpacity = 0.25 + self.layer.shadowOffset = CGSize(width: 0, height: 2) + self.layer.shadowRadius = 5 + } + + override func layoutSubviews() { + super.layoutSubviews() + // 버튼의 크기가 결정된 후에 그림자 경로 설정 + self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath + } +} diff --git a/Drink-EG/Drink-EG/Sources/Models/CustomPickerButton.swift b/Drink-EG/Drink-EG/Sources/Models/CustomPickerButton.swift new file mode 100644 index 0000000..ea12fc5 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Models/CustomPickerButton.swift @@ -0,0 +1,98 @@ +// +// CustomPickerButton.swift +// Drink-EG +// +// Created by 이현주 on 8/18/24. +// + +import UIKit +import SnapKit + +class CustomPickerButton: UIButton { + + var pickerView: UIPickerView? + var toolbar: UIToolbar? + var pickerData: [String] = [] + + let pickerButtonHeight: CGFloat = 22 + let buttonWidth: CGFloat = 100 + + override init(frame: CGRect) { + super.init(frame: frame) + setupButton() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupButton() + } + + private func setupButton() { + setTitle("분류 순서", for: .normal) + setImage(UIImage(named: "pickerView"), for: .normal) + backgroundColor = .white + setTitleColor(UIColor(hex: "#767676"), for: .normal) + titleLabel?.font = .boldSystemFont(ofSize: 12) + contentHorizontalAlignment = .center + imageEdgeInsets = UIEdgeInsets(top: 0, left: 80, bottom: 0, right: 0) + titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 20) + layer.cornerRadius = 5 + layer.borderWidth = 1 + layer.borderColor = UIColor(hex: "#999999")?.cgColor + addTarget(self, action: #selector(showPicker), for: .touchUpInside) + } + + func setupPickerView(_ pickerView: UIPickerView, toolbar: UIToolbar, pickerData: [String]) { + self.pickerView = pickerView + self.toolbar = toolbar + self.pickerData = pickerData + + pickerView.dataSource = self + pickerView.delegate = self + pickerView.backgroundColor = .white + pickerView.isHidden = true + + toolbar.isHidden = true + toolbar.sizeToFit() + let cancelButton = UIBarButtonItem(title: "취소", style: .plain, target: self, action: #selector(dismissPicker)) + let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) + let doneButton = UIBarButtonItem(title: "완료", style: .done, target: self, action: #selector(donePicker)) + toolbar.setItems([cancelButton, flexibleSpace, doneButton], animated: false) + } + + @objc private func showPicker() { + pickerView?.isHidden = false + toolbar?.isHidden = false + } + + @objc private func dismissPicker() { + pickerView?.isHidden = true + toolbar?.isHidden = true + } + + @objc private func donePicker() { + if let pickerView = pickerView { + let selectedOption = pickerData[pickerView.selectedRow(inComponent: 0)] + setTitle(selectedOption, for: .normal) + titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) + setImage(nil, for: .normal) + dismissPicker() + } + } +} + +// MARK: - UIPickerViewDataSource & UIPickerViewDelegate +extension CustomPickerButton: UIPickerViewDataSource, UIPickerViewDelegate { + func numberOfComponents(in pickerView: UIPickerView) -> Int { + return 1 + } + + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return pickerData.count + } + + func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return pickerData[row] + } +} + diff --git a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSlider.swift b/Drink-EG/Drink-EG/Sources/Models/CustomSlider.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/TastingNote/CustomSlider.swift rename to Drink-EG/Drink-EG/Sources/Models/CustomSlider.swift diff --git a/Drink-EG/Drink-EG/Sources/Models/SelectionManager.swift b/Drink-EG/Drink-EG/Sources/Models/Managers/SelectionManager.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/Models/SelectionManager.swift rename to Drink-EG/Drink-EG/Sources/Models/Managers/SelectionManager.swift diff --git a/Drink-EG/Drink-EG/Sources/Models/ShoppingListManager.swift b/Drink-EG/Drink-EG/Sources/Models/Managers/ShoppingListManager.swift similarity index 92% rename from Drink-EG/Drink-EG/Sources/Models/ShoppingListManager.swift rename to Drink-EG/Drink-EG/Sources/Models/Managers/ShoppingListManager.swift index 0b0e6ce..5d211af 100644 --- a/Drink-EG/Drink-EG/Sources/Models/ShoppingListManager.swift +++ b/Drink-EG/Drink-EG/Sources/Models/Managers/ShoppingListManager.swift @@ -40,7 +40,7 @@ class ShoppingListManager { } /// 담아두기 목록에 와인, 판매처 정보로 찾아서 인덱스 반환 - private func isExistingInList(_ name: String, in shopName : String) -> Int? { + func isExistingInList(_ name: String, in shopName : String) -> Int? { for (idx, data) in myCartWines.enumerated() { if data.wineData.wine.name == name && data.wineData.shop.name == shopName { return idx @@ -51,7 +51,7 @@ class ShoppingListManager { /// 담아두기 목록에 와인 정보로 찾아서 인덱스 반환 /// 판매처 변경 시 호출됨 - private func isExistingWineInList(_ name: String) -> Int? { + func isExistingWineInList(_ name: String) -> Int? { for (idx, data) in myCartWines.enumerated() { if data.wineData.wine.name == name { return idx diff --git a/Drink-EG/Drink-EG/Sources/VCs/PolygonChartView.swift b/Drink-EG/Drink-EG/Sources/Models/PolygonChartView.swift similarity index 100% rename from Drink-EG/Drink-EG/Sources/VCs/PolygonChartView.swift rename to Drink-EG/Drink-EG/Sources/Models/PolygonChartView.swift diff --git a/Drink-EG/Drink-EG/Sources/Protocols/NewNoteFooterDelegate.swift b/Drink-EG/Drink-EG/Sources/Protocols/NewNoteFooterDelegate.swift new file mode 100644 index 0000000..a3cbcd5 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/Protocols/NewNoteFooterDelegate.swift @@ -0,0 +1,15 @@ +// +// NoteProtocol.swift +// Drink-EG +// +// Created by 김도연 on 8/20/24. +// + +import Foundation +import UIKit +import SnapKit +import Moya + +protocol NewNoteFooterDelegate: AnyObject { + func didTapNewNoteButton() +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Community/ModalViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Community/ModalViewController.swift index 204385f..885bc77 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Community/ModalViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Community/ModalViewController.swift @@ -260,23 +260,3 @@ class ModalViewController: UIViewController, UITableViewDataSource, UITableViewD return cell } } - -extension UserDefaults { - private enum Keys { - static let comments = "comments" - } - - func saveComments(_ comments: [Comment]) { - if let encoded = try? JSONEncoder().encode(comments) { - self.set(encoded, forKey: Keys.comments) - } - } - - func loadComments() -> [Comment] { - if let savedData = self.data(forKey: Keys.comments), - let savedComments = try? JSONDecoder().decode([Comment].self, from: savedData) { - return savedComments - } - return [] - } -} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Login/JoinViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Login/JoinViewController.swift index 6c3674c..8db2708 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Login/JoinViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Login/JoinViewController.swift @@ -318,7 +318,7 @@ class JoinViewController: UIViewController, UITextFieldDelegate { case .success(let response): do { let data = try response.map(APIResponseString.self) - print("User Created: \(data)") +// print("User Created: \(data)") completion(data.isSuccess) } catch { print("Failed to map data: \(error)") diff --git a/Drink-EG/Drink-EG/Sources/VCs/Login/SelectLoginViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Login/SelectLoginViewController.swift index 37b47e7..758dbcb 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Login/SelectLoginViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Login/SelectLoginViewController.swift @@ -8,9 +8,11 @@ import UIKit import SnapKit import AuthenticationServices +import Moya class SelectLoginViewController: UIViewController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { + let provider = MoyaProvider() let loginButton = UIButton(type: .system) let kakaoButton = UIButton(type: .system) @@ -154,32 +156,25 @@ class SelectLoginViewController: UIViewController, ASAuthorizationControllerDele case let appleIDCredential as ASAuthorizationAppleIDCredential: let userIdentifier = appleIDCredential.user let fullName = appleIDCredential.fullName - let email = appleIDCredential.email - if let authorizationCode = appleIDCredential.authorizationCode, - let identityToken = appleIDCredential.identityToken, - let authCodeString = String(data: authorizationCode, encoding: .utf8), - let identifyTokenString = String(data: identityToken, encoding: .utf8) { - print("authorizationCode: \(authorizationCode)\n") - print("identityToken: \(identityToken)\n") - print("authCodeString: \(authCodeString)\n") - print("identifyTokenString: \(identifyTokenString)\n") + if let identityToken = appleIDCredential.identityToken, + let identityTokenString = String(data: identityToken, encoding: .utf8) { + postAppleLogin(token: identityTokenString) { isSuccess in + if isSuccess { + self.goToNextView() + } else { + print("로그인 실패") + } + } } - print("useridentifier: \(userIdentifier)") - print("fullName: \(fullName)") - print("email: \(email)") - - // move to MainPage - goToNextView() - case let passwordCredential as ASPasswordCredential: // Sign in using an existing iCloud Keychain credential. let username = passwordCredential.user let password = passwordCredential.password - print("username: \(username)") - print("password: \(password)") +// print("username: \(username)") +// print("password: \(password)") default: break } @@ -201,6 +196,34 @@ class SelectLoginViewController: UIViewController, ASAuthorizationControllerDele print("login failed - \(error.localizedDescription)") } + //MARK: - Login API + private func postAppleLogin(token: String, completion: @escaping (Bool) -> Void) { + provider.request(.postAppleLogin(identityTokenString: token)) { result in + switch result { + case .success(let response): + if let httpResponse = response.response, + let setCookie = httpResponse.allHeaderFields["Set-Cookie"] as? String { + let cookies = HTTPCookie.cookies(withResponseHeaderFields: ["Set-Cookie": setCookie], for: httpResponse.url!) + + for cookie in cookies { + HTTPCookieStorage.shared.setCookie(cookie) + } + do { + let data = try response.map(AppleLoginResponse.self) + LoginViewController.isFirstLogin = data.result.isFirst + print(data) + } catch { + completion(false) + } + } + completion(true) + case .failure(let error): + print("Request failed: \(error)") + completion(false) + } + } + } + private func configureJoinButton() { joinButton.setTitle("회원가입", for: .normal) diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift index cda4fa8..9b0a45a 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Main/HomeViewController.swift @@ -13,6 +13,7 @@ import SDWebImage class HomeViewController: UIViewController { let provider = MoyaProvider(plugins: [CookiePlugin()]) + let shoppingListManager = ShoppingListManager.shared private var AdContents: [String] = ["ad1", "ad2"] private var RecomContents: [RecommendWineResponse] = [] @@ -41,6 +42,38 @@ class HomeViewController: UIViewController { let firstLine = UILabel() let NoteLabel = UILabel() + lazy var badgeLabel: UILabel = { + let label = UILabel(frame: CGRect(x: 0, y: 0, width: 16, height: 16)) + label.translatesAutoresizingMaskIntoConstraints = false + label.layer.cornerRadius = label.bounds.size.height / 2 + label.textAlignment = .center + label.layer.masksToBounds = true + label.textColor = .white + label.font = .boldSystemFont(ofSize: 10) + label.backgroundColor = UIColor(hex: "FF7A6D") + return label + }() + + private func showBadge() { + badgeLabel.text = "\(shoppingListManager.myCartWines.count)" + + // 장바구니가 비어 있는지 확인 + if shoppingListManager.myCartWines.isEmpty { + // 장바구니가 비어 있으면 badgeLabel을 cartButton에서 제거 + badgeLabel.removeFromSuperview() + } else { + // 장바구니에 아이템이 있으면 badgeLabel을 cartButton에 추가 + if badgeLabel.superview == nil { + cartButton.addSubview(badgeLabel) + } + badgeLabel.snp.makeConstraints { make in + make.centerX.equalTo(cartButton.snp.centerX).offset(10) + make.top.equalTo(cartButton).inset(2) + make.width.height.equalTo(16) + } + } + } + override func viewDidLoad() { super.viewDidLoad() @@ -56,20 +89,13 @@ class HomeViewController: UIViewController { } } - } - - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - // 버튼 하단에 노란색으로 칠하는 layer 추가 + // 버튼 하단에 붉은색으로 칠하는 layer 추가 let Layer = CALayer() - Layer.frame = CGRect(x: 0, y: 72, width: goToNoteButton.frame.width, height: goToNoteButton.frame.height - 72) + Layer.name = "redLayer" // 레이어 식별용 이름 설정 Layer.backgroundColor = UIColor(hue: 0.0417, saturation: 0.19, brightness: 1, alpha: 0.8).cgColor - - // 버튼에 layer 추가 goToNoteButton.layer.addSublayer(Layer) - //layer 위에 label 추가 + // layer 위에 label 추가 let titleLabel = UILabel() titleLabel.text = "테이스팅 노트 작성하기" titleLabel.textColor = .black @@ -77,20 +103,48 @@ class HomeViewController: UIViewController { titleLabel.textAlignment = .left titleLabel.translatesAutoresizingMaskIntoConstraints = false goToNoteButton.addSubview(titleLabel) - titleLabel.snp.makeConstraints { make in - make.top.equalToSuperview().offset(86) - make.leading.equalToSuperview().offset(18) - } let goToIcon = UIImageView() goToIcon.image = UIImage(named: "icon_goTo") goToNoteButton.addSubview(goToIcon) + + // 초기 레이아웃 설정 + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(86) // 초기 위치 (임시 값) + make.leading.equalToSuperview().offset(18) + } + goToIcon.snp.makeConstraints { make in - make.top.equalToSuperview().offset(86) + make.centerY.equalTo(titleLabel) // 초기 위치 (임시 값) make.trailing.equalToSuperview().inset(12) } } + // 홈으로 갈 때마다 쇼핑카트 badge의 상태가 업데이트 + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + // badgeLabel 업데이트 + showBadge() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + // Layer의 크기 및 위치 조정 + if let Layer = goToNoteButton.layer.sublayers?.first(where: { $0.name == "redLayer" }) { + let width = goToNoteButton.frame.width + let height = width * (47.0 / 353.0) + Layer.frame = CGRect(x: 0, y: goToNoteButton.bounds.height - height, width: width, height: height) + } + + // titleLabel의 위치 조정 + if let titleLabel = goToNoteButton.subviews.compactMap({ $0 as? UILabel }).first { + titleLabel.snp.updateConstraints { make in + make.top.equalTo(goToNoteButton.bounds.height - (goToNoteButton.frame.width * (47.0 / 353.0)) + 14) + } + } + } + private func setupUI() { // 검색 버튼 설정 configureSearchButton() @@ -112,8 +166,8 @@ class HomeViewController: UIViewController { // SnapKit을 사용하여 제약 조건 설정 stackView.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide.snp.top) - make.leading.trailing.equalToSuperview().inset(20) - make.height.equalTo(34) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(20) + make.height.greaterThanOrEqualTo(34) } searchButton.snp.makeConstraints { make in @@ -147,29 +201,28 @@ class HomeViewController: UIViewController { make.top.equalTo(contentView.snp.top).offset(10) make.centerX.equalToSuperview() make.leading.trailing.equalTo(stackView) - make.width.equalTo(356) - make.height.equalTo(247) + make.height.equalTo(AdImageCollectionView.snp.width).multipliedBy(247.0/356.0) } pageControl.snp.makeConstraints { make in make.top.equalTo(AdImageCollectionView.snp.bottom).offset(8) - make.centerX.equalToSuperview() + make.centerX.equalTo(view.safeAreaLayoutGuide) } contentView.addSubview(firstLine) firstLine.snp.makeConstraints {make in make.top.equalTo(pageControl.snp.bottom).offset(12) - make.leading.trailing.equalTo(AdImageCollectionView) + make.leading.equalTo(AdImageCollectionView) } contentView.addSubview(RecomCollectionView) RecomCollectionView.snp.makeConstraints { make in make.top.equalTo(firstLine.snp.bottom).offset(13) - make.centerX.equalToSuperview() + make.centerX.equalTo(view.safeAreaLayoutGuide) make.leading.trailing.equalTo(AdImageCollectionView) - make.height.equalTo(166) + make.height.greaterThanOrEqualTo(166) } @@ -181,9 +234,9 @@ class HomeViewController: UIViewController { contentView.addSubview(goToNoteButton) goToNoteButton.snp.makeConstraints { make in - make.top.equalTo(NoteLabel.snp.bottom).offset(22) + make.top.equalTo(NoteLabel.snp.bottom).offset(20) make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(23) - make.height.greaterThanOrEqualTo(119) + make.height.equalTo(AdImageCollectionView.snp.width).multipliedBy(119.0/353.0) make.bottom.equalToSuperview().inset(20) } @@ -261,6 +314,8 @@ class HomeViewController: UIViewController { goToNoteButton.layer.borderWidth = 0 goToNoteButton.setImage(UIImage(named: "HomeGoToTastingNote")?.withRenderingMode(.alwaysOriginal), for: .normal) + goToNoteButton.contentVerticalAlignment = .fill + goToNoteButton.contentHorizontalAlignment = .fill goToNoteButton.addTarget(self, action: #selector(noteButtonTapped), for: .touchUpInside) @@ -371,7 +426,7 @@ extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelega let selectedWine = RecomContents[indexPath.row] let wineInfoViewController = WineInfoViewController() wineInfoViewController.name.text = selectedWine.wineName - wineInfoViewController.wineImage = selectedWine.imageUrl + wineInfoViewController.wineImageURL = selectedWine.imageUrl wineInfoViewController.wineId = selectedWine.wineId navigationController?.pushViewController(wineInfoViewController, animated: true) } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/MainTabBarViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Main/MainTabBarViewController.swift index 1de7bd7..e991063 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/MainTabBarViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Main/MainTabBarViewController.swift @@ -28,7 +28,7 @@ class MainTabBarViewController : UITabBarController { let nav2 = UINavigationController(rootViewController: WineClassMainViewController()) let nav3 = UINavigationController(rootViewController: NoteListViewController()) let nav4 = UINavigationController(rootViewController: CommunityMainViewController()) - let nav5 = UINavigationController(rootViewController: SettingMainController()) + let nav5 = UINavigationController(rootViewController: MypageViewController()) nav1.tabBarItem = UITabBarItem(title: "", image: UIImage(named: "TabHome"), tag: 0) nav2.tabBarItem = UITabBarItem(title: "", image: UIImage(named: "TabClass"), tag: 1) @@ -39,6 +39,7 @@ class MainTabBarViewController : UITabBarController { tabBar.tintColor = .label tabBar.backgroundColor = UIColor(hue: 0, saturation: 0, brightness: 0, alpha: 0.6) tabBar.layer.cornerRadius = 20 + tabBar.layer.maskedCorners = CACornerMask(arrayLiteral: .layerMinXMinYCorner, .layerMaxXMinYCorner) tabBar.layer.masksToBounds = true tabBar.tintColor = .white diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/SettingMainController.swift b/Drink-EG/Drink-EG/Sources/VCs/Main/SettingMainController.swift deleted file mode 100644 index 9e1a349..0000000 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/SettingMainController.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// SettingMainController.swift -// Drink-EG -// -// Created by 이현주 on 7/22/24. -// - -import UIKit - -class SettingMainController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - view.backgroundColor = .green - } -} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift index fdc7435..f94acd4 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Main/ShoppingCartListViewController.swift @@ -8,19 +8,23 @@ import UIKit import SnapKit -protocol StoreListDelegate: AnyObject { - func didSelectStore(_ store: String) -} - -class ShoppingCartListViewController: UIViewController, CartListCollectionViewCellDelegate { +class ShoppingCartListViewController: UIViewController, CartListCollectionViewCellDelegate, StoreListDelegate { var selectedStore: String? let shoppingListManager = ShoppingListManager.shared private var CartContents: [ShoppingObject] = [] - private var itemsSelectedState: [Bool] = [] - private var totalSum : Int = 0 + // selectedCell을 인스턴스 변수로 선언하여 매장 변경을 선택한 셀을 추적합니다. + private var selectedCell: CartListCollectionViewCell? + + private var totalSum: Int = 0 { + didSet { + if totalSum < 0 { + totalSum = 0 + } + } + } var currentCheckCellCount : Int = 0 private let allCheckImage = UIImage(named: "icon_cartCheck_fill") @@ -43,6 +47,7 @@ class ShoppingCartListViewController: UIViewController, CartListCollectionViewCe b.setTitleColor(UIColor(hex: "#767676"), for: .normal) b.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14) b.backgroundColor = .clear + b.addTarget(self, action: #selector(checkDeleteButtonTapped(_:)), for: .touchUpInside) return b }() @@ -81,6 +86,9 @@ class ShoppingCartListViewController: UIViewController, CartListCollectionViewCe super.viewWillAppear(animated) CartContents = shoppingListManager.myCartWines + if shoppingListManager.myCartWines.isEmpty { + showNoWineLabel() + } } override func viewDidLoad() { @@ -93,7 +101,6 @@ class ShoppingCartListViewController: UIViewController, CartListCollectionViewCe CartContents = shoppingListManager.myCartWines view.backgroundColor = .white - itemsSelectedState = Array(repeating: false, count: 20) setupUI() DispatchQueue.main.async { self.cartListCollectionView.reloadData() @@ -110,6 +117,18 @@ class ShoppingCartListViewController: UIViewController, CartListCollectionViewCe cartListCollectionView.reloadData() } + private func showNoWineLabel() { + let noWine = UILabel() + noWine.text = "장바구니에 담은 상품이 없습니다." + noWine.font = .boldSystemFont(ofSize: 15) + noWine.textColor = UIColor(hex: "#767676") + + self.cartListCollectionView.addSubview(noWine) + noWine.snp.makeConstraints { make in + make.centerX.centerY.equalToSuperview() + } + } + private func setupUI() { configureAllCheckButton() @@ -175,6 +194,60 @@ class ShoppingCartListViewController: UIViewController, CartListCollectionViewCe return allIndexPaths } + @objc private func checkDeleteButtonTapped(_ sender: UIButton) { + // 선택된 셀의 인덱스 경로를 저장할 배열을 초기화합니다. + var indexPathsToDelete: [IndexPath] = [] + + // 전체 셀을 반복하면서 선택된 셀의 인덱스 경로를 수집합니다. + for indexPath in getIndexPathAllCells() { + if let cell = cartListCollectionView.cellForItem(at: indexPath) as? CartListCollectionViewCell { + if cell.CheckButton.isSelected { + // 선택된 셀의 인덱스 경로를 배열에 추가합니다. + indexPathsToDelete.append(indexPath) + // 총 합계와 선택된 셀 개수를 업데이트합니다. + currentCheckCellCount -= 1 + totalSum -= cell.price * cell.quantity + } + } + } + + // 인덱스 경로 배열을 역순으로 정렬하여 삭제 작업을 수행합니다. + let sortedIndexPathsToDelete = indexPathsToDelete.sorted { $0.item > $1.item } + + // 선택된 셀들만 삭제합니다. + for indexPath in sortedIndexPathsToDelete { + let item = CartContents[indexPath.row] + CartContents.remove(at: indexPath.row) + shoppingListManager.deleteWine(item) + } + + // 컬렉션 뷰의 삭제 애니메이션을 수행합니다. + cartListCollectionView.performBatchUpdates({ + cartListCollectionView.deleteItems(at: sortedIndexPathsToDelete) + }, completion: { _ in + // UI 업데이트 + self.buyButton.setTitle("\(self.totalSum)원 구매하기", for: .normal) + self.configureAllCheckLabel() + + // 전체 선택 버튼의 상태를 업데이트합니다. + if self.currentCheckCellCount == self.CartContents.count && self.CartContents.isEmpty == false { + self.allCheckButton.setImage(self.allCheckImage?.withRenderingMode(.alwaysOriginal), for: .selected) + self.allCheckButton.isSelected = true + } else { + self.allCheckButton.setImage(self.nAllCheckImage?.withRenderingMode(.alwaysOriginal), for: .normal) + self.allCheckButton.isSelected = false + } + }) + + if self.shoppingListManager.myCartWines.isEmpty { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { + self.showNoWineLabel() + } + } + } + + + @objc private func allCheckButtonTapped(_ sender: UIButton) { // Bool 값 toggle sender.isSelected.toggle() @@ -210,38 +283,6 @@ class ShoppingCartListViewController: UIViewController, CartListCollectionViewCe // 모든 셀의 configure2를 호출하여 선택 상태 업데이트 cartListCollectionView.reloadData() } - -// @objc private func allCheckButtonTapped(_ sender: UIButton) { -// // Bool 값 toggle -// let isSelectingAll = !sender.isSelected -// sender.isSelected = isSelectingAll -// -// // 버튼이 클릭될 때마다, 버튼 이미지를 변환 -// let newImage = isSelectingAll ? allCheckImage?.withRenderingMode(.alwaysOriginal) : nAllCheckImage?.withRenderingMode(.alwaysOriginal) -// sender.setImage(newImage, for: .normal) -// -// // 모든 셀에 대해 체크 상태 업데이트 -// currentCheckCellCount = isSelectingAll ? CartContents.count : 0 -// totalSum = 0 // totalSum 초기화 -// for indexPath in getIndexPathAllCells() { -// if let cell = cartListCollectionView.cellForItem(at: indexPath) as? CartListCollectionViewCell { -// if cell.CheckButton.isSelected != isSelectingAll { -// cell.CheckButton.isSelected = isSelectingAll -// cell.CheckButtonTapped(cell.CheckButton) // 직접 호출하여 셀의 선택 상태를 변경 -// } -// if isSelectingAll { -// totalSum += cell.price * cell.quantity // 전체 선택 시 모든 셀의 가격을 더합니다. -// } -// } -// } -// -// // totalSum을 표시할 UI 업데이트 (예: 구매 버튼의 타이틀) -// buyButton.setTitle("\(totalSum)원 구매하기", for: .normal) -// -// // 전체 선택 상태를 업데이트하고 라벨을 갱신 -// configureAllCheckLabel() -// cartListCollectionView.reloadData() -// } func configureAllCheckLabel() { @@ -250,6 +291,66 @@ class ShoppingCartListViewController: UIViewController, CartListCollectionViewCe allCheckLabel.textColor = UIColor(hex: "#767676") } + func didTapChangeStoreButton(on cell: CartListCollectionViewCell) { + let wineShopListVC = WineStoreListViewController() + wineShopListVC.delegate = self + wineShopListVC.wineImage = cell.wineImage + wineShopListVC.name.text = cell.name.text + wineShopListVC.score.text = "" + navigationController?.pushViewController(wineShopListVC, animated: true) + + // 선택된 셀을 추적하여 나중에 업데이트할 수 있도록 저장 + selectedCell = cell + } + + func didSelectStore(_ store: ShopData) { + guard let selectedCell = selectedCell, let indexPath = cartListCollectionView.indexPath(for: selectedCell) else { return } + + // 현재 셀의 아이템을 가져옵니다. + let item = CartContents[indexPath.row] + + // 선택된 셀의 매장 이름과 가격을 업데이트합니다. + selectedCell.shop = store.name + selectedCell.price = store.price + + // 셀의 UI를 업데이트합니다. + selectedCell.configureMarketNPlace(store.name, store.price, selectedCell.quantity) + + // 장바구니 데이터를 업데이트합니다. + if let wineName = selectedCell.name.text, let index = shoppingListManager.isExistingWineInList(wineName) { + var shoppingObject = shoppingListManager.myCartWines[index] + // 기존 매장에서 새로운 매장으로 업데이트 + let updatedShoppingObject = ShoppingObject(wineData: UserWineData(wine: shoppingObject.wineData.wine, shop: store)) + shoppingListManager.updatePlace(updatedShoppingObject) + } + + // CartContents 배열의 항목을 업데이트합니다. + item.wineData.shop = store + CartContents[indexPath.row] = item + + // 총 합계 재계산 + totalSum = 0 + + // 모든 인덱스 경로를 가져옵니다. + for section in 0.. Int { + return 1 + } + + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return pickerData.count + } + + func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return pickerData[row] + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListViewController.swift index 5fc9abe..5655fc7 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/ReviewListViewController.swift @@ -20,6 +20,11 @@ class ReviewListViewController: UIViewController { var score = 4.5 private let scoreLabel = UILabel() + let customPickerButton = CustomPickerButton() + let pickerView = UIPickerView() + let toolbar = UIToolbar() + let pickerData = ["최신 리뷰 순", "별점 높은 순", "별점 낮은 순"] + private let label: UILabel = { let l = UILabel() l.text = "다른유저 리뷰" @@ -40,9 +45,8 @@ class ReviewListViewController: UIViewController { let l = UILabel() l.font = .boldSystemFont(ofSize: 22) l.textColor = .black - l.numberOfLines = 0 - l.adjustsFontSizeToFitWidth = true // 텍스트가 레이블 너비에 맞도록 크기 조정 - l.minimumScaleFactor = 0.5 + l.numberOfLines = 2 + l.lineBreakMode = .byTruncatingTail // 생략 부호(...)가 꼬리에 위치하도록 설정 return l }() @@ -121,25 +125,57 @@ class ReviewListViewController: UIViewController { make.height.lessThanOrEqualTo(140) } + view.addSubview(scoreLabel) + scoreLabel.snp.makeConstraints { make in + make.top.equalTo(image.snp.top) + make.trailing.equalTo(view.safeAreaLayoutGuide).inset(20) + } + view.addSubview(name) name.snp.makeConstraints { make in - make.top.equalTo(image) - make.leading.equalTo(image.snp.trailing).offset(16) - make.width.lessThanOrEqualTo(175) + make.top.equalTo(image.snp.top) + make.leading.equalTo(image.snp.trailing).offset(13) + make.trailing.equalTo(scoreLabel.snp.leading).offset(-10) +// make.width.lessThanOrEqualTo(175) + make.height.lessThanOrEqualTo(80) } - view.addSubview(scoreLabel) - scoreLabel.snp.makeConstraints { make in - make.centerY.equalTo(name) - make.trailing.equalTo(view.safeAreaLayoutGuide).inset(20) + customPickerButton.setupPickerView(pickerView, toolbar: toolbar, pickerData: pickerData) + view.addSubview(customPickerButton) + + customPickerButton.snp.makeConstraints { make in + make.bottom.equalTo(image.snp.bottom).offset(10) + make.trailing.equalTo(stick.snp.trailing) + make.width.equalTo(customPickerButton.buttonWidth) + make.height.equalTo(customPickerButton.pickerButtonHeight) + } + + // Setup Picker View + view.addSubview(pickerView) + + pickerView.snp.makeConstraints { make in + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) + make.height.equalTo(200) // 높이 설정 + } + + // Setup Toolbar + view.addSubview(toolbar) + + toolbar.snp.makeConstraints { make in + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalTo(pickerView.snp.top) + make.height.equalTo(44) // 높이 설정 } view.addSubview(reviewListCollectionView) reviewListCollectionView.snp.makeConstraints { make in - make.top.equalTo(image.snp.bottom).offset(22) + make.top.equalTo(image.snp.bottom).offset(20) make.leading.trailing.equalTo(view.safeAreaLayoutGuide) make.bottom.equalTo(view.safeAreaLayoutGuide) } + + view.sendSubviewToBack(reviewListCollectionView) } private func configureScore() { @@ -179,6 +215,16 @@ extension ReviewListViewController: UICollectionViewDataSource, UICollectionView } let responseData = try JSONDecoder().decode(APIResponseWineReviewResponse.self, from: response.data) self.reviewResults = responseData.result + if self.reviewResults.isEmpty { + let noReview = UILabel() + noReview.text = "등록된 리뷰가 없습니다." + noReview.font = .boldSystemFont(ofSize: 15) + noReview.textColor = UIColor(hex: "#767676") + self.reviewListCollectionView.addSubview(noReview) + noReview.snp.makeConstraints { make in + make.centerX.centerY.equalToSuperview() + } + } self.reviewListCollectionView.reloadData() completion(true) } catch { diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift index 9bb448f..8eaee85 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/SearchHomeViewController.swift @@ -157,7 +157,7 @@ extension SearchHomeViewController: UICollectionViewDataSource, UICollectionView let wineInfoViewController = WineInfoViewController() wineInfoViewController.name.text = selectedWine.name - wineInfoViewController.wineImage = selectedWine.imageUrl + wineInfoViewController.wineImageURL = selectedWine.imageUrl wineInfoViewController.wineId = selectedWine.wineId navigationController?.pushViewController(wineInfoViewController, animated: true) } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift index bc839a8..443269c 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineInfoViewController.swift @@ -14,7 +14,7 @@ class WineInfoViewController: UIViewController { let provider = MoyaProvider(plugins: [CookiePlugin()]) - var wineImage: String? + var wineImageURL: String? var wineId: Int? var sort: String = "" @@ -78,7 +78,7 @@ class WineInfoViewController: UIViewController { let iv = UIImageView() iv.layer.cornerRadius = 10 iv.layer.masksToBounds = true - if let imageUrl = wineImage, let url = URL(string: imageUrl) { + if let imageUrl = wineImageURL, let url = URL(string: imageUrl) { iv.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) } else { iv.image = UIImage(named: "Loxton") @@ -92,7 +92,6 @@ class WineInfoViewController: UIViewController { l.textColor = .black l.numberOfLines = 0 l.adjustsFontSizeToFitWidth = true // 텍스트가 레이블 너비에 맞도록 크기 조정 - l.minimumScaleFactor = 0.7 return l }() @@ -102,6 +101,7 @@ class WineInfoViewController: UIViewController { l.font = .systemFont(ofSize: 12) l.textColor = .black l.numberOfLines = 0 + l.adjustsFontSizeToFitWidth = true // 텍스트가 레이블 너비에 맞도록 크기 조정 return l }() @@ -192,7 +192,7 @@ class WineInfoViewController: UIViewController { let reviewListViewController = ReviewListViewController() reviewListViewController.score = self.scoreDouble reviewListViewController.name.text = self.name.text - reviewListViewController.wineImage = self.wineImage + reviewListViewController.wineImage = self.wineImageURL reviewListViewController.wineId = self.wineId navigationController?.pushViewController(reviewListViewController, animated: true) } @@ -217,7 +217,7 @@ class WineInfoViewController: UIViewController { wineStoreListViewController.curWine = repackWineData() wineStoreListViewController.scoreDouble = self.scoreDouble wineStoreListViewController.name.text = self.name.text - wineStoreListViewController.imageView.image = self.imageView.image + wineStoreListViewController.wineImage = self.wineImageURL ?? "" //reviewListViewController.wineId = self.wineId navigationController?.pushViewController(wineStoreListViewController, animated: true) } @@ -287,31 +287,34 @@ class WineInfoViewController: UIViewController { make.width.equalTo(imageView.snp.height) } + infoView.addSubview(score) + score.snp.makeConstraints { make in + make.top.equalToSuperview().offset(13) + make.trailing.equalToSuperview().inset(15) + } + infoView.addSubview(name) name.snp.makeConstraints { make in - make.top.equalToSuperview().offset(11) - make.leading.equalTo(imageView.snp.trailing).offset(20) - make.width.lessThanOrEqualTo(205) + make.top.equalToSuperview().offset(10) + make.leading.equalTo(imageView.snp.trailing).offset(10) + make.trailing.equalTo(score.snp.leading).offset(-10) +// make.width.lessThanOrEqualTo(205) make.height.lessThanOrEqualTo(40) } infoView.addSubview(specInfo) specInfo.snp.makeConstraints { make in - make.top.equalTo(name.snp.bottom).offset(11) + make.top.equalTo(name.snp.bottom).offset(8) make.leading.equalTo(name) - } - - infoView.addSubview(score) - score.snp.makeConstraints { make in - make.top.equalTo(name.snp.top) - make.trailing.equalToSuperview().inset(15) + make.trailing.equalToSuperview().offset(-10) + make.height.lessThanOrEqualTo(37) } contentView.addSubview(tastingNoteView) tastingNoteView.snp.makeConstraints { make in make.top.equalTo(infoView.snp.bottom).offset(10.5) make.leading.trailing.equalTo(infoView) - make.height.greaterThanOrEqualTo(414) + make.height.greaterThanOrEqualTo(400) } tastingNoteView.addSubview(represent) @@ -322,10 +325,11 @@ class WineInfoViewController: UIViewController { tastingNoteView.addSubview(pentagonChart) pentagonChart.snp.makeConstraints{ make in - make.top.equalTo(represent.snp.bottom).offset(29) + make.top.equalTo(represent.snp.bottom).offset(20) make.centerX.equalToSuperview() - make.width.equalTo(353) - make.height.equalTo(309) + make.leading.equalToSuperview().offset(10) // 추가: 좌우 여백을 설정할 수 있습니다 + make.bottom.equalToSuperview().offset(-10) + make.width.equalTo(pentagonChart.snp.height).multipliedBy(353.0/309.0) } contentView.addSubview(explainEntireView) @@ -458,6 +462,6 @@ extension WineInfoViewController { } func repackWineData() -> Wine { - return Wine(wineId: self.wineId!, name: self.name.text!, imageUrl: self.wineImage, rating: self.scoreDouble, price: 0, area: "", sort: "") + return Wine(wineId: self.wineId!, name: self.name.text!, imageUrl: self.wineImageURL, rating: self.scoreDouble, price: 0, area: "", sort: "") } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift index a99c1ea..c8b9e66 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineOrderViewController.swift @@ -7,8 +7,10 @@ import UIKit import SnapKit +import SDWebImage class WineOrderViewController: UIViewController { + let shoppingManager = ShoppingListManager.shared private var quantity: Int = 1 { @@ -20,7 +22,7 @@ class WineOrderViewController: UIViewController { var shop: String? var score = 4.5 var wineName: String = "" - var wineImage: UIImage? + var wineImage: String? var shopAddr : String? var distanceDouble : Double? var priceInt: Int? @@ -50,8 +52,10 @@ class WineOrderViewController: UIViewController { private let name: UILabel = { let l = UILabel() l.text = "Red Label" - l.font = .boldSystemFont(ofSize: 22) + l.font = .boldSystemFont(ofSize: 20) l.textColor = .black + l.numberOfLines = 2 + l.lineBreakMode = .byTruncatingTail // 생략 부호(...)가 꼬리에 위치하도록 설정 return l }() @@ -60,6 +64,8 @@ class WineOrderViewController: UIViewController { i.image = UIImage(named: "Red Label") i.layer.cornerRadius = 10 i.layer.masksToBounds = true + i.layer.borderWidth = 1.5 + i.layer.borderColor = UIColor(hex: "#E5E5E5")?.cgColor return i }() @@ -73,9 +79,9 @@ class WineOrderViewController: UIViewController { return v }() - private let distance: UILabel = { - let l2 = UILabel() - + private let distance = UILabel() + + fileprivate func setDistanceText(_ textData : String) { let imageAttachment = NSTextAttachment() imageAttachment.image = UIImage(named: "icon_location") @@ -86,14 +92,13 @@ class WineOrderViewController: UIViewController { let attachmentString = NSAttributedString(attachment: imageAttachment) completeText.append(attachmentString) - + // 매장 텍스트 추가 - let text = NSAttributedString(string: " 2.3 km", attributes: [.font: UIFont.boldSystemFont(ofSize: 12)]) + let text = NSAttributedString(string: " \(textData) km", attributes: [.font: UIFont.boldSystemFont(ofSize: 12)]) completeText.append(text) - l2.attributedText = completeText - l2.textColor = UIColor(hex: "#FF7A6D") - return l2 - }() + distance.attributedText = completeText + distance.textColor = UIColor(hex: "#FF7A6D") + } private let address: UILabel = { let l3 = UILabel() @@ -206,6 +211,12 @@ class WineOrderViewController: UIViewController { view.backgroundColor = .white setupUI() + + if let imageUrl = wineImage, let url = URL(string: imageUrl) { + image.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) + } else { + image.image = UIImage(named: "Loxton") + } } private func setupUI() { @@ -237,7 +248,10 @@ class WineOrderViewController: UIViewController { view.addSubview(name) name.snp.makeConstraints { make in make.top.equalTo(image.snp.top) - make.leading.equalTo(image.snp.trailing).offset(22) + make.leading.equalTo(image.snp.trailing).offset(13) + make.trailing.equalTo(stick.snp.trailing).offset(-5) + make.height.lessThanOrEqualTo(60) +// make.width.lessThanOrEqualTo(250) } // view.addSubview(scoreLabel) @@ -321,13 +335,12 @@ class WineOrderViewController: UIViewController { if let shopdata = curShop { shopName.text = shop address.text = shopAddr - distance.text = " \(shopdata.distanceToUser) km" + setDistanceText("\(shopdata.distanceToUser)") price.text = "\(shopdata.price) ₩" } } private func configureWineName() { name.text = self.wineName - image.image = self.wineImage } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift index 18437df..f1ecedb 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/Search/WineStoreListViewController.swift @@ -7,9 +7,19 @@ import SnapKit import UIKit +import SDWebImage + +protocol StoreListDelegate: AnyObject { + func didSelectStore(_ store: ShopData) +} class WineStoreListViewController: UIViewController { + let customPickerButton = CustomPickerButton() + let pickerView = UIPickerView() + let toolbar = UIToolbar() + let pickerData = ["낮은 가격순", "가까운 거리순"] + weak var delegate: StoreListDelegate? var selectedShop: String? @@ -57,13 +67,14 @@ class WineStoreListViewController: UIViewController { l1.text = "Loxton" l1.font = .boldSystemFont(ofSize: 18) l1.textColor = .black - l1.numberOfLines = 0 + l1.numberOfLines = 2 + l1.lineBreakMode = .byTruncatingTail // 생략 부호(...)가 꼬리에 위치하도록 설정 return l1 }() lazy var score: UILabel = { let l3 = UILabel() - l3.text = "\(scoreDouble) ★" + l3.text = "★ \(scoreDouble)" l3.font = .boldSystemFont(ofSize: 12) l3.textColor = UIColor(hex: "#FF7A6D") return l3 @@ -93,51 +104,97 @@ class WineStoreListViewController: UIViewController { self.navigationController?.isNavigationBarHidden = false self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) self.navigationController?.navigationBar.tintColor = .black + // 네비게이션 바 설정 +// if let navigationBar = navigationController?.navigationBar { +// navigationBar.isTranslucent = false +// navigationBar.shadowImage = UIImage() // 하단에 생기는 경계선을 없앰 +// navigationBar.setBackgroundImage(UIImage(), for: .default) // 배경 이미지를 투명하게 설정 +// navigationBar.barTintColor = .white // 필요 시 배경 색을 흰색으로 설정 +// } view.backgroundColor = .white setupUI() + + if let imageUrl = wineImage, let url = URL(string: imageUrl) { + imageView.sd_setImage(with: url, placeholderImage: UIImage(named: "Loxton")) + } else { + imageView.image = UIImage(named: "Loxton") + } } private func setupUI() { - view.addSubview(label) - label.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).offset(20) - make.leading.equalTo(view.safeAreaLayoutGuide).offset(27) - } - - view.addSubview(wineInfo) - wineInfo.snp.makeConstraints { make in - make.top.equalTo(label.snp.bottom).offset(26) - make.trailing.leading.equalToSuperview().inset(16) - make.height.lessThanOrEqualTo(120) - } - - wineInfo.addSubview(imageView) - imageView.snp.makeConstraints { make in - make.top.bottom.equalToSuperview().inset(20) - make.leading.equalToSuperview().offset(12) - make.width.equalTo(imageView.snp.height) - } - - wineInfo.addSubview(name) - name.snp.makeConstraints { make in - make.top.equalTo(imageView) - make.leading.equalTo(imageView.snp.trailing).offset(23) - } + view.addSubview(label) + label.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(20) + make.leading.equalTo(view.safeAreaLayoutGuide).offset(27) + } + + view.addSubview(wineInfo) + wineInfo.snp.makeConstraints { make in + make.top.equalTo(label.snp.bottom).offset(26) + make.trailing.leading.equalToSuperview().inset(16) + make.height.lessThanOrEqualTo(120) + } + + wineInfo.addSubview(imageView) + imageView.snp.makeConstraints { make in + make.top.bottom.equalToSuperview().inset(20) + make.leading.equalToSuperview().offset(12) + make.width.equalTo(imageView.snp.height) + } - wineInfo.addSubview(score) - score.snp.makeConstraints { make in - make.centerY.equalTo(name) - make.leading.equalTo(name.snp.trailing).offset(13) - } + wineInfo.addSubview(score) + score.snp.makeConstraints { make in + make.top.equalTo(imageView.snp.top) + make.trailing.equalToSuperview().inset(15) + } - 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) + wineInfo.addSubview(name) + name.snp.makeConstraints { make in + make.top.equalTo(imageView.snp.top) + make.leading.equalTo(imageView.snp.trailing).offset(13) + make.trailing.equalTo(score.snp.leading).offset(-10) +// make.width.lessThanOrEqualTo(205) + make.height.lessThanOrEqualTo(55) + } + + customPickerButton.setupPickerView(pickerView, toolbar: toolbar, pickerData: pickerData) + view.addSubview(customPickerButton) + + customPickerButton.snp.makeConstraints { make in + make.top.equalTo(wineInfo.snp.bottom).offset(44) + make.trailing.equalTo(wineInfo.snp.trailing) + make.width.equalTo(customPickerButton.buttonWidth) + make.height.equalTo(customPickerButton.pickerButtonHeight) + } + + // Setup Picker View + view.addSubview(pickerView) + + pickerView.snp.makeConstraints { make in + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) + make.height.equalTo(200) // 높이 설정 + } + + // Setup Toolbar + view.addSubview(toolbar) + + toolbar.snp.makeConstraints { make in + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalTo(pickerView.snp.top) + make.height.equalTo(44) // 높이 설정 + } + + view.addSubview(wineShopListCollectionView) + wineShopListCollectionView.snp.makeConstraints { make in + make.top.equalTo(customPickerButton.snp.bottom).offset(10) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(15) + make.bottom.equalTo(view.safeAreaLayoutGuide).inset(15) + } + + view.sendSubviewToBack(wineShopListCollectionView) } - } } extension WineStoreListViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { @@ -164,7 +221,7 @@ extension WineStoreListViewController: UICollectionViewDataSource, UICollectionV wineOrderViewController.wine = curWine wineOrderViewController.curShop = data - wineOrderViewController.wineImage = imageView.image + wineOrderViewController.wineImage = self.wineImage ?? "" // TODO : 삭제 가능한 데이터들 wineOrderViewController.shop = data.name @@ -176,8 +233,8 @@ extension WineStoreListViewController: UICollectionViewDataSource, UICollectionV navigationController?.pushViewController(wineOrderViewController, animated: true) } else if previousViewController is ShoppingCartListViewController { - let selectedCell = collectionView.cellForItem(at: indexPath) as! WineShopListCollectionViewCell - delegate?.didSelectStore(selectedCell.shopName.text ?? "") + let selectedShop = whineShopList[indexPath.row] + delegate?.didSelectStore(selectedShop) navigationController?.popViewController(animated: true) // 장바구니 화면으로 돌아가기 } } diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageBusinessViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageBusinessViewController.swift new file mode 100644 index 0000000..baaed99 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageBusinessViewController.swift @@ -0,0 +1,121 @@ +// +// MyPageBusinessViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import UIKit + +class MyPageBusinessViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { + + let myPageMenu = ["제휴 문의", "판매자 입점 문의"] + let cellID = "MyPageSettingsCellID" + let tableView = UITableView(frame: .zero, style: .grouped) + + + private let label: UILabel = { + let l = UILabel() + l.text = "제휴,입점 문의" + l.font = .systemFont(ofSize: 28, weight: .bold) + l.textColor = .black + l.numberOfLines = 0 + return l + }() + + override func viewDidLoad() { + super.viewDidLoad() + + setupNavigationBarButton() + configureUI() + } + + func setupNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + func configureUI() { + + view.backgroundColor = .white + + view.addSubview(label) + + view.addSubview(tableView) + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.backgroundColor = .white + + tableView.delegate = self + tableView.dataSource = self + + tableView.register(MyPageBusinessCell.self, forCellReuseIdentifier: cellID) + + + + label.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), + label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20) + ]) + + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 20), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.rightAnchor.constraint(equalTo: view.rightAnchor) + ]) + } + + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return myPageMenu.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as? MyPageBusinessCell else { + fatalError("Failed to dequeue MyPageSettingsCell") + } + cell.menuLabel.text = myPageMenu[indexPath.row] + cell.backgroundColor = UIColor(hex: "D9D9D9") + return cell + } + + +} + +class MyPageBusinessCell: UITableViewCell { + + let menuLabel = UILabel() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + configureUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configureUI() { + addSubview(menuLabel) + menuLabel.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + menuLabel.centerYAnchor.constraint(equalTo: centerYAnchor), + menuLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 12) + ]) + } +} + diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageNoticeViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageNoticeViewController.swift new file mode 100644 index 0000000..2ddcff1 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageNoticeViewController.swift @@ -0,0 +1,240 @@ +// +// MyPageNoticeViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import UIKit +import SnapKit + +private let cellID = "MyPageNoticeCellID" + +class MyPageNoticeViewController: UIViewController { + + let myPageNoticeFirstMenu = ["[공지] 개인정보 처리방침 변경 안내", "[공지] 구매, 판매처 관련 안내", "[공지] 업데이트 안내", "[공지] 주의사항 안내", "모두보기"] + let myPageNoticeSecondMenu = ["[공지] 클래스 이벤트 당첨자 안내", "[공지] 8월의 할인 혜택 안내", "모두보기"] + + let tableView = UITableView(frame: .zero, style: .grouped) + + private let label: UILabel = { + let l = UILabel() + l.text = "공지사항" + l.font = .systemFont(ofSize: 28, weight: .bold) + l.textColor = .black + l.numberOfLines = 0 + return l + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupNavigationBarButton() + setupUI() + } + + func setupNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + func setupUI() { + view.backgroundColor = .white + + // Label 추가 + view.addSubview(label) + label.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(30) + make.leading.equalTo(view.safeAreaLayoutGuide).offset(27) + } + + view.addSubview(tableView) + tableView.backgroundColor = .white + + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.delegate = self + tableView.dataSource = self + tableView.register(MyPageNoticeCell.self, forCellReuseIdentifier: cellID) + + + tableView.snp.makeConstraints { make in + make.top.equalTo(label.snp.bottom).offset(20) + make.left.right.bottom.equalTo(view) + } + + + } +} + +extension MyPageNoticeViewController: UITableViewDataSource { + + func numberOfSections(in tableView: UITableView) -> Int { + return 2 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == 0 { + return myPageNoticeFirstMenu.count + } else { + return myPageNoticeSecondMenu.count + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! MyPageNoticeCell + cell.backgroundColor = UIColor(hex: "D9D9D9") + cell.menuLabel.textColor = .black + cell.iconImageView.image = nil + + + if indexPath.section == 0 { + let menuTitle = myPageNoticeFirstMenu[indexPath.row] + cell.menuLabel.text = menuTitle + if menuTitle == "모두보기" { + cell.backgroundColor = .white + tableView.separatorStyle = .none + + cell.menuLabel.textColor = UIColor(hex: "FA735B") + cell.iconImageView.image = UIImage(systemName: "arrowtriangle.down.fill")?.withRenderingMode(.alwaysTemplate) + cell.iconImageView.tintColor = UIColor(hex: "FA735B") + + + } + } else { + let menuTitle = myPageNoticeSecondMenu[indexPath.row] + cell.menuLabel.text = menuTitle + if menuTitle == "모두보기" { + cell.backgroundColor = .white + cell.menuLabel.textColor = UIColor(hex: "FA735B") + cell.iconImageView.image = UIImage(systemName: "arrowtriangle.down.fill")?.withRenderingMode(.alwaysTemplate) + cell.iconImageView.tintColor = UIColor(hex: "FA735B") + } + } + return cell + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + if section == 0 { + return FirstNoticeSectionHeader() + } else { + return SecondNoticeSectionHeader() + } + } +} + +extension MyPageNoticeViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 50 + } +} + +class FirstNoticeSectionHeader: UIView { + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "일반공지" + label.font = .boldSystemFont(ofSize: 18) + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .white + self.layer.borderColor = UIColor.lightGray.cgColor + self.layer.borderWidth = 1.0 + + addSubview(titleLabel) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: topAnchor), + titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20), + titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor), + titleLabel.rightAnchor.constraint(equalTo: rightAnchor) + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +class SecondNoticeSectionHeader: UIView { + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "이벤트 안내" + label.font = .boldSystemFont(ofSize: 18) + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .white + self.layer.borderColor = UIColor.lightGray.cgColor + self.layer.borderWidth = 1.0 + + addSubview(titleLabel) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: topAnchor), + titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20), + titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor), + titleLabel.rightAnchor.constraint(equalTo: rightAnchor) + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + + + +class MyPageNoticeCell: UITableViewCell { + + + let menuLabel: UILabel = { + let label = UILabel() + label.font = .systemFont(ofSize: 16) + return label + }() + + let iconImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.tintColor = .black + return imageView + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + configureUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configureUI() { + contentView.addSubview(menuLabel) + contentView.addSubview(iconImageView) + + + + menuLabel.snp.makeConstraints { make in + make.centerY.equalTo(contentView.snp.centerY) + make.leading.equalTo(contentView.snp.leading).offset(20) + } + iconImageView.snp.makeConstraints { make in + make.centerY.equalTo(contentView.snp.centerY) + make.leading.equalTo(menuLabel.snp.trailing).offset(10) + make.width.height.equalTo(17) + } + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageOrderViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageOrderViewController.swift new file mode 100644 index 0000000..13ac056 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageOrderViewController.swift @@ -0,0 +1,210 @@ +// +// MyPageOrderViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import UIKit +import SnapKit + +class MyPageOrderViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { + + private let items = [ + ["title": "19charles", "detail": "PODO | 165,000원", "imageName": "SampleImage"], + ["title": "19charles", "detail": "PODO | 165,000원", "imageName": "SampleImage"], + ["title": "19charles", "detail": "PODO | 165,000원", "imageName": "SampleImage"], + ["title": "19charles", "detail": "PODO | 165,000원", "imageName": "SampleImage"], + ] + + lazy var scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.alwaysBounceVertical = true + return scrollView + }() + + lazy var OrdercontentView: UIView = { + return UIView() + }() + + lazy var OrdertitleLabel: UILabel = { + let label = UILabel() + label.text = "와인 주문 내역" + label.font = UIFont.boldSystemFont(ofSize: 24) + label.textColor = .black + return label + }() + + lazy var OrderlowerCollectionStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.spacing = 10 + stackView.distribution = .fillEqually + return stackView + }() + + lazy var orderDetailButton: UIButton = { + let button = UIButton() + button.setTitle("주문상세", for: .normal) + button.setTitleColor(.black, for: .normal) + let chevronIcon = UIImage(systemName: "chevron.right") + button.setImage(chevronIcon, for: .normal) + button.semanticContentAttribute = .forceRightToLeft + button.addTarget(self, action: #selector(orderDetailButtonTapped), for: .touchUpInside) + return button + }() + + override func viewDidLoad() { + view.backgroundColor = .white + super.viewDidLoad() + + setupScrollView() + setupOrderView() + setupOrderNavigationBarButton() + setupOrderLowerCollectionView() + setupOrderStackViewConstraints() + setupOrderTitleLabel() + setupOrderDetailButton() + } + + func setupOrderView() { + OrdercontentView.addSubview(OrderlowerCollectionStackView) + OrdercontentView.addSubview(OrdertitleLabel) + OrdercontentView.addSubview(orderDetailButton) + } + + func setupScrollView() { + view.addSubview(scrollView) + scrollView.addSubview(OrdercontentView) + + scrollView.snp.makeConstraints { make in + make.edges.equalTo(view) + } + } + + func setupOrderNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + func setupOrderTitleLabel() { + OrdertitleLabel.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(66) + make.leading.equalTo(view).offset(16) + } + } + + func setupOrderDetailButton() { + orderDetailButton.snp.makeConstraints { make in + make.top.equalTo(OrdertitleLabel.snp.bottom).offset(40) + make.trailing.equalTo(view).offset(-16) + } + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + func setupOrderLowerCollectionView() { + for item in items { + let cellView = CustomCellView() + cellView.configure(title: item["title"]!, detail: item["detail"]!, imageName: item["imageName"]!) + + cellView.layer.cornerRadius = 10 + cellView.layer.masksToBounds = true + + OrderlowerCollectionStackView.addArrangedSubview(cellView) + + cellView.snp.makeConstraints { make in + make.height.equalTo(94) + make.width.equalTo(366) + } + } + } + + func setupOrderStackViewConstraints() { + OrderlowerCollectionStackView.snp.makeConstraints { make in + make.top.equalTo(orderDetailButton.snp.bottom).offset(24) + make.leading.equalTo(OrdercontentView.snp.leading).offset(16) + make.centerX.equalTo(OrdercontentView.snp.centerX) + } + } + + @objc func orderDetailButtonTapped() { + + } +} + +class CustomCellView: UIView { + let titleLabel = UILabel() + let detailLabel = UILabel() + let imageView = UIImageView() + let quantityLabel = UILabel() + + override init(frame: CGRect) { + super.init(frame: frame) + + layer.cornerRadius = 10 + layer.masksToBounds = true + backgroundColor = UIColor.lightGray + + addSubview(imageView) + addSubview(titleLabel) + addSubview(detailLabel) + addSubview(quantityLabel) + + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.layer.cornerRadius = 10 + + titleLabel.textColor = .black + titleLabel.font = UIFont.boldSystemFont(ofSize: 18) + + detailLabel.textColor = .gray + detailLabel.font = UIFont.systemFont(ofSize: 12) + + quantityLabel.text = "1개" + quantityLabel.textColor = .black + quantityLabel.font = UIFont.systemFont(ofSize: 12) + + setupConstraints() + } + + func setupConstraints() { + imageView.snp.makeConstraints { make in + make.width.height.equalTo(60) + make.leading.equalToSuperview().offset(10) + make.centerY.equalToSuperview() + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(imageView.snp.trailing).offset(8) + make.top.equalToSuperview().offset(20) + make.trailing.lessThanOrEqualTo(quantityLabel.snp.leading).offset(-10) + } + + detailLabel.snp.makeConstraints { make in + make.leading.equalTo(titleLabel.snp.leading) + make.top.equalTo(quantityLabel.snp.top).offset(0) + make.trailing.lessThanOrEqualTo(quantityLabel.snp.leading).offset(-10) + } + + quantityLabel.snp.makeConstraints { make in + make.trailing.equalToSuperview().offset(-10) + make.bottom.equalToSuperview().offset(-20) + } + } + + func configure(title: String, detail: String, imageName: String) { + titleLabel.text = title + detailLabel.text = detail + imageView.image = UIImage(named: imageName) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageQnaViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageQnaViewController.swift new file mode 100644 index 0000000..4149e77 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageQnaViewController.swift @@ -0,0 +1,172 @@ +// +// MyPageQnaViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import UIKit +import SnapKit + +class MyPageQnaViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { + + let myPageQnaFirstMenu = ["메일 문의", "채팅 문의", "전화 문의"] + let myPageQnaSecondMenu = ["문의 내역 조회"] + let myPageQnaFirstMenuIcons = [ + UIImage(systemName: "envelope.fill"), + UIImage(systemName: "message"), + UIImage(systemName: "phone") + ] + + let cellID = "MyPageSettingsCellID" + let tableView = UITableView(frame: .zero, style: .grouped) + + + private let label: UILabel = { + let l = UILabel() + l.text = "1:1 문의하기" + l.font = .systemFont(ofSize: 28, weight: .bold) + l.textColor = .black + l.numberOfLines = 0 + return l + }() + + override func viewDidLoad() { + super.viewDidLoad() + + setupNavigationBarButton() + configureUI() + } + + func setupNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + func configureUI() { + + view.backgroundColor = .white + + view.addSubview(label) + + view.addSubview(tableView) + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.backgroundColor = .white + + tableView.delegate = self + tableView.dataSource = self + + tableView.register(MyPageQnaCell.self, forCellReuseIdentifier: cellID) + + + + label.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(20) + make.leading.equalTo(view.snp.leading).offset(20) + } + + tableView.snp.makeConstraints { make in + make.top.equalTo(label.snp.bottom).offset(20) + make.left.right.bottom.equalTo(view) + } + } + + + func numberOfSections(in tableView: UITableView) -> Int { + return 2 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == 0 { + return myPageQnaFirstMenu.count + } + else { + return myPageQnaSecondMenu.count + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as? MyPageQnaCell else { + fatalError("Failed to dequeue MyPageQnaCell") + } + + cell.backgroundColor = UIColor(hex: "D9D9D9") + if indexPath.section == 0{ + cell.menuLabel.text = myPageQnaFirstMenu[indexPath.row] + cell.iconImageView.image = myPageQnaFirstMenuIcons[indexPath.row] + cell.imageView?.tintColor = .black + + } + else { + cell.menuLabel.text = myPageQnaSecondMenu[indexPath.row] + } + return cell + } + + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + return 10 // 원하는 섹션 간 간격으로 설정 + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView = UIView() + headerView.backgroundColor = .clear + return headerView + } + + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + let footerView = UIView() + footerView.backgroundColor = .clear + return footerView + } +} + + + +class MyPageQnaCell: UITableViewCell { + + let menuLabel: UILabel = { + let label = UILabel() + label.font = .systemFont(ofSize: 16) + return label + }() + + let iconImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.tintColor = .black + return imageView + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + configureUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configureUI() { + contentView.addSubview(menuLabel) + contentView.addSubview(iconImageView) + + iconImageView.snp.makeConstraints { make in + make.centerY.equalTo(contentView.snp.centerY) + make.leading.equalTo(contentView.snp.leading).offset(20) + make.width.height.equalTo(17) + } + + menuLabel.snp.makeConstraints { make in + make.centerY.equalTo(contentView.snp.centerY) + make.leading.equalTo(iconImageView.snp.trailing).offset(10) + make.trailing.equalTo(safeAreaLayoutGuide.snp.trailing).offset(-16) + } + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageSettingsViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageSettingsViewController.swift new file mode 100644 index 0000000..d3b7dd9 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageSettingsViewController.swift @@ -0,0 +1,128 @@ +// +// File.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// +import Foundation +import UIKit +import SnapKit + +class MyPageSettingsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { + + let myPageMenu = ["휴대폰 번호 변경", "알림설정"] + let cellID = "MyPageSettingsCellID" + let tableView = UITableView(frame: .zero, style: .grouped) + + + private let label: UILabel = { + let l = UILabel() + l.text = "설정" + l.font = .systemFont(ofSize: 28, weight: .bold) + l.textColor = .black + l.numberOfLines = 0 + return l + }() + + override func viewDidLoad() { + super.viewDidLoad() + + setupNavigationBarButton() + configureUI() + } + + func setupNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + func configureUI() { + + view.backgroundColor = .white + + // Add the label to the view + view.addSubview(label) + + // Add the table view to the view + view.addSubview(tableView) + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.backgroundColor = .white + + tableView.delegate = self + tableView.dataSource = self + + // Register the cell with the correct identifier + tableView.register(MyPageSettingsCell.self, forCellReuseIdentifier: cellID) + + + + // Layout constraints for label + label.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), + label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20) + ]) + + // Layout constraints for table view + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 20), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.rightAnchor.constraint(equalTo: view.rightAnchor) + ]) + } + + // MARK: - UITableViewDataSource + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return myPageMenu.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as? MyPageSettingsCell else { + fatalError("Failed to dequeue MyPageSettingsCell") + } + cell.menuLabel.text = myPageMenu[indexPath.row] + cell.backgroundColor = UIColor(hex: "D9D9D9") + return cell + } + + +} + +class MyPageSettingsCell: UITableViewCell { + + let menuLabel = UILabel() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + configureUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configureUI() { + addSubview(menuLabel) + menuLabel.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + menuLabel.centerYAnchor.constraint(equalTo: centerYAnchor), + menuLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 12) + ]) + } +} + diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageSuggestViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageSuggestViewController.swift new file mode 100644 index 0000000..639fd17 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MyPageSuggestViewController.swift @@ -0,0 +1,121 @@ +// +// MyPageSuggestViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import UIKit + +class MyPageSuggestViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { + + let myPageMenu = ["개선 제안하기"] + let cellID = "MyPageSettingsCellID" + let tableView = UITableView(frame: .zero, style: .grouped) + + + private let label: UILabel = { + let l = UILabel() + l.text = "개선 제안하기" + l.font = .systemFont(ofSize: 28, weight: .bold) + l.textColor = .black + l.numberOfLines = 0 + return l + }() + + override func viewDidLoad() { + super.viewDidLoad() + + setupNavigationBarButton() + configureUI() + } + + func setupNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + func configureUI() { + + view.backgroundColor = .white + + view.addSubview(label) + + view.addSubview(tableView) + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.backgroundColor = .white + + tableView.delegate = self + tableView.dataSource = self + + tableView.register(MyPageSuggestCell.self, forCellReuseIdentifier: cellID) + + + + label.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), + label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20) + ]) + + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 20), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.rightAnchor.constraint(equalTo: view.rightAnchor) + ]) + } + + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return myPageMenu.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as? MyPageSuggestCell else { + fatalError("Failed to dequeue MyPageSettingsCell") + } + cell.menuLabel.text = myPageMenu[indexPath.row] + cell.backgroundColor = UIColor(hex: "D9D9D9") + return cell + } + + +} + +class MyPageSuggestCell: UITableViewCell { + + let menuLabel = UILabel() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + configureUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configureUI() { + addSubview(menuLabel) + menuLabel.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + menuLabel.centerYAnchor.constraint(equalTo: centerYAnchor), + menuLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 12) + ]) + } +} + diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MypageInfoBottomViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MypageInfoBottomViewController.swift new file mode 100644 index 0000000..a6f60b1 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MypageInfoBottomViewController.swift @@ -0,0 +1,253 @@ +// +// MypageInfoBottomViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import UIKit + +class MyPageBottomSheetViewController: UIViewController { + + private let contentViewController: UIViewController + init(contentViewController: MypageInfoViewController) { + self.contentViewController = contentViewController + super.init(nibName: nil, bundle: nil) + } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private let dimmedView: UIView = { + let view = UIView() + view.backgroundColor = UIColor.darkGray.withAlphaComponent(0.7) + return view + }() + // 1 + var defaultHeight: CGFloat = 661 + + private let bottomSheetView: UIView = { + let view = UIView() + view.backgroundColor = .white + + view.layer.cornerRadius = 10 + view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] + view.clipsToBounds = true + return view + }() + + // 2 + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + showBottomSheet() + } + + private var bottomSheetViewTopConstraint: NSLayoutConstraint! + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + let dimmedTap = UITapGestureRecognizer(target: self, action: #selector(dimmedViewTapped(_:))) + dimmedView.addGestureRecognizer(dimmedTap) + dimmedView.isUserInteractionEnabled = true + } + @objc private func dimmedViewTapped(_ tapRecognizer: UITapGestureRecognizer) { + hideBottomSheetAndGoBack() + } + // 3 + private func setupUI() { + view.addSubview(dimmedView) + view.addSubview(bottomSheetView) + dimmedView.alpha = 0.0 + addChild(contentViewController) + bottomSheetView.addSubview(contentViewController.view) + contentViewController.didMove(toParent: self) + bottomSheetView.clipsToBounds = true + dimmedView.alpha = 0.0 + + + setupLayout() + } + + // 4 + private func showBottomSheet() { + let safeAreaHeight: CGFloat = view.safeAreaLayoutGuide.layoutFrame.height + let bottomPadding: CGFloat = view.safeAreaInsets.bottom + + bottomSheetViewTopConstraint.constant = (safeAreaHeight + bottomPadding) - defaultHeight + + UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseIn, animations: { + self.dimmedView.alpha = 0.7 + self.view.layoutIfNeeded() + }, completion: nil) + } + private func hideBottomSheetAndGoBack() { + let safeAreaHeight = view.safeAreaLayoutGuide.layoutFrame.height + let bottomPadding = view.safeAreaInsets.bottom + bottomSheetViewTopConstraint.constant = safeAreaHeight + bottomPadding + UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseIn, animations: { + self.dimmedView.alpha = 0.0 + self.view.layoutIfNeeded() + }) { _ in + if self.presentingViewController != nil { + self.dismiss(animated: false, completion: nil) + } + } + } + + private func setupLayout() { + dimmedView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + dimmedView.topAnchor.constraint(equalTo: view.topAnchor), + dimmedView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + dimmedView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + dimmedView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + bottomSheetView.translatesAutoresizingMaskIntoConstraints = false + let topConstant = view.safeAreaInsets.bottom + view.safeAreaLayoutGuide.layoutFrame.height + + bottomSheetViewTopConstraint = bottomSheetView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: topConstant) + NSLayoutConstraint.activate([ + bottomSheetView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + bottomSheetView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), + bottomSheetView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + bottomSheetViewTopConstraint, + ]) + contentViewController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + contentViewController.view.topAnchor.constraint(equalTo: bottomSheetView.topAnchor), + contentViewController.view.leadingAnchor.constraint(equalTo: bottomSheetView.leadingAnchor), + contentViewController.view.trailingAnchor.constraint(equalTo: bottomSheetView.trailingAnchor), + contentViewController.view.bottomAnchor.constraint(equalTo: bottomSheetView.bottomAnchor) + ]) + } + + +} + + +class MypageInfoViewController: UIViewController { + + let mypageLabel = UILabel() + let myinfoLabel = UILabel() + let mynameLabel = UILabel() + let myinfobutton = UIButton(type: .system) + + + let imageView = UIImageView() + + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + setupView() + setupNavigationBarButton() + setupMyImageView() + setupMyImageViewConstraints() + setupMyinfoLabel() + setupMyinfoLabelConstraints() + setupMynameLabel() + setupMynameLabelConstraints() + setupMyinfoButton() + + } + + func setupView() { + view.addSubview(mypageLabel) + view.addSubview(myinfoLabel) + view.addSubview(imageView) + view.addSubview(mynameLabel) + view.addSubview(myinfobutton) + + } + + func setupNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + + func setupMyinfoLabel() { + myinfoLabel.text = "내 정보" + myinfoLabel.font = .boldSystemFont(ofSize: 24) + myinfoLabel.textAlignment = .center + myinfoLabel.textColor = .black + } + + func setupMyinfoLabelConstraints() { + myinfoLabel.snp.makeConstraints{ make in + make.top.equalTo(mypageLabel.snp.top).offset(30) + make.leading.equalTo(mypageLabel.snp.leading).offset(16) + } + } + + + + + func setupMyImageView() { + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.layer.cornerRadius = 40 + imageView.image = UIImage(named: "SampleImage") + } + + func setupMyImageViewConstraints() { + imageView.snp.makeConstraints { make in + make.top.equalTo(myinfoLabel.snp.bottom).offset(60) + make.centerX.equalToSuperview() + make.width.height.equalTo(134) + } + } + + + func setupMynameLabel() { + mynameLabel.text = "안녕하세요, 김이지님!" + mynameLabel.font = .boldSystemFont(ofSize: 24) + mynameLabel.textAlignment = .center + mynameLabel.textColor = .black + } + + func setupMynameLabelConstraints() { + mynameLabel.snp.makeConstraints{ make in + make.top.equalTo(imageView.snp.bottom).offset(18) + make.centerX.equalToSuperview() + + } + } + + + func setupMyinfoButton() { + myinfobutton.setTitle("내 정보 수정", for: .normal) + myinfobutton.setTitleColor(.black, for: .normal) + myinfobutton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14) + myinfobutton.backgroundColor = UIColor(hex: "FA735B") + myinfobutton.layer.cornerRadius = 20 + myinfobutton.addTarget(self, action: #selector(myinfoButtonTapped), for: .touchUpInside) + myinfobutton.snp.makeConstraints { make in + make.top.equalTo(mynameLabel.snp.bottom).offset(12) + make.centerX.equalToSuperview() + make.height.equalTo(40) + make.width.equalTo(101) + + } + } + + @objc func myinfoButtonTapped() { + navigationController?.popViewController(animated: true) + } + + } + + + + + + + + diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/MypageViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/MypageViewController.swift new file mode 100644 index 0000000..1e80e62 --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/MypageViewController.swift @@ -0,0 +1,398 @@ +// +// MypageViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import Foundation +import UIKit +import SnapKit + + +private let cellID = "Cell" + +class MypageViewController: UIViewController { + + let tableview = UITableView(frame: .zero, style: .grouped) + + let myPagefirstMenu = ["내 정보", "와인 주문 내역", "위시리스트"] + let myPageSecondMenu = ["1:1 문의하기", "제휴 입점 문의하기", "개선 제안하기"] + let myPageThirdMenu = ["서비스 이용약관", "위치정보 이용약관", "개인정보 처리방침"] + + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + + + configureUI() + + } + + func configureUI() { + + view.addSubview(tableview) + tableview.backgroundColor = .white + + tableview.translatesAutoresizingMaskIntoConstraints = false + + tableview.delegate = self + tableview.dataSource = self + + tableview.register(MyPageCell.self, forCellReuseIdentifier: cellID) + + + tableview.tableHeaderView = TopHeader(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 100)) + + tableview.topAnchor.constraint(equalTo: view.topAnchor).isActive = true + tableview.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true + tableview.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true + tableview.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true + + } + +} + +extension MypageViewController: UITableViewDataSource { + + + func numberOfSections(in tableView: UITableView) -> Int { + return 3 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == 0 { + return myPagefirstMenu.count + } + if section == 1 { + return myPageSecondMenu.count + } + else { + return myPageThirdMenu.count + } + + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! MyPageCell + cell.backgroundColor = UIColor(hex: "D9D9D9") + + if indexPath.section == 0{ + cell.textLabel?.text = myPagefirstMenu[indexPath.row] + } + if indexPath.section == 1{ + cell.textLabel?.text = myPageSecondMenu[indexPath.row] + } + if indexPath.section == 2{ + cell.textLabel?.text = myPageThirdMenu[indexPath.row] + } + + return cell + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + if section == 0 { + let header = FirstSectionHeader() + return header + } + if section == 1 { + let header = SecondSectionHeader() + return header + } + else { + let header = ThirdSectionHeader() + return header + + } + } + +} + +extension MypageViewController: UITableViewDelegate { + + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + if section == 0 { + return 30 + } else { + return 30 + } + + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if let cell = tableView.cellForRow(at: indexPath) { + cell.contentView.backgroundColor = UIColor(hex: "#FF9F8E") // 셀의 배경색을 빨간색으로 변경 + } + switch indexPath.section { + case 0: + switch indexPath.row { + case 0: + let bottomSheetContent = MypageInfoViewController() // 실제 사용하고자 하는 뷰 컨트롤러 + let bottomSheetVC = MyPageBottomSheetViewController(contentViewController: bottomSheetContent) + bottomSheetVC.modalPresentationStyle = .overFullScreen + bottomSheetVC.modalTransitionStyle = .crossDissolve + present(bottomSheetVC, animated: true, completion: nil) + case 1: + let controller = MyPageSettingsViewController() + navigationController?.pushViewController(controller, animated: true) + case 2: + print("\(myPagefirstMenu[indexPath.row])") + default: + print("\(myPagefirstMenu[indexPath.row])") + } + case 1: + switch indexPath.row { + case 0: + let controller = MyPageSettingsViewController() + navigationController?.pushViewController(controller, animated: true) + case 1: + print("\(myPageSecondMenu[indexPath.row])") + case 2: + print("\(myPageSecondMenu[indexPath.row])") + default: + print("\(myPageSecondMenu[indexPath.row])") + } + case 2: + switch indexPath.row { + case 0: + let controller = MypageViewController() + navigationController?.pushViewController(controller, animated: true) + case 1: + print("\(myPageThirdMenu[indexPath.row])") + case 2: + print("\(myPageThirdMenu[indexPath.row])") + default: + print("\(myPageThirdMenu[indexPath.row])") + } + default: + break + } + } + + func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { + if let cell = tableView.cellForRow(at: indexPath) { + cell.contentView.backgroundColor = UIColor(hex: "D9D9D9") // 원래 색상으로 복원 + } + } +} + + + +class FirstSectionHeader: UIView { + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "기본 정보" + label.font = .systemFont(ofSize: 14) + return label + }() + + override init (frame: CGRect) { + super.init (frame: frame) + backgroundColor = .white + + + addSubview(titleLabel) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true + titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true + titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + titleLabel.rightAnchor.constraint(equalTo: rightAnchor).isActive = true + + } + + + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented" ) + } + +} + +class SecondSectionHeader: UIView { + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "고객센터" + label.font = .systemFont(ofSize: 14) + return label + }() + + override init (frame: CGRect) { + super.init (frame: frame) + + backgroundColor = .white + addSubview(titleLabel) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true + titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true + titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + titleLabel.rightAnchor.constraint(equalTo: rightAnchor).isActive = true + + + + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented" ) + } + +} + +class ThirdSectionHeader: UIView { + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "이용약관" + label.font = .systemFont(ofSize: 14) + return label + }() + + override init (frame: CGRect) { + super.init (frame: frame) + backgroundColor = .white + + + addSubview(titleLabel) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true + titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true + titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + titleLabel.rightAnchor.constraint(equalTo: rightAnchor).isActive = true + + } + + + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented" ) + } + +} + +class TopHeader: UIView { + + // UI 요소들 + let topView: UIView = { + let view = UIView() + view.backgroundColor = .white + return view + }() + + let searchButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("", for: .normal) + let searchImage = UIImage(systemName: "magnifyingglass") + button.setImage(searchImage, for: .normal) + button.tintColor = UIColor(hue: 0, saturation: 0, brightness: 0.4, alpha: 1.0) + return button + }() + + let cartButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("", for: .normal) + let cartImage = UIImage(systemName: "cart") + button.setImage(cartImage, for: .normal) + button.tintColor = UIColor(hue: 0, saturation: 0, brightness: 0.4, alpha: 1.0) + return button + }() + + let mypageLabel: UILabel = { + let label = UILabel() + label.text = "마이페이지" + label.font = .boldSystemFont(ofSize: 28) + label.textAlignment = .center + label.textColor = .black + return label + }() + + let stackView = UIStackView() + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(topView) + addSubview(stackView) + + setupStackView() + setupConstraints() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupStackView() { + let leftStackView = UIStackView(arrangedSubviews: [mypageLabel]) + leftStackView.axis = .horizontal + leftStackView.alignment = .leading + + let rightStackView = UIStackView(arrangedSubviews: [searchButton, cartButton]) + rightStackView.axis = .horizontal + rightStackView.alignment = .trailing + rightStackView.spacing = 20 + + stackView.addArrangedSubview(leftStackView) + stackView.addArrangedSubview(UIView()) + stackView.addArrangedSubview(rightStackView) + stackView.axis = .horizontal + stackView.distribution = .fill + stackView.spacing = 5 + } + + func setupConstraints() { + stackView.snp.makeConstraints { make in + make.top.equalTo(safeAreaLayoutGuide.snp.top) + make.leading.trailing.equalToSuperview().inset(20) + make.height.equalTo(34) + } + + topView.translatesAutoresizingMaskIntoConstraints = false + + topView.topAnchor.constraint(equalTo: topAnchor).isActive = true + topView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true + topView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + topView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true + } +} + +class MyPageCell: UITableViewCell { + + let menuLable = UILabel() + + + override init(style: UITableViewCell.CellStyle, reuseIdentifier reuseIdenfitifer: String?) { + super.init(style: style, reuseIdentifier: reuseIdenfitifer) + + configureUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + } + + func configureUI() { + addSubview(menuLable) + menuLable.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + menuLable.centerYAnchor.constraint(equalTo: centerYAnchor), + menuLable.leftAnchor.constraint(equalTo: leftAnchor, constant: 12) + ]) + } + +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/Settings/WishListViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/Settings/WishListViewController.swift new file mode 100644 index 0000000..03609ae --- /dev/null +++ b/Drink-EG/Drink-EG/Sources/VCs/Settings/WishListViewController.swift @@ -0,0 +1,219 @@ +// +// WishListViewController.swift +// Drink-EG +// +// Created by 이호연 on 8/16/24. +// + +import UIKit +import SnapKit + + + +class MyPageWishListViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { + + private let items = [ + ["title": "19charles", "imageName": "SampleImage", "rating": "4.5", "price": "165,000원"], + ["title": "19charles", "imageName": "SampleImage", "rating": "4.5", "price": "165,000원"], + ["title": "19charles", "imageName": "SampleImage", "rating": "4.5", "price": "165,000원"], + ["title": "19charles", "imageName": "SampleImage", "rating": "4.5", "price": "165,000원"], + ] + + lazy var scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.alwaysBounceVertical = true + return scrollView + }() + + lazy var contentView: UIView = { + return UIView() + }() + + lazy var titleLabel: UILabel = { + let label = UILabel() + label.text = "위시리스트" + label.font = UIFont.boldSystemFont(ofSize: 24) + label.textColor = .black + return label + }() + + lazy var lowerCollectionStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.spacing = 10 + stackView.distribution = .fillEqually + return stackView + }() + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + + setupScrollView() + setupView() + setupNavigationBarButton() + setupWishCommunityLowerCollectionView() + setupStackViewConstraints() + setupTitleLabel() + } + + func setupView() { + contentView.addSubview(lowerCollectionStackView) + contentView.addSubview(titleLabel) + } + + func setupScrollView() { + view.addSubview(scrollView) + scrollView.addSubview(contentView) + + scrollView.snp.makeConstraints { make in + make.edges.equalTo(view) + } + + + } + + func setupNavigationBarButton() { + navigationItem.hidesBackButton = true + let backArrow = UIImage(systemName: "chevron.backward") + let leftButton = UIBarButtonItem(image: backArrow, style: .plain, target: self, action: #selector(backButtonTapped)) + navigationItem.leftBarButtonItem = leftButton + leftButton.tintColor = .black + } + + func setupTitleLabel() { + titleLabel.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(66) + make.leading.equalTo(view).offset(16) + } + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + func setupWishCommunityLowerCollectionView() { + for item in items { + let cellView = WishCustomCellView() + cellView.configure(title: item["title"]!, imageName: item["imageName"]!, rating: item["rating"]!, price: item["price"]!) + cellView.layer.cornerRadius = 10 + cellView.layer.masksToBounds = true + + lowerCollectionStackView.addArrangedSubview(cellView) + + cellView.snp.makeConstraints { make in + make.height.equalTo(120) + make.width.equalTo(366) + } + } + } + + func setupStackViewConstraints() { + lowerCollectionStackView.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(24) + make.leading.equalTo(contentView.snp.leading).offset(16) + make.centerX.equalTo(contentView.snp.centerX) + } + } + + + +} + +class WishCustomCellView: UIView { + let titleLabel = UILabel() + let imageView = UIImageView() + let ratingLabel = UILabel() + let priceLabel = UILabel() + let likeButton = UIButton(type: .custom) + + private let likeImage = UIImage(systemName: "heart.circle") + private let nlikeImage = UIImage(systemName: "heart.fill") + + override init(frame: CGRect) { + super.init(frame: frame) + + layer.cornerRadius = 10 + layer.masksToBounds = true + backgroundColor = UIColor.lightGray + + + + addSubview(imageView) + addSubview(titleLabel) + addSubview(ratingLabel) + addSubview(priceLabel) + addSubview(likeButton) + + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.layer.cornerRadius = 10 + + titleLabel.textColor = .black + titleLabel.font = UIFont.boldSystemFont(ofSize: 18) + + ratingLabel.textColor = .black + ratingLabel.font = UIFont.systemFont(ofSize: 12) + + priceLabel.textColor = .black + priceLabel.font = UIFont.systemFont(ofSize: 16) + + configureLikeButton() + setupConstraints() + } + + func setupConstraints() { + imageView.snp.makeConstraints { make in + make.width.height.equalTo(80) + make.leading.equalTo(snp.leading).offset(8) + make.centerY.equalTo(snp.centerY) + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(imageView.snp.trailing).offset(8) + make.top.equalTo(snp.top).offset(10) + } + + ratingLabel.snp.makeConstraints { make in + make.trailing.equalTo(snp.trailing).offset(-8) + make.top.equalTo(titleLabel.snp.top) + } + + priceLabel.snp.makeConstraints { make in + make.leading.equalTo(titleLabel.snp.leading) + make.top.equalTo(titleLabel.snp.bottom).offset(8) + } + + likeButton.snp.makeConstraints { make in + make.trailing.equalTo(snp.trailing).offset(-8) + make.bottom.equalTo(snp.bottom).offset(-10) + make.width.height.equalTo(24) + } + } + + func configure(title: String, imageName: String, rating: String, price: String) { + titleLabel.text = title + imageView.image = UIImage(named: imageName) + ratingLabel.text = rating + priceLabel.text = price + } + + private func configureLikeButton() { + likeButton.setImage(nlikeImage?.withRenderingMode(.alwaysOriginal), for: .normal) + likeButton.backgroundColor = .clear + likeButton.addTarget(self, action: #selector(likeButtonTapped), for: .touchUpInside) + } + + @objc private func likeButtonTapped(_ sender: UIButton) { + sender.isSelected.toggle() + if sender.isSelected { + sender.setImage(likeImage?.withRenderingMode(.alwaysOriginal), for: .selected) + } else { + sender.setImage(nlikeImage?.withRenderingMode(.alwaysOriginal), for: .normal) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdKindTasteTestViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdKindTasteTestViewController.swift index e49c162..94ab334 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdKindTasteTestViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdKindTasteTestViewController.swift @@ -9,8 +9,8 @@ import UIKit class ThirdKindTasteTestViewController: UIViewController { - var kind: [String] = ["레드", "화이트", "스파클링", "로제", "주정강화", "네츄럴", "기타"] - var kindEng : [String] = ["Red", "White", "Sparkling", "Rose", "Port", "Natural", "etc"] + var kind: [String] = ["레드", "화이트", "스파클링", "로제", "주정강화", "기타"] + var kindEng : [String] = ["레드", "화이트", "스파클링", "로제", "포트", "dessert"] var selectedIndexPaths: [IndexPath] = [] var selectedWineName : [String] = [] diff --git a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdNationTasteTestViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdNationTasteTestViewController.swift index a6fedf2..7443dfc 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdNationTasteTestViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdNationTasteTestViewController.swift @@ -10,7 +10,7 @@ import UIKit class ThirdNationTasteTestViewController: UIViewController { var nation: [String] = ["프랑스", "이탈리아", "미국", "칠레", "스페인", "호주", "아르헨티나", "독일", "뉴질랜드", "포르투갈", "오스트리아", "그리스", "슬로베니아", "헝가리", "캐나다", "대한민국", "기타1"] - var nationEng: [String] = ["France", "Italy", "United States", "Chile", "Spain", "Australia", "Argentina", "Germany", "New Zealand", "Portugal", "Austria", "Greece", "Slovenia", "Hungary", "Canada", "South Korea", "Other"] +// var nationEng: [String] = ["France", "Italy", "United States", "Chile", "Spain", "Australia", "Argentina", "Germany", "New Zealand", "Portugal", "Austria", "Greece", "Slovenia", "Hungary", "Canada", "South Korea", "Other"] var selectedIndexPaths: [IndexPath] = [] private var selectedNations : [String] = [] @@ -147,7 +147,7 @@ extension ThirdNationTasteTestViewController: UICollectionViewDataSource, UIColl let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TasteTestSecondCollectionViewCell", for: indexPath) as! TasteTestSecondCollectionViewCell - cell.configure(imageName: nation[indexPath.item], nationName: nationEng[indexPath.item]) + cell.configure(imageName: nation[indexPath.item], nationName: nation[indexPath.item]) return cell } diff --git a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdVarietyTasteTestViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdVarietyTasteTestViewController.swift index a6d8da9..b2a909e 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdVarietyTasteTestViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TasteTest/ThirdVarietyTasteTestViewController.swift @@ -165,12 +165,12 @@ class ThirdVarietyTasteTestViewController: UIViewController { func callAPI(completion: @escaping (Bool) -> Void) { if let data = self.memberInfoDTO { provider.request(.patchMember(data: data)) { result in - print(data) +// print(data) switch result { case .success(let response): do { let data = try response.map(APIResponseMemberResponse.self) - print("Success: \(data)") +// print("Success: \(data)") LoginViewController.isFirstLogin = false completion(data.isSuccess) } catch { diff --git a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift index b4ad513..21ace15 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/CheckNoteViewController.swift @@ -5,7 +5,6 @@ // Created by 이수현 on 8/13/24. // -import Foundation import UIKit import SnapKit import Moya @@ -419,4 +418,3 @@ class CheckNoteViewController: UIViewController { } } } - diff --git a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift index 0380795..a6d7b89 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/TastingNote/RatingViewController.swift @@ -5,7 +5,6 @@ // Created by 이수현 on 8/13/24. // -import Foundation import UIKit import SnapKit import Moya diff --git a/Drink-EG/Drink-EG/Sources/VCs/WineClass/SavingVideoViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/WineClass/SavingVideoViewController.swift index 22be0f6..7c795de 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/WineClass/SavingVideoViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/WineClass/SavingVideoViewController.swift @@ -5,7 +5,6 @@ // Created by 김도연 on 7/21/24. // -import Foundation import UIKit class SaveVideoViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { diff --git a/Drink-EG/Drink-EG/Sources/VCs/WineClass/WineClassMainViewController.swift b/Drink-EG/Drink-EG/Sources/VCs/WineClass/WineClassMainViewController.swift index 53ebcbc..9e79bd5 100644 --- a/Drink-EG/Drink-EG/Sources/VCs/WineClass/WineClassMainViewController.swift +++ b/Drink-EG/Drink-EG/Sources/VCs/WineClass/WineClassMainViewController.swift @@ -226,322 +226,3 @@ class WineClassMainViewController: UIViewController, UICollectionViewDataSource, } } -class CarouselLayout: UICollectionViewFlowLayout { - - public var sideItemScale: CGFloat = UIConstants.sideItemScale - public var sideItemAlpha: CGFloat = UIConstants.sideItemAlpha - public var spacing: CGFloat = UIConstants.carouselSpacing - - public var isPagingEnabled: Bool = false - - private var isSetup: Bool = false - - override public func prepare() { - super.prepare() - if isSetup == false { - setupLayout() - isSetup = true - } - } - - private func setupLayout() { - guard let collectionView = self.collectionView else { return } - - let collectionViewSize = collectionView.bounds.size - let xInset = (collectionViewSize.width - self.itemSize.width) / 2 - let yInset = (collectionViewSize.height - self.itemSize.height) / 2 - - self.sectionInset = UIEdgeInsets(top: yInset, left: xInset, bottom: yInset, right: xInset) - let itemWidth = self.itemSize.width - let scaledItemOffset = (itemWidth - (itemWidth * (self.sideItemScale + (1 - self.sideItemScale) / 2))) / 2 - self.minimumLineSpacing = spacing - scaledItemOffset - - self.scrollDirection = .horizontal - } - - public override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { - return true - } - - public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { - guard let superAttributes = super.layoutAttributesForElements(in: rect), - let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] - else { return nil } - - return attributes.map({ self.transformLayoutAttributes(attributes: $0) }) - } - - private func transformLayoutAttributes(attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { - guard let collectionView = self.collectionView else { return attributes } - - let collectionCenter = collectionView.frame.size.width / 2 - let contentOffset = collectionView.contentOffset.x - let center = attributes.center.x - contentOffset - - let maxDistance = 8 * (self.itemSize.width + self.minimumLineSpacing) - let distance = min(abs(collectionCenter - center), maxDistance) - let ratio = (maxDistance - distance) / maxDistance - - let alpha = ratio * (1 - self.sideItemAlpha) + self.sideItemAlpha - let scale = ratio * (1 - self.sideItemScale) + self.sideItemScale - - attributes.alpha = alpha - if abs(collectionCenter - center) > maxDistance + 1 { - attributes.alpha = 0 - } - - let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size) - let dist = attributes.frame.midX - visibleRect.midX - var transform = CATransform3DScale(CATransform3DIdentity, scale, scale, 1) - transform = CATransform3DTranslate(transform, 0, 0, -abs(dist / 1000)) - attributes.transform3D = transform - - return attributes - } - - override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { - guard let collectionView = self.collectionView else { - let latestOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) - return latestOffset - } - - let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.frame.width, height: collectionView.frame.height) - guard let rectAttributes = super.layoutAttributesForElements(in: targetRect) else { return .zero } - - var offsetAdjustment = CGFloat.greatestFiniteMagnitude - let horizontalCenter = proposedContentOffset.x + collectionView.frame.width / 2 - - for layoutAttributes in rectAttributes { - let itemHorizontalCenter = layoutAttributes.center.x - if (itemHorizontalCenter - horizontalCenter).magnitude < offsetAdjustment.magnitude { - offsetAdjustment = itemHorizontalCenter - horizontalCenter - } - } - - return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y) - } -} - -//class CarouselLayout: UICollectionViewFlowLayout { -// -// public var sideItemScale: CGFloat = 0.8 // 측면 아이템의 크기 비율 -// public var sideItemAlpha: CGFloat = 0.6 // 측면 아이템의 투명도 -// public var spacing: CGFloat = -80 // 셀 간의 간격 (겹치도록 음수로 설정) -// -// public var isPagingEnabled: Bool = false -// -// private var isSetup: Bool = false -// -// override public func prepare() { -// super.prepare() -// if isSetup == false { -// setupLayout() -// isSetup = true -// } -// } -// -// private func setupLayout() { -// guard let collectionView = self.collectionView else { return } -// -// let collectionViewSize = collectionView.bounds.size -// let xInset = (collectionViewSize.width - self.itemSize.width) / 2 -// let yInset = (collectionViewSize.height - self.itemSize.height) / 2 -// -// self.sectionInset = UIEdgeInsets(top: yInset, left: xInset, bottom: yInset, right: xInset) -// -// // 셀 간의 간격 계산 (절반씩 겹치도록 설정) -// self.minimumLineSpacing = spacing -// -// self.scrollDirection = .horizontal -// } -// -// public override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { -// return true -// } -// -// public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { -// guard let superAttributes = super.layoutAttributesForElements(in: rect), -// let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] -// else { return nil } -// -// return attributes.map({ self.transformLayoutAttributes(attributes: $0) }) -// } -// -// private func transformLayoutAttributes(attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { -// guard let collectionView = self.collectionView else { return attributes } -// -// let collectionCenter = collectionView.frame.size.width / 2 -// let contentOffset = collectionView.contentOffset.x -// let center = attributes.center.x - contentOffset -// -// // 중앙에서 떨어진 거리 계산 -// let maxDistance = collectionView.frame.size.width / 2 -// let distance = min(abs(collectionCenter - center), maxDistance) -// let ratio = (maxDistance - distance) / maxDistance -// -// // 투명도 및 크기 조정 -// let alpha = ratio * (1 - self.sideItemAlpha) + self.sideItemAlpha -// let scale = ratio * (1 - self.sideItemScale) + self.sideItemScale -// -// attributes.alpha = alpha -// attributes.transform3D = CATransform3DMakeScale(scale, scale, 1) -// -// // 3D 효과 추가 (회전 효과) -// let rotationAngle = (1 - ratio) * (.pi / 8) // 최대 22.5도 회전 -// attributes.transform3D = CATransform3DRotate(attributes.transform3D, rotationAngle, 0, 1, 0) -// -// // 중앙에서 멀어지면 투명하게 -// if abs(collectionCenter - center) > maxDistance { -// attributes.alpha = 0 -// } -// -// return attributes -// } -// -// override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { -// guard let collectionView = self.collectionView else { -// let latestOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) -// return latestOffset -// } -// -// let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.frame.width, height: collectionView.frame.height) -// guard let rectAttributes = super.layoutAttributesForElements(in: targetRect) else { return .zero } -// -// var offsetAdjustment = CGFloat.greatestFiniteMagnitude -// let horizontalCenter = proposedContentOffset.x + collectionView.frame.width / 2 -// -// for layoutAttributes in rectAttributes { -// let itemHorizontalCenter = layoutAttributes.center.x -// if abs(itemHorizontalCenter - horizontalCenter) < abs(offsetAdjustment) { -// offsetAdjustment = itemHorizontalCenter - horizontalCenter -// } -// } -// -// return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y) -// } -//} - - -class WineClassCell: UICollectionViewCell { - static let reuseIdentifier = "WineClassCell" - - let imageView = UIImageView() - - override init(frame: CGRect) { - super.init(frame: frame) - - imageView.contentMode = .scaleAspectFill - imageView.clipsToBounds = true - contentView.addSubview(imageView) - - imageView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - contentView.layer.cornerRadius = UIConstants.cellCornerRadius - contentView.layer.masksToBounds = true - contentView.layer.shadowColor = UIColor.black.cgColor - contentView.layer.shadowOpacity = UIConstants.cellShadowOpacity - contentView.layer.shadowOffset = UIConstants.cellShadowOffset - contentView.layer.shadowRadius = UIConstants.cellShadowRadius - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configure(with image: UIImage) { - imageView.image = image - } -} - - - -struct UIConstants { - static let searchBarHeight: CGFloat = 34 - static let searchBarCornerRadius: CGFloat = 8 - static let labelFontSize: CGFloat = 28 - static let titleClassLabelFontSize: CGFloat = 24 - static let labelTopOffset: CGFloat = 10 - static let viewSideInset: CGFloat = 16 - static let classViewHeight: CGFloat = 250 - static let mainClassViewItemSize = CGSize(width: 100, height: 180) - static let mainClassViewSpacing: CGFloat = 20 - static let carouselSpacing: CGFloat = -90 - static let sideItemScale: CGFloat = 0.4 - static let sideItemAlpha: CGFloat = 0.8 - static let cellCornerRadius: CGFloat = 10 - static let cellShadowOpacity: Float = 0.3 - static let cellShadowOffset = CGSize(width: 0, height: 2) - static let cellShadowRadius: CGFloat = 5 -} - -class CustomButton: UIButton { - - override init(frame: CGRect) { - super.init(frame: frame) - setupButton() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setupButton() - } - - private func setupButton() { - // 버튼 타이틀 설정 - self.setTitle("내 보관함", for: .normal) - self.setTitleColor(.lightGray, for: .normal) - - // 버튼 배경색 설정 - self.backgroundColor = .white - - // 버튼의 둥근 모서리 설정 - self.layer.cornerRadius = 15 - self.layer.masksToBounds = false - - // 그림자 설정 - self.layer.shadowColor = UIColor.black.cgColor - self.layer.shadowOpacity = 0.25 - self.layer.shadowOffset = CGSize(width: 0, height: 2) - self.layer.shadowRadius = 5 - } - - override func layoutSubviews() { - super.layoutSubviews() - // 버튼의 크기가 결정된 후에 그림자 경로 설정 - self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath - } -} - - -extension UIView { - - func applyTopShadow(shadowColor: UIColor = .black, shadowOpacity: Float = 0.25, shadowRadius: CGFloat = 5, shadowOffset: CGSize = CGSize(width: 0, height: -3)) { - // 그림자 색상 - self.layer.shadowColor = shadowColor.cgColor - - // 그림자 투명도 - self.layer.shadowOpacity = shadowOpacity - - // 그림자 퍼짐 정도 - self.layer.shadowRadius = shadowRadius - - // 그림자 오프셋 (상단에만 그림자가 보이도록 설정) - self.layer.shadowOffset = shadowOffset - - // 레이아웃이 완료된 후에 shadowPath 설정 - DispatchQueue.main.async { - let shadowPath = UIBezierPath() - shadowPath.move(to: CGPoint(x: 0, y: 0)) - shadowPath.addLine(to: CGPoint(x: self.bounds.width, y: 0)) - shadowPath.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height / 4)) - shadowPath.addLine(to: CGPoint(x: 0, y: self.bounds.height / 4)) - shadowPath.close() - - self.layer.shadowPath = shadowPath.cgPath - } - } -} - -