diff --git a/Hankkijogbo/Hankkijogbo.xcodeproj/project.pbxproj b/Hankkijogbo/Hankkijogbo.xcodeproj/project.pbxproj index 2375ae61..b18a7468 100644 --- a/Hankkijogbo/Hankkijogbo.xcodeproj/project.pbxproj +++ b/Hankkijogbo/Hankkijogbo.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 8322D03D2C5FB38700F6D725 /* HankkiCategoryTagLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8322D03C2C5FB38700F6D725 /* HankkiCategoryTagLabel.swift */; }; 832546EC2C3F28F900B8C3DC /* DropDownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832546EB2C3F28F900B8C3DC /* DropDownView.swift */; }; 8336B5222CBACDC90034474E /* NetworkResultDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8336B5212CBACDC90034474E /* NetworkResultDelegate.swift */; }; + 8364B4022D17CA8D005FA842 /* CustomLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8364B4012D17CA81005FA842 /* CustomLineView.swift */; }; 837F10DB2C4A851A00E3CCE6 /* HankkiInfoCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837F10D92C4A851A00E3CCE6 /* HankkiInfoCardView.swift */; }; 837F10DC2C4A851A00E3CCE6 /* ReportCompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837F10DA2C4A851A00E3CCE6 /* ReportCompleteViewController.swift */; }; 838BEB032C38196300AAA153 /* TabBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 838BEB022C38196300AAA153 /* TabBarItem.swift */; }; @@ -54,7 +55,6 @@ 83DBEDB42C2566300042BA48 /* StringLiterals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83DBEDB32C2566300042BA48 /* StringLiterals.swift */; }; 83DBEDB92C25666E0042BA48 /* MainButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83DBEDB82C25666E0042BA48 /* MainButton.swift */; }; 83DBEDBE2C25698B0042BA48 /* Then in Frameworks */ = {isa = PBXBuildFile; productRef = 83DBEDBD2C25698B0042BA48 /* Then */; }; - 83DBEDC12C2569A80042BA48 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 83DBEDC02C2569A80042BA48 /* SnapKit */; }; 83DBEDC42C256A3B0042BA48 /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 83DBEDC32C256A3B0042BA48 /* Moya */; }; 83DBEDC62C256A7A0042BA48 /* UIView+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83DBEDC52C256A7A0042BA48 /* UIView+.swift */; }; 83DBEDC82C256AD00042BA48 /* NSObject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83DBEDC72C256AD00042BA48 /* NSObject+.swift */; }; @@ -67,6 +67,7 @@ 83DD39762C46AEC800DD7EC3 /* MarkerInfoCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83DD39752C46AEC800DD7EC3 /* MarkerInfoCardView.swift */; }; 83E9B3422D0C0553009F033E /* FilteringBottomSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83E9B3412D0C054B009F033E /* FilteringBottomSheetViewController.swift */; }; 861704F72C38304D00D99E50 /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 861704F62C38304D00D99E50 /* AlertViewController.swift */; }; + 862518AD2D1CA33C00E8B2A3 /* GetSharedZipListResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 862518AC2D1CA33C00E8B2A3 /* GetSharedZipListResponseDTO.swift */; }; 8641516A2C67B9AE00E2FD44 /* MyZipListBottomSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864151632C67B9AD00E2FD44 /* MyZipListBottomSheetViewController.swift */; }; 8641516B2C67B9AE00E2FD44 /* MyZipListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864151642C67B9AD00E2FD44 /* MyZipListCollectionViewCell.swift */; }; 8641516C2C67B9AE00E2FD44 /* MyZipListHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864151652C67B9AD00E2FD44 /* MyZipListHeaderView.swift */; }; @@ -81,6 +82,12 @@ 864FA9122C3D34B80051EA36 /* MypageCollectionViewCellEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864FA9112C3D34B80051EA36 /* MypageCollectionViewCellEnum.swift */; }; 864FA91C2C3D63400051EA36 /* BottomButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864FA91B2C3D63400051EA36 /* BottomButtonView.swift */; }; 865826062C4170BE00265401 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865826052C4170BE00265401 /* LoginViewController.swift */; }; + 865938142D10226200A07E7A /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 865938132D10226200A07E7A /* SnapKit */; }; + 8659381C2D10262800A07E7A /* KakaoSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 8659381B2D10262800A07E7A /* KakaoSDK */; }; + 8659381E2D10262800A07E7A /* KakaoSDKCommon in Frameworks */ = {isa = PBXBuildFile; productRef = 8659381D2D10262800A07E7A /* KakaoSDKCommon */; }; + 865938202D10262800A07E7A /* KakaoSDKShare in Frameworks */ = {isa = PBXBuildFile; productRef = 8659381F2D10262800A07E7A /* KakaoSDKShare */; }; + 865938222D10262800A07E7A /* KakaoSDKTemplate in Frameworks */ = {isa = PBXBuildFile; productRef = 865938212D10262800A07E7A /* KakaoSDKTemplate */; }; + 865938242D14939700A07E7A /* URL+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865938232D14939700A07E7A /* URL+.swift */; }; 865C3D022C44E9E0009D9BEA /* MoreButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865C3D012C44E9E0009D9BEA /* MoreButton.swift */; }; 865C3D042C4506C8009D9BEA /* ZipFooterTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865C3D032C4506C8009D9BEA /* ZipFooterTableView.swift */; }; 865D59C62C7B72C9004CC517 /* FullLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865D59C52C7B72C9004CC517 /* FullLoadingView.swift */; }; @@ -91,6 +98,10 @@ 8668D2482C7DAEEC001CBCA0 /* Amplitude in Frameworks */ = {isa = PBXBuildFile; productRef = 8668D2472C7DAEEC001CBCA0 /* Amplitude */; }; 8668D24A2C7DE0CA001CBCA0 /* SetupAmplitude.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8668D2492C7DE0CA001CBCA0 /* SetupAmplitude.swift */; }; 8668D24C2C7EAF5F001CBCA0 /* AmplitudeLiterals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8668D24B2C7EAF5F001CBCA0 /* AmplitudeLiterals.swift */; }; + 866DFE0A2D1548BD006EE662 /* HankkiListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866DFE092D1548BD006EE662 /* HankkiListViewController.swift */; }; + 866DFE0C2D154ACF006EE662 /* ZipDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866DFE0B2D154ACF006EE662 /* ZipDetailViewController.swift */; }; + 866DFE0E2D155DC6006EE662 /* CreateZipViewControllerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866DFE0D2D155DC6006EE662 /* CreateZipViewControllerType.swift */; }; + 866DFE142D17295A006EE662 /* GetZipOwnershipResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 866DFE132D172959006EE662 /* GetZipOwnershipResponseDTO.swift */; }; 8670A7832C4971A80098DCF1 /* UniversityModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8670A7822C4971A80098DCF1 /* UniversityModel.swift */; }; 8670A7862C49C3290098DCF1 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 8670A7852C49C3290098DCF1 /* Lottie */; }; 8670A78A2C49C3670098DCF1 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8670A7892C49C3670098DCF1 /* OnboardingViewController.swift */; }; @@ -100,7 +111,6 @@ 8670A7942C49CBB50098DCF1 /* onboarding4.json in Resources */ = {isa = PBXBuildFile; fileRef = 8670A7932C49CBB50098DCF1 /* onboarding4.json */; }; 8670A7972C49EFC80098DCF1 /* OnboardingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8670A7962C49EFC80098DCF1 /* OnboardingModel.swift */; }; 86784E8B2C3FC0CD00E94A5D /* CreateZipViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86784E8A2C3FC0CD00E94A5D /* CreateZipViewController.swift */; }; - 86784E8F2C4021E200E94A5D /* TagTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86784E8E2C4021E200E94A5D /* TagTextField.swift */; }; 86880BD02C46C0FD00CAEF58 /* AuthAPIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86880BCF2C46C0FD00CAEF58 /* AuthAPIService.swift */; }; 86880BD22C46C27E00CAEF58 /* AuthTargetType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86880BD12C46C27E00CAEF58 /* AuthTargetType.swift */; }; 86880BD52C46C55200CAEF58 /* UserTargetType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86880BD42C46C55200CAEF58 /* UserTargetType.swift */; }; @@ -130,7 +140,7 @@ 86880C382C4920A700CAEF58 /* PostZipRequestDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86880C372C4920A700CAEF58 /* PostZipRequestDTO.swift */; }; 86B761142C3DC79F00413059 /* ZipListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B761132C3DC79F00413059 /* ZipListViewController.swift */; }; 86B761162C3DC7AB00413059 /* ZipListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B761152C3DC7AB00413059 /* ZipListCollectionViewCell.swift */; }; - 86B7611C2C3DE04200413059 /* HankkiListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B7611B2C3DE04200413059 /* HankkiListViewController.swift */; }; + 86B7611C2C3DE04200413059 /* BaseHankkiListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B7611B2C3DE04200413059 /* BaseHankkiListViewController.swift */; }; 86B7611F2C3DE05800413059 /* HankkiListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B7611E2C3DE05800413059 /* HankkiListTableViewCell.swift */; }; 86B761212C3DF60800413059 /* ZipHeaderTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B761202C3DF60800413059 /* ZipHeaderTableView.swift */; }; 86B761232C3EC87A00413059 /* ZipListCollectionViewCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B761222C3EC87A00413059 /* ZipListCollectionViewCellModel.swift */; }; @@ -262,6 +272,7 @@ 8322D03C2C5FB38700F6D725 /* HankkiCategoryTagLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HankkiCategoryTagLabel.swift; sourceTree = ""; }; 832546EB2C3F28F900B8C3DC /* DropDownView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownView.swift; sourceTree = ""; }; 8336B5212CBACDC90034474E /* NetworkResultDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkResultDelegate.swift; sourceTree = ""; }; + 8364B4012D17CA81005FA842 /* CustomLineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomLineView.swift; sourceTree = ""; }; 837F10D92C4A851A00E3CCE6 /* HankkiInfoCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HankkiInfoCardView.swift; sourceTree = ""; }; 837F10DA2C4A851A00E3CCE6 /* ReportCompleteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportCompleteViewController.swift; sourceTree = ""; }; 838BEB022C38196300AAA153 /* TabBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarItem.swift; sourceTree = ""; }; @@ -299,6 +310,7 @@ 83DD39752C46AEC800DD7EC3 /* MarkerInfoCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkerInfoCardView.swift; sourceTree = ""; }; 83E9B3412D0C054B009F033E /* FilteringBottomSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilteringBottomSheetViewController.swift; sourceTree = ""; }; 861704F62C38304D00D99E50 /* AlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = ""; }; + 862518AC2D1CA33C00E8B2A3 /* GetSharedZipListResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetSharedZipListResponseDTO.swift; sourceTree = ""; }; 864151632C67B9AD00E2FD44 /* MyZipListBottomSheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyZipListBottomSheetViewController.swift; sourceTree = ""; }; 864151642C67B9AD00E2FD44 /* MyZipListCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyZipListCollectionViewCell.swift; sourceTree = ""; }; 864151652C67B9AD00E2FD44 /* MyZipListHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyZipListHeaderView.swift; sourceTree = ""; }; @@ -314,6 +326,7 @@ 864FA91B2C3D63400051EA36 /* BottomButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomButtonView.swift; sourceTree = ""; }; 865826052C4170BE00265401 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; 865826072C41762600265401 /* Hankkijogbo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Hankkijogbo.entitlements; sourceTree = ""; }; + 865938232D14939700A07E7A /* URL+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+.swift"; sourceTree = ""; }; 865C3D012C44E9E0009D9BEA /* MoreButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreButton.swift; sourceTree = ""; }; 865C3D032C4506C8009D9BEA /* ZipFooterTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipFooterTableView.swift; sourceTree = ""; }; 865C3D052C45B4B3009D9BEA /* Target Support Files/Pods-Hankkijogbo/Pods-Hankkijogbo.debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Target Support Files/Pods-Hankkijogbo/Pods-Hankkijogbo.debug.xcconfig"; sourceTree = ""; }; @@ -326,6 +339,10 @@ 86685C572C3BD89500C080C4 /* UnivCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnivCollectionViewCell.swift; sourceTree = ""; }; 8668D2492C7DE0CA001CBCA0 /* SetupAmplitude.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupAmplitude.swift; sourceTree = ""; }; 8668D24B2C7EAF5F001CBCA0 /* AmplitudeLiterals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmplitudeLiterals.swift; sourceTree = ""; }; + 866DFE092D1548BD006EE662 /* HankkiListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HankkiListViewController.swift; sourceTree = ""; }; + 866DFE0B2D154ACF006EE662 /* ZipDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipDetailViewController.swift; sourceTree = ""; }; + 866DFE0D2D155DC6006EE662 /* CreateZipViewControllerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateZipViewControllerType.swift; sourceTree = ""; }; + 866DFE132D172959006EE662 /* GetZipOwnershipResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetZipOwnershipResponseDTO.swift; sourceTree = ""; }; 8670A7822C4971A80098DCF1 /* UniversityModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversityModel.swift; sourceTree = ""; }; 8670A7892C49C3670098DCF1 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; 8670A78B2C49C6BD0098DCF1 /* onboarding2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = onboarding2.json; sourceTree = ""; }; @@ -334,7 +351,6 @@ 8670A7932C49CBB50098DCF1 /* onboarding4.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = onboarding4.json; sourceTree = ""; }; 8670A7962C49EFC80098DCF1 /* OnboardingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingModel.swift; sourceTree = ""; }; 86784E8A2C3FC0CD00E94A5D /* CreateZipViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateZipViewController.swift; sourceTree = ""; }; - 86784E8E2C4021E200E94A5D /* TagTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagTextField.swift; sourceTree = ""; }; 86880BCF2C46C0FD00CAEF58 /* AuthAPIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPIService.swift; sourceTree = ""; }; 86880BD12C46C27E00CAEF58 /* AuthTargetType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthTargetType.swift; sourceTree = ""; }; 86880BD42C46C55200CAEF58 /* UserTargetType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTargetType.swift; sourceTree = ""; }; @@ -365,7 +381,7 @@ 86880C372C4920A700CAEF58 /* PostZipRequestDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostZipRequestDTO.swift; sourceTree = ""; }; 86B761132C3DC79F00413059 /* ZipListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipListViewController.swift; sourceTree = ""; }; 86B761152C3DC7AB00413059 /* ZipListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipListCollectionViewCell.swift; sourceTree = ""; }; - 86B7611B2C3DE04200413059 /* HankkiListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HankkiListViewController.swift; sourceTree = ""; }; + 86B7611B2C3DE04200413059 /* BaseHankkiListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseHankkiListViewController.swift; sourceTree = ""; }; 86B7611E2C3DE05800413059 /* HankkiListTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HankkiListTableViewCell.swift; sourceTree = ""; }; 86B761202C3DF60800413059 /* ZipHeaderTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipHeaderTableView.swift; sourceTree = ""; }; 86B761222C3EC87A00413059 /* ZipListCollectionViewCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipListCollectionViewCellModel.swift; sourceTree = ""; }; @@ -481,10 +497,14 @@ buildActionMask = 2147483647; files = ( 83DBEDBE2C25698B0042BA48 /* Then in Frameworks */, - 83DBEDC12C2569A80042BA48 /* SnapKit in Frameworks */, + 8659381C2D10262800A07E7A /* KakaoSDK in Frameworks */, 83DBEDC42C256A3B0042BA48 /* Moya in Frameworks */, + 865938222D10262800A07E7A /* KakaoSDKTemplate in Frameworks */, 839FC7232C47A3DB00B7FEDD /* Kingfisher in Frameworks */, + 8659381E2D10262800A07E7A /* KakaoSDKCommon in Frameworks */, + 865938142D10226200A07E7A /* SnapKit in Frameworks */, 8668D2482C7DAEEC001CBCA0 /* Amplitude in Frameworks */, + 865938202D10262800A07E7A /* KakaoSDKShare in Frameworks */, 8670A7862C49C3290098DCF1 /* Lottie in Frameworks */, 9E38C1F6B1DB0B110CF9BCB7 /* Pods_Hankkijogbo.framework in Frameworks */, ); @@ -775,6 +795,7 @@ 83DBEDA72C2565840042BA48 /* Extensions */ = { isa = PBXGroup; children = ( + 865938232D14939700A07E7A /* URL+.swift */, 83DBEDC72C256AD00042BA48 /* NSObject+.swift */, A240EA5A2C459DEA000FF458 /* CATransition+.swift */, A2DEBF442C3BD0DD00DE14A9 /* UIScreen+.swift */, @@ -1037,7 +1058,7 @@ isa = PBXGroup; children = ( 86784E8A2C3FC0CD00E94A5D /* CreateZipViewController.swift */, - 86784E8E2C4021E200E94A5D /* TagTextField.swift */, + 866DFE0D2D155DC6006EE662 /* CreateZipViewControllerType.swift */, ); path = View; sourceTree = ""; @@ -1251,8 +1272,10 @@ isa = PBXGroup; children = ( 86B7611D2C3DE04600413059 /* Cell */, - 86B7611B2C3DE04200413059 /* HankkiListViewController.swift */, + 86B7611B2C3DE04200413059 /* BaseHankkiListViewController.swift */, 86B7612F2C3EEDEE00413059 /* HankkiListViewControllerType.swift */, + 866DFE092D1548BD006EE662 /* HankkiListViewController.swift */, + 866DFE0B2D154ACF006EE662 /* ZipDetailViewController.swift */, ); path = View; sourceTree = ""; @@ -1556,6 +1579,7 @@ A29A441C2C6ADC11002B8D36 /* HankkiLineView */ = { isa = PBXGroup; children = ( + 8364B4012D17CA81005FA842 /* CustomLineView.swift */, A29A441D2C6ADC28002B8D36 /* DottedLineView.swift */, ); path = HankkiLineView; @@ -1641,6 +1665,8 @@ children = ( A2C9FCAE2C49985800868DF7 /* GetMyZipListResponseDTO.swift */, A2C9FCAF2C49985800868DF7 /* GetZipListResponseDTO.swift */, + 862518AC2D1CA33C00E8B2A3 /* GetSharedZipListResponseDTO.swift */, + 866DFE132D172959006EE662 /* GetZipOwnershipResponseDTO.swift */, ); path = Response; sourceTree = ""; @@ -1760,11 +1786,15 @@ name = Hankkijogbo; packageProductDependencies = ( 83DBEDBD2C25698B0042BA48 /* Then */, - 83DBEDC02C2569A80042BA48 /* SnapKit */, 83DBEDC32C256A3B0042BA48 /* Moya */, 839FC7222C47A3DB00B7FEDD /* Kingfisher */, 8670A7852C49C3290098DCF1 /* Lottie */, 8668D2472C7DAEEC001CBCA0 /* Amplitude */, + 865938132D10226200A07E7A /* SnapKit */, + 8659381B2D10262800A07E7A /* KakaoSDK */, + 8659381D2D10262800A07E7A /* KakaoSDKCommon */, + 8659381F2D10262800A07E7A /* KakaoSDKShare */, + 865938212D10262800A07E7A /* KakaoSDKTemplate */, ); productName = Hankkijogbo; productReference = 83DBED722C255A180042BA48 /* Hankkijogbo.app */; @@ -1796,11 +1826,12 @@ mainGroup = 83DBED692C255A180042BA48; packageReferences = ( 83DBEDBC2C25698A0042BA48 /* XCRemoteSwiftPackageReference "Then" */, - 83DBEDBF2C2569A80042BA48 /* XCRemoteSwiftPackageReference "SnapKit" */, 83DBEDC22C256A3B0042BA48 /* XCRemoteSwiftPackageReference "Moya" */, 839FC7212C47A3DB00B7FEDD /* XCRemoteSwiftPackageReference "Kingfisher" */, 8670A7842C49C3290098DCF1 /* XCRemoteSwiftPackageReference "lottie-ios" */, 8668D2462C7DAEEC001CBCA0 /* XCRemoteSwiftPackageReference "Amplitude-iOS" */, + 865938122D10226200A07E7A /* XCRemoteSwiftPackageReference "SnapKit" */, + 8659381A2D10262800A07E7A /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */, ); productRefGroup = 83DBED732C255A180042BA48 /* Products */; projectDirPath = ""; @@ -1911,6 +1942,7 @@ 830285472C455BB10004D9F7 /* NetworkService.swift in Sources */, A2DEBF622C3D67D400DE14A9 /* SelectImageCollectionViewCell.swift in Sources */, A2EC33AF2C47166F00809840 /* LocationTargetType.swift in Sources */, + 862518AD2D1CA33C00E8B2A3 /* GetSharedZipListResponseDTO.swift in Sources */, A2DEBF5C2C3D2F6700DE14A9 /* ReportCompositionalLayoutFactory.swift in Sources */, 8641516C2C67B9AE00E2FD44 /* MyZipListHeaderView.swift in Sources */, A21DAE9B2CD9085B004D896C /* ModifyMenuViewModel.swift in Sources */, @@ -1918,13 +1950,14 @@ A2DEBF452C3BD0DD00DE14A9 /* UIScreen+.swift in Sources */, 838BEB052C382B0700AAA153 /* TabBarController.swift in Sources */, 86880BF62C46E93400CAEF58 /* GetMeHankkiListResponseDTO.swift in Sources */, - 86B7611C2C3DE04200413059 /* HankkiListViewController.swift in Sources */, + 86B7611C2C3DE04200413059 /* BaseHankkiListViewController.swift in Sources */, 838BEB032C38196300AAA153 /* TabBarItem.swift in Sources */, 8668D24C2C7EAF5F001CBCA0 /* AmplitudeLiterals.swift in Sources */, 864FA9032C3D1F7B0051EA36 /* MypageViewController.swift in Sources */, 86B761142C3DC79F00413059 /* ZipListViewController.swift in Sources */, A240EA352C4405A4000FF458 /* UIResponder+.swift in Sources */, 86784E8B2C3FC0CD00E94A5D /* CreateZipViewController.swift in Sources */, + 866DFE0A2D1548BD006EE662 /* HankkiListViewController.swift in Sources */, A29A441E2C6ADC28002B8D36 /* DottedLineView.swift in Sources */, 864FA90C2C3D20BE0051EA36 /* MypageQuitFooterView.swift in Sources */, 864FA9122C3D34B80051EA36 /* MypageCollectionViewCellEnum.swift in Sources */, @@ -1938,11 +1971,13 @@ 830285552C4562BE0004D9F7 /* HankkiTargetType.swift in Sources */, 865C3D022C44E9E0009D9BEA /* MoreButton.swift in Sources */, A2C9FC952C48F7D100868DF7 /* GetHankkiDetailResponseDTO.swift in Sources */, - 86784E8F2C4021E200E94A5D /* TagTextField.swift in Sources */, 8302F8E72C3E991F004ADAA4 /* TypeCollectionViewCell.swift in Sources */, A27AD9392CB8057700515D3B /* EditMenuCollectionViewCell.swift in Sources */, A240EA3C2C4450E2000FF458 /* HankkiDetailViewController.swift in Sources */, A2C9FCB32C49AFF800868DF7 /* PostHankkiRequestDTO.swift in Sources */, + A240EA402C445D6B000FF458 /* HankkiDetailHeaderView.swift in Sources */, + 866DFE0C2D154ACF006EE662 /* ZipDetailViewController.swift in Sources */, + A240EA542C4551A3000FF458 /* HankkiReportOptionFooterView.swift in Sources */, A240EA402C445D6B000FF458 /* HankkiMenuHeaderView.swift in Sources */, A2471B8D2C46AB770080FA30 /* UIApplication+.swift in Sources */, A2EC33C82C47184500809840 /* GetSearchedLocationResponseDTO.swift in Sources */, @@ -1961,6 +1996,7 @@ 8668D24A2C7DE0CA001CBCA0 /* SetupAmplitude.swift in Sources */, 830285592C4565940004D9F7 /* GetHankkiListRequestDTO.swift in Sources */, A2DEBF782C3E700A00DE14A9 /* AddMenuCollectionViewCell.swift in Sources */, + 865938242D14939700A07E7A /* URL+.swift in Sources */, 8302854B2C455E860004D9F7 /* BaseAPIService.swift in Sources */, A2EC33AD2C47166500809840 /* ReportTargetType.swift in Sources */, A23D119A2C4811790023480C /* HankkiDebouncer.swift in Sources */, @@ -1992,8 +2028,10 @@ 864FA9062C3D20150051EA36 /* MypageHankkiCollectionViewCell.swift in Sources */, 861704F72C38304D00D99E50 /* AlertViewController.swift in Sources */, 839FC7202C46E64000B7FEDD /* GetSortOptionFilterResponseDTO.swift in Sources */, + 866DFE142D17295A006EE662 /* GetZipOwnershipResponseDTO.swift in Sources */, 864FA91C2C3D63400051EA36 /* BottomButtonView.swift in Sources */, A2079BA92C68C26D00817651 /* HankkiCategoryModel.swift in Sources */, + 8364B4022D17CA8D005FA842 /* CustomLineView.swift in Sources */, 8641516D2C67B9AE00E2FD44 /* MyZipViewModel.swift in Sources */, 83DBEDB42C2566300042BA48 /* StringLiterals.swift in Sources */, 83DBED782C255A180042BA48 /* SceneDelegate.swift in Sources */, @@ -2046,6 +2084,7 @@ A2FF94112C31660E001ADA03 /* BaseDTO.swift in Sources */, A200C66F2D19EA0D0065C749 /* DetailMapView.swift in Sources */, 837F10DC2C4A851A00E3CCE6 /* ReportCompleteViewController.swift in Sources */, + 866DFE0E2D155DC6006EE662 /* CreateZipViewControllerType.swift in Sources */, 865D59C62C7B72C9004CC517 /* FullLoadingView.swift in Sources */, A23F35512D2211BF00B6F8C8 /* NaverMapTargetType.swift in Sources */, 86B761232C3EC87A00413059 /* ZipListCollectionViewCellModel.swift in Sources */, @@ -2367,20 +2406,28 @@ minimumVersion = 3.0.0; }; }; - 83DBEDBF2C2569A80042BA48 /* XCRemoteSwiftPackageReference "SnapKit" */ = { + 83DBEDC22C256A3B0042BA48 /* XCRemoteSwiftPackageReference "Moya" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit"; + repositoryURL = "https://github.com/Moya/Moya"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 5.7.1; + minimumVersion = 15.0.3; }; }; - 83DBEDC22C256A3B0042BA48 /* XCRemoteSwiftPackageReference "Moya" */ = { + 865938122D10226200A07E7A /* XCRemoteSwiftPackageReference "SnapKit" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Moya/Moya"; + repositoryURL = "https://github.com/SnapKit/SnapKit.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 15.0.3; + minimumVersion = 5.7.1; + }; + }; + 8659381A2D10262800A07E7A /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kakao/kakao-ios-sdk"; + requirement = { + branch = master; + kind = branch; }; }; 8668D2462C7DAEEC001CBCA0 /* XCRemoteSwiftPackageReference "Amplitude-iOS" */ = { @@ -2412,16 +2459,36 @@ package = 83DBEDBC2C25698A0042BA48 /* XCRemoteSwiftPackageReference "Then" */; productName = Then; }; - 83DBEDC02C2569A80042BA48 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 83DBEDBF2C2569A80042BA48 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; 83DBEDC32C256A3B0042BA48 /* Moya */ = { isa = XCSwiftPackageProductDependency; package = 83DBEDC22C256A3B0042BA48 /* XCRemoteSwiftPackageReference "Moya" */; productName = Moya; }; + 865938132D10226200A07E7A /* SnapKit */ = { + isa = XCSwiftPackageProductDependency; + package = 865938122D10226200A07E7A /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = SnapKit; + }; + 8659381B2D10262800A07E7A /* KakaoSDK */ = { + isa = XCSwiftPackageProductDependency; + package = 8659381A2D10262800A07E7A /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDK; + }; + 8659381D2D10262800A07E7A /* KakaoSDKCommon */ = { + isa = XCSwiftPackageProductDependency; + package = 8659381A2D10262800A07E7A /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKCommon; + }; + 8659381F2D10262800A07E7A /* KakaoSDKShare */ = { + isa = XCSwiftPackageProductDependency; + package = 8659381A2D10262800A07E7A /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKShare; + }; + 865938212D10262800A07E7A /* KakaoSDKTemplate */ = { + isa = XCSwiftPackageProductDependency; + package = 8659381A2D10262800A07E7A /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKTemplate; + }; 8668D2472C7DAEEC001CBCA0 /* Amplitude */ = { isa = XCSwiftPackageProductDependency; package = 8668D2462C7DAEEC001CBCA0 /* XCRemoteSwiftPackageReference "Amplitude-iOS" */; diff --git a/Hankkijogbo/Hankkijogbo.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Hankkijogbo/Hankkijogbo.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6cccd2a2..4c94a3d6 100644 --- a/Hankkijogbo/Hankkijogbo.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Hankkijogbo/Hankkijogbo.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "83f265caa107bd411a5b1166549c8ea62979fd689642172db418fac79f0298a8", + "originHash" : "ec45888e133ae9767d5888f71108bbada090fd616f4ec1a668477eeace7cbafd", "pins" : [ { "identity" : "alamofire", @@ -28,6 +28,15 @@ "version" : "1.0.3" } }, + { + "identity" : "kakao-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kakao/kakao-ios-sdk", + "state" : { + "branch" : "master", + "revision" : "ab4309c1950550add307046ad1e08024c7514603" + } + }, { "identity" : "kingfisher", "kind" : "remoteSourceControl", @@ -76,7 +85,7 @@ { "identity" : "snapkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/SnapKit/SnapKit", + "location" : "https://github.com/SnapKit/SnapKit.git", "state" : { "revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4", "version" : "5.7.1" diff --git a/Hankkijogbo/Hankkijogbo/Application/AppDelegate.swift b/Hankkijogbo/Hankkijogbo/Application/AppDelegate.swift index 3cab887e..d4a71d39 100644 --- a/Hankkijogbo/Hankkijogbo/Application/AppDelegate.swift +++ b/Hankkijogbo/Hankkijogbo/Application/AppDelegate.swift @@ -8,12 +8,14 @@ import UIKit import Amplitude +import KakaoSDKCommon @main class AppDelegate: UIResponder, UIApplicationDelegate { - + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Amplitude.instance().initializeApiKey(Config.Amplitude) + KakaoSDK.initSDK(appKey: Config.Kakao) return true } diff --git a/Hankkijogbo/Hankkijogbo/Application/SceneDelegate.swift b/Hankkijogbo/Hankkijogbo/Application/SceneDelegate.swift index 059317e1..59d3f844 100644 --- a/Hankkijogbo/Hankkijogbo/Application/SceneDelegate.swift +++ b/Hankkijogbo/Hankkijogbo/Application/SceneDelegate.swift @@ -16,8 +16,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: windowScene) - window?.rootViewController = SplashViewController() window?.makeKeyAndVisible() + + guard let urlContext = connectionOptions.urlContexts.first else { + window?.rootViewController = SplashViewController() + return + } + + // 딥링크로 앱이 시작된 경우 처리합니다 + handleDeeplink(urlContext.url) } func sceneDidDisconnect(_ scene: UIScene) { @@ -36,6 +43,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func sceneDidEnterBackground(_ scene: UIScene) { } + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + guard let urlContext = URLContexts.first else { return } + + // 앱이 실행중일 때, 딥링크로 접속했을 경우 처리를 진행합니다. + handleDeeplink(urlContext.url) + } } private extension SceneDelegate { @@ -44,9 +57,9 @@ private extension SceneDelegate { func checkAppleAccountStatus() { let appleIDProvider = ASAuthorizationAppleIDProvider() let userId: String = UserDefaults.standard.getUserId() - + if userId.isEmpty { return } - + appleIDProvider.getCredentialState(forUserID: userId) { (credentialState, _) in DispatchQueue.main.async { switch credentialState { @@ -61,7 +74,7 @@ private extension SceneDelegate { } } - // 서버에 사용자의 정보가 저장되어있는지 확인합니다. + /// 서버에 사용자의 정보가 저장되어있는지 확인합니다. func checkServerAccountStatus() { let accessToken: String = UserDefaults.standard.getAccesshToken() @@ -69,8 +82,54 @@ private extension SceneDelegate { getMe() } } + + /// 딥링크로 앱이 시작된 경우, url 에 따라 view를 처리합니다 + private func handleDeeplink(_ url: URL) { + guard url.scheme == "kakao\(Config.Kakao)" else { return } + + switch url.host { + case "kakaolink": + let queryParameters: [String: String] = url.getQueryParameters() + + switch Set(queryParameters.keys) { + case ["sharedZipId"]: + guard let zipId = Int(queryParameters["sharedZipId"] ?? "") else { print("❌ NO-EXISTENT DEEP LINK ❌ - ZIP ID IS ERROR"); return } + handleSharedZipDeeplink(zipId: zipId) + + default: + print("❌ NO-EXISTENT DEEP LINK ❌ - NO PARAMETERS") + } + default: + print("❌ NO-EXISTENT DEEP LINK ❌") + } + } + + /// 족보 공유의 딥링크를 이용한 경우, zipVC를 반환합니다. + private func handleSharedZipDeeplink(zipId: Int) { + if UserDefaults.standard.isLogin { + getZipOwnership(zipId: zipId) + } else { + presentZipDetails(zipId: zipId, isOwnership: false) + } + } + + /// 공유받은 족보 상세 페이지로 이동 + private func presentZipDetails(zipId: Int, isOwnership: Bool) { + let tabBarController = TabBarController() + tabBarController.selectedIndex = 2 + let navigationController = HankkiNavigationController(rootViewController: tabBarController) + + window?.rootViewController = navigationController + + if isOwnership { + navigationController.pushViewController(ZipDetailViewController(zipId: zipId, type: .myZip), animated: false) + } else { + navigationController.pushViewController(ZipDetailViewController(zipId: zipId, type: .sharedZip), animated: false) + } + } } +// MARK: - API private extension SceneDelegate { func getMe() { NetworkService.shared.userService.getMe { result in @@ -106,4 +165,20 @@ private extension SceneDelegate { } } } + + func getZipOwnership(zipId: Int) { + NetworkService.shared.zipService.getZipOwnership(zipId: zipId) { result in + switch result { + case .success(let response): + guard let isOwnership = response?.data.isOwner else { return } + self.presentZipDetails(zipId: zipId, isOwnership: isOwnership) + + case .notFound: + fatalError("\(zipId)의 족보가 없습니다") + + default: + fatalError("잘못된 접근입니다!") + } + } + } } diff --git a/Hankkijogbo/Hankkijogbo/Global/Components/HankkiButtons/BottomButtonView.swift b/Hankkijogbo/Hankkijogbo/Global/Components/HankkiButtons/BottomButtonView.swift index 0fc9859f..1482964e 100644 --- a/Hankkijogbo/Hankkijogbo/Global/Components/HankkiButtons/BottomButtonView.swift +++ b/Hankkijogbo/Hankkijogbo/Global/Components/HankkiButtons/BottomButtonView.swift @@ -18,6 +18,7 @@ final class BottomButtonView: BaseView { setupStyle() } } + let lineButtonText: String let leftButtonText: String let rightButtonText: String @@ -28,6 +29,8 @@ final class BottomButtonView: BaseView { var rightButtonHandler: ButtonAction? var gradientColor: UIColor + var isPrimaryButtonAble: Bool = false + // MARK: - UI Properties private let primaryButton: UIButton = UIButton() @@ -49,7 +52,8 @@ final class BottomButtonView: BaseView { lineButtonHandler: ButtonAction? = nil, leftButtonHandler: ButtonAction? = nil, rightButtonHandler: ButtonAction? = nil, - gradientColor: UIColor = .hankkiWhite + gradientColor: UIColor = .hankkiWhite, + isPrimaryButtonAble: Bool = false ) { self.primaryButtonText = primaryButtonText self.lineButtonText = lineButtonText @@ -62,6 +66,10 @@ final class BottomButtonView: BaseView { self.gradientColor = gradientColor super.init(frame: frame) + if isPrimaryButtonAble { + self.setupEnabledDoneButton() + } + setupButtonAction() } diff --git a/Hankkijogbo/Hankkijogbo/Global/Components/HankkiLineView/CustomLineView.swift b/Hankkijogbo/Hankkijogbo/Global/Components/HankkiLineView/CustomLineView.swift new file mode 100644 index 00000000..40b75547 --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Global/Components/HankkiLineView/CustomLineView.swift @@ -0,0 +1,45 @@ +// +// GrayLineView.swift +// Hankkijogbo +// +// Created by Gahyun Kim on 12/22/24. +// + +import UIKit + +import SnapKit + +/// 색상과 높이를 동적으로 설정할 수 있는 Custom Line View +/// default : gray200, height 1 +final class CustomLineView: UIView { + + init(frame: CGRect = .zero, backgroundColor: UIColor = .gray200, height: Int = 1) { + super.init(frame: frame) + + setupStyle(backgroundColor: backgroundColor) + setupLayout(height: height) + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + + setupStyle(backgroundColor: .gray200) + setupLayout(height: 1) + } + + override var intrinsicContentSize: CGSize { + return CGSize(width: UIView.noIntrinsicMetric, height: 1) + } +} + +private extension CustomLineView { + func setupStyle(backgroundColor: UIColor) { + self.backgroundColor = backgroundColor + } + + func setupLayout(height: Int) { + self.snp.makeConstraints { + $0.height.equalTo(height) + } + } +} diff --git a/Hankkijogbo/Hankkijogbo/Global/Consts/StringLiterals.swift b/Hankkijogbo/Hankkijogbo/Global/Consts/StringLiterals.swift index 5bf2d9fc..9c2eb773 100644 --- a/Hankkijogbo/Hankkijogbo/Global/Consts/StringLiterals.swift +++ b/Hankkijogbo/Hankkijogbo/Global/Consts/StringLiterals.swift @@ -9,7 +9,11 @@ import Foundation // swiftlint:disable nesting enum StringLiterals { - + enum Kakao { + static let storeUrl = "itms-apps://itunes.apple.com/app/362057947" + static let zipShareTemplete = 115383 + } + enum Common { static let goToHome = "홈으로" static let withdraw = "탈퇴하기" @@ -65,6 +69,17 @@ enum StringLiterals { static let primaryButton = "로그인하기" } + enum NeedLoginToSharedZip { + static let title = "족보를 확인하려면\n로그인이 필요해요" + static let primaryButton = "로그인" + } + + enum NeedOneMoreHankkiToShare { + static let title = "족보에 식당이 없어요\n식당 1개 이상 시에만 공유할 수 있어요" + static let secondaryButton = back + static let primaryButton = "둘러보기" + } + enum Logout { static let title = "정말 로그아웃 하실 건가요?" static let secondaryButton = Common.logout @@ -130,6 +145,7 @@ enum StringLiterals { static let deleteAlready = "이미 삭제된 식당입니다" static let serverError = "오류가 발생했어요 다시 시도해주세요" static let accessError = "로그인 유효기간이 만료되었어요 재로그인 해주세요" + static let addSharedZip = "족보가 추가되었습니다" } enum Toolbar { @@ -257,9 +273,9 @@ enum StringLiterals { } enum Option { - static let Terms = "약관 및 정책" - static let OneonOne = "1:1 문의" - static let Logout = Common.logout + static let terms = "약관 및 정책" + static let oneOnOne = "1:1 문의" + static let logout = Common.logout } enum Header { @@ -307,9 +323,21 @@ enum StringLiterals { } } + enum SharedZip { + static let zipShareDefaultImageURL = Config.DefaultHankkiImageURL + + static let navigation = "공유받은 족보" + static let addButton = "내 족보에 추가하기" + + static let viewTitle = "공유받은 족보의\n새로운 이름을 지어주세요" + static let viewDescription = "공유받은 족보는 내 마음대로 편집할 수 있어요!" + static let submitButton = "추가하기" + } + enum ExternalLink { - static let OneonOne = "https://tally.so/r/mO0oJY" - static let Terms = "https://fast-kilometer-dbf.notion.site/FAQ-bb4d74b681d14f4f91bbbcc829f6d023?pvs=4" + static let oneOnOne = "https://tally.so/r/mO0oJY" + static let terms = "https://fast-kilometer-dbf.notion.site/FAQ-bb4d74b681d14f4f91bbbcc829f6d023?pvs=4" + static let linkTree = "https://link.inpock.co.kr/hankkilink?fbclid=PAZXh0bgNhZW0CMTEAAabp7jPfQGVtGfHXOSEA-urXPNPbog0a0Rco43_a-zsdcxQOvFqVXQoqsXQ_aem_gyGO3bZoFAlf0tMF7QTqKg" } enum Onboarding { diff --git a/Hankkijogbo/Hankkijogbo/Global/Extensions/URL+.swift b/Hankkijogbo/Hankkijogbo/Global/Extensions/URL+.swift new file mode 100644 index 00000000..560e5485 --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Global/Extensions/URL+.swift @@ -0,0 +1,18 @@ +// +// URL+.swift +// Hankkijogbo +// +// Created by 심서현 on 12/20/24. +// + +import Foundation + +extension URL { + // URL 의 쿼리 파라미터를 딕셔너리 객체로 변환한다. + func getQueryParameters() -> [String:String] { + var parameters: [String:String] = [:] + let components = URLComponents(url: self, resolvingAgainstBaseURL: false) + components?.queryItems?.forEach { parameters[$0.name] = $0.value } + return parameters + } +} diff --git a/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/Contents.json b/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/Contents.json index a7d2defb..594598bd 100644 --- a/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/Contents.json +++ b/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "btn_heart.svg", + "filename" : "ic_heart.svg", "idiom" : "universal" } ], diff --git a/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/btn_heart.svg b/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/btn_heart.svg deleted file mode 100644 index 47fb10ce..00000000 --- a/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/btn_heart.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/ic_heart.svg b/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/ic_heart.svg new file mode 100644 index 00000000..f1ac80dc --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Global/Resources/Assets/Assets.xcassets/Button/btn_like_selected_list.imageset/ic_heart.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Hankkijogbo/Hankkijogbo/Global/Resources/Config.swift b/Hankkijogbo/Hankkijogbo/Global/Resources/Config.swift index cfd01672..c571abe5 100644 --- a/Hankkijogbo/Hankkijogbo/Global/Resources/Config.swift +++ b/Hankkijogbo/Hankkijogbo/Global/Resources/Config.swift @@ -17,6 +17,8 @@ enum Config { static let Amplitude = "Amplitude" static let reverseGeocodingClientId = "ReverseGeocodingClientId" static let reverseGeocodingClientSecret = "ReverseGeocodingClientSecret" + static let Kakao = "Kakao" + static let DefaultHankkiImageURL = "DefaultHankkiImageURL" } } @@ -63,4 +65,18 @@ extension Config { } return key }() + + static let Kakao: String = { + guard let key = Config.infoDictionary[Keys.Plist.Kakao] as? String else { + fatalError("Kakao is not set in plist for this configuration.") + } + return key + }() + + static let DefaultHankkiImageURL: String = { + guard let key = Config.infoDictionary[Keys.Plist.DefaultHankkiImageURL] as? String else { + fatalError("DefaultHankkiImageURL is not set in plist for this configuration.") + } + return key + }() } diff --git a/Hankkijogbo/Hankkijogbo/Global/Supporting Files/Info.plist b/Hankkijogbo/Hankkijogbo/Global/Supporting Files/Info.plist index 1c23e9d8..dac5eb34 100644 --- a/Hankkijogbo/Hankkijogbo/Global/Supporting Files/Info.plist +++ b/Hankkijogbo/Hankkijogbo/Global/Supporting Files/Info.plist @@ -12,8 +12,28 @@ Light BASE_URL $(BASE_URL) + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + kakao${Kakao} + + + + DefaultHankkiImageURL + ${DefaultHankkiImageURL} ITSAppUsesNonExemptEncryption + Kakao + ${Kakao} + LSApplicationQueriesSchemes + + kakaokompassauth + kakaolink + NMFClientId $(NMFClientId) UIAppFonts diff --git a/Hankkijogbo/Hankkijogbo/Network/Zip/Response/GetSharedZipListResponseDTO.swift b/Hankkijogbo/Hankkijogbo/Network/Zip/Response/GetSharedZipListResponseDTO.swift new file mode 100644 index 00000000..9b5d0d4f --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Network/Zip/Response/GetSharedZipListResponseDTO.swift @@ -0,0 +1,24 @@ +// +// GetSharedZipListResponseDTO.swift +// Hankkijogbo +// +// Created by 심서현 on 12/26/24. +// + +import Foundation + +struct GetSharedZipDetailResponseData: Codable { + let title: String + let details: [String] + let nickname: String + let stores: [GetSharedZipDetailData] +} + +struct GetSharedZipDetailData: Codable { + let id: Int + let name: String + let imageUrl: String? + let category: String + let lowestPrice: Int + let heartCount: Int +} diff --git a/Hankkijogbo/Hankkijogbo/Network/Zip/Response/GetZipOwnershipResponseDTO.swift b/Hankkijogbo/Hankkijogbo/Network/Zip/Response/GetZipOwnershipResponseDTO.swift new file mode 100644 index 00000000..db554a86 --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Network/Zip/Response/GetZipOwnershipResponseDTO.swift @@ -0,0 +1,12 @@ +// +// GetZipOwnershipResponseDTO.swift +// Hankkijogbo +// +// Created by 심서현 on 12/22/24. +// + +import Foundation + +struct GetZipOwnershipResponseData: Codable { + let isOwner: Bool +} diff --git a/Hankkijogbo/Hankkijogbo/Network/Zip/ZipAPIService.swift b/Hankkijogbo/Hankkijogbo/Network/Zip/ZipAPIService.swift index 3ce1b158..0538950c 100644 --- a/Hankkijogbo/Hankkijogbo/Network/Zip/ZipAPIService.swift +++ b/Hankkijogbo/Hankkijogbo/Network/Zip/ZipAPIService.swift @@ -12,17 +12,23 @@ import Moya protocol ZipAPIServiceProtocol { typealias GetMyZipListResponseDTO = BaseDTO typealias GetZipDetailResponseDTO = BaseDTO + typealias GetSharedZipDetailResponseDTO = BaseDTO + typealias GetZipOwnershipResponseDTO = BaseDTO func getMyZipList(id: Int, completion: @escaping(NetworkResult) -> Void) - func getZipList(zipId: Int, completion: @escaping(NetworkResult) -> Void) + func getZipDetail(zipId: Int, completion: @escaping(NetworkResult) -> Void) + func getSharedZipDetail(zipId: Int, completion: @escaping (NetworkResult) -> Void) + func postZipBatchDelete(requesBody: PostZipBatchDeleteRequestDTO, completion: @escaping(NetworkResult) -> Void) func postZip(requestBody: PostZipRequestDTO, completion: @escaping (NetworkResult) -> Void) + func postSharedZip(zipId: Int, requestBody: PostZipRequestDTO, completion: @escaping (NetworkResult) -> Void) func deleteZipToHankki(requestBody: DeleteZipToHankkiRequestDTO, completion: @escaping (NetworkResult) -> Void) func postHankkiToZip(requestBody: PostHankkiToZipRequestDTO, completion: @escaping(NetworkResult) -> Void) + func getZipOwnership(zipId: Int, completion: @escaping (NetworkResult) -> Void) } final class ZipAPIService: BaseAPIService, ZipAPIServiceProtocol { - + private let provider = MoyaProvider(plugins: [MoyaPlugin.shared]) func deleteZipToHankki(requestBody: DeleteZipToHankkiRequestDTO, completion: @escaping (NetworkResult) -> Void) { @@ -56,7 +62,7 @@ final class ZipAPIService: BaseAPIService, ZipAPIServiceProtocol { } } - func getZipList(zipId: Int, completion: @escaping (NetworkResult) -> Void) { + func getZipDetail(zipId: Int, completion: @escaping (NetworkResult) -> Void) { provider.request(.getZipDetail(zipId: zipId)) { result in switch result { case .success(let response): @@ -101,6 +107,36 @@ final class ZipAPIService: BaseAPIService, ZipAPIServiceProtocol { } } + func getSharedZipDetail(zipId: Int, completion: @escaping (NetworkResult) -> Void) { + provider.request(.getSharedZipDetail(zipId: zipId)) { result in + switch result { + case .success(let response): + let networkResult: NetworkResult = self.fetchNetworkResult(statusCode: response.statusCode, data: response.data) + completion(networkResult) + case .failure(let error): + if let response = error.response { + let networkResult: NetworkResult = self.fetchNetworkResult(statusCode: response.statusCode, data: response.data) + completion(networkResult) + } + } + } + } + + func postSharedZip(zipId: Int, requestBody: PostZipRequestDTO, completion: @escaping (NetworkResult) -> Void) { + provider.request(.postSharedZip(zipId: zipId, requestBody: requestBody)) { result in + switch result { + case .success(let response): + let networkResult: NetworkResult = self.fetchNetworkResult(statusCode: response.statusCode, data: response.data) + completion(networkResult) + case .failure(let error): + if let response = error.response { + let networkResult: NetworkResult = self.fetchNetworkResult(statusCode: response.statusCode, data: response.data) + completion(networkResult) + } + } + } + } + /// 족보에 식당 추가 func postHankkiToZip(requestBody: PostHankkiToZipRequestDTO, completion: @escaping (NetworkResult) -> Void) { provider.request(.postHankkiToZip(requestBody: requestBody)) { result in @@ -116,4 +152,19 @@ final class ZipAPIService: BaseAPIService, ZipAPIServiceProtocol { } } } + + func getZipOwnership(zipId: Int, completion: @escaping (NetworkResult) -> Void) { + provider.request(.getZipOwnership(zipId: zipId)) { result in + switch result { + case .success(let response): + let networkResult: NetworkResult = self.fetchNetworkResult(statusCode: response.statusCode, data: response.data) + completion(networkResult) + case .failure(let error): + if let response = error.response { + let networkResult: NetworkResult = self.fetchNetworkResult(statusCode: response.statusCode, data: response.data) + completion(networkResult) + } + } + } + } } diff --git a/Hankkijogbo/Hankkijogbo/Network/Zip/ZipTargetType.swift b/Hankkijogbo/Hankkijogbo/Network/Zip/ZipTargetType.swift index d744e500..5511657a 100644 --- a/Hankkijogbo/Hankkijogbo/Network/Zip/ZipTargetType.swift +++ b/Hankkijogbo/Hankkijogbo/Network/Zip/ZipTargetType.swift @@ -12,11 +12,15 @@ import Moya enum ZipTargetType { case getZipList(storedId: Int) case getZipDetail(zipId: Int) + case getSharedZipDetail(zipId: Int) + case postZip(requestBody: PostZipRequestDTO) + case postSharedZip(zipId: Int, requestBody: PostZipRequestDTO) case postZipBatchDelete(requestBody: PostZipBatchDeleteRequestDTO) case postHankkiToZip(requestBody: PostHankkiToZipRequestDTO) case deleteZipToHankki(requestBody: DeleteZipToHankkiRequestDTO) case getMyZipList(id: Int) + case getZipOwnership(zipId: Int) } extension ZipTargetType: BaseTargetType { @@ -45,11 +49,15 @@ extension ZipTargetType: BaseTargetType { switch self { case .getZipList(let storeId): return storeId case .getZipDetail: return .none + case .getSharedZipDetail: return .none case .postZip(let requestBody): return requestBody + case .postSharedZip(zipId: _, requestBody: let requestBody): return requestBody case .postZipBatchDelete(let requestBody): return requestBody case .postHankkiToZip: return .none case .deleteZipToHankki: return .none case .getMyZipList: return .none + case .getZipOwnership: + return .none } } @@ -59,8 +67,12 @@ extension ZipTargetType: BaseTargetType { return utilPath.rawValue case .getZipDetail(let zipId): return utilPath.rawValue + "/\(zipId)" + case .getSharedZipDetail(let zipId): + return utilPath.rawValue + "/shared/\(zipId)" case .postZip: return utilPath.rawValue + case .postSharedZip(zipId: let zipId, requestBody: _): + return utilPath.rawValue + "/shared/\(zipId)" case .postZipBatchDelete: return utilPath.rawValue + "/batch-delete" case .postHankkiToZip(let requestBody): @@ -69,14 +81,16 @@ extension ZipTargetType: BaseTargetType { return utilPath.rawValue + "/\(requestBody.favoriteId)/stores/\(requestBody.storeId)" case .getMyZipList: return utilPath.rawValue + case .getZipOwnership(let zipId): + return utilPath.rawValue + "/shared/\(zipId)/ownership" } } var method: Moya.Method { switch self { - case .getZipList, .getZipDetail, .getMyZipList: + case .getZipList, .getZipDetail, .getMyZipList, .getSharedZipDetail, .getZipOwnership: return .get - case .postZip, .postZipBatchDelete, .postHankkiToZip: + case .postZip, .postSharedZip, .postZipBatchDelete, .postHankkiToZip: return .post case .deleteZipToHankki: return .delete @@ -85,8 +99,8 @@ extension ZipTargetType: BaseTargetType { var loadingViewType: LoadingViewType { switch self { - case .getZipList, .getMyZipList, .getZipDetail: return .fullView - case .postZip, .postZipBatchDelete, .deleteZipToHankki: return .submit + case .getZipList, .getMyZipList, .getZipDetail, .getSharedZipDetail, .getZipOwnership: return .fullView + case .postZip, .postSharedZip, .postZipBatchDelete, .deleteZipToHankki: return .submit default: return .none } } diff --git a/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/CreateZipViewController.swift b/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/CreateZipViewController.swift index 1e341468..2a0b5a4e 100644 --- a/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/CreateZipViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/CreateZipViewController.swift @@ -19,8 +19,10 @@ final class CreateZipViewController: BaseViewController { // MARK: - Properties + private let type: CreateZipViewControllerType private let isBottomSheetOpen: Bool private let storeId: Int? + private let zipId: Int? private let viewModel: CreateZipViewModel = CreateZipViewModel() @@ -39,18 +41,20 @@ final class CreateZipViewController: BaseViewController { } private lazy var submitButton: MainButton = MainButton( - titleText: StringLiterals.CreateZip.submitButton, + titleText: type.submitButtonText, isValid: false, buttonHandler: submitButtonDidTap ) - private let hankkiAccessoryView: HankkiAccessoryView = HankkiAccessoryView(text: StringLiterals.CreateZip.submitButton) + private lazy var hankkiAccessoryView: HankkiAccessoryView = HankkiAccessoryView(text: type.submitButtonText) // MARK: - Life Cycle - init(isBottomSheetOpen: Bool, storeId: Int? = nil) { + init(isBottomSheetOpen: Bool, storeId: Int? = nil, zipId: Int? = nil, type: CreateZipViewControllerType = .myZip) { self.isBottomSheetOpen = isBottomSheetOpen self.storeId = storeId + self.zipId = zipId + self.type = type super.init() } @@ -76,18 +80,19 @@ final class CreateZipViewController: BaseViewController { override func setupStyle() { viewTitleLabel.do { + $0.numberOfLines = 0 $0.attributedText = UILabel.setupAttributedText( for: SuiteStyle.h1, - withText: StringLiterals.CreateZip.viewTitle, + withText: type.viewTitle, color: .gray900 ) } descriptionLabel.do { - $0.numberOfLines = 2 + $0.numberOfLines = 0 $0.attributedText = UILabel.setupAttributedText( for: PretendardStyle.body6, - withText: StringLiterals.CreateZip.viewDescription, + withText: type.viewDescription, color: .gray400 ) } @@ -172,7 +177,16 @@ private extension CreateZipViewController { let data = PostZipRequestDTO(title: title, details: tagList) - viewModel.postZip(data, onConflict: resetTitleTextField, completion: dismissSelf) + switch type { + case .sharedZip: + // 공유된 족보를 내 족보에 추가 + viewModel.postSharedZip(data, zipId: zipId!, onConflict: resetTitleTextField, completion: presentMyZipListViewController) + + case .myZip: + // 내 족보를 새로 만들기 + viewModel.postZip(data, onConflict: resetTitleTextField, completion: dismissSelf) + } + } // textField 값의 유효성 검사 @@ -204,4 +218,25 @@ private extension CreateZipViewController { } } } + + func presentMyZipListViewController() { + DispatchQueue.main.async { + // 족보 만들기를 완료해서, 서버에서 생성이되면 나의 족보 리스트 페이지로 이동한다. + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + if let window = windowScene.windows.first { + let tabBarController = TabBarController() + tabBarController.selectedIndex = 2 + let navigationController = HankkiNavigationController(rootViewController: tabBarController) + + window.rootViewController = navigationController + let viewController = ZipListViewController() + if self.type == .sharedZip { + viewController.showBlackToast(message: StringLiterals.Toast.addSharedZip) + } + navigationController.pushViewController(viewController, animated: false) + + } + } + } + } } diff --git a/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/CreateZipViewControllerType.swift b/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/CreateZipViewControllerType.swift new file mode 100644 index 00000000..8e1c1dfd --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/CreateZipViewControllerType.swift @@ -0,0 +1,36 @@ +// +// CreateZipViewControllerType.swift +// Hankkijogbo +// +// Created by 심서현 on 12/20/24. +// + +import UIKit + +extension CreateZipViewController { + enum CreateZipViewControllerType { + case sharedZip + case myZip + + var viewTitle: String { + switch self { + case .sharedZip: return StringLiterals.SharedZip.viewTitle + case .myZip: return StringLiterals.CreateZip.viewTitle + } + } + + var viewDescription: String { + switch self { + case .sharedZip: return StringLiterals.SharedZip.viewDescription + case .myZip: return StringLiterals.CreateZip.viewDescription + } + } + + var submitButtonText: String { + switch self { + case .sharedZip: return StringLiterals.SharedZip.submitButton + case .myZip: return StringLiterals.CreateZip.submitButton + } + } + } +} diff --git a/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/TagTextField.swift b/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/TagTextField.swift deleted file mode 100644 index dc79f5ac..00000000 --- a/Hankkijogbo/Hankkijogbo/Present/CreateZip/View/TagTextField.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// TagTextField.swift -// Hankkijogbo -// -// Created by 심서현 on 7/11/24. -// - -import UIKit - -class TagTextField: UITextField { - - // 터치 이벤트를 무시하여 드래그 방지 - override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { - - if action == #selector(UIResponderStandardEditActions.paste(_:)) { - return false - } - - return super.canPerformAction(action, withSender: sender) - } -} diff --git a/Hankkijogbo/Hankkijogbo/Present/CreateZip/ViewModel/CreateZipViewModel.swift b/Hankkijogbo/Hankkijogbo/Present/CreateZip/ViewModel/CreateZipViewModel.swift index c04b9bc6..301d7c3a 100644 --- a/Hankkijogbo/Hankkijogbo/Present/CreateZip/ViewModel/CreateZipViewModel.swift +++ b/Hankkijogbo/Hankkijogbo/Present/CreateZip/ViewModel/CreateZipViewModel.swift @@ -18,7 +18,7 @@ extension CreateZipViewModel { result.handleNetworkResult() } } - + func postZip(_ data: PostZipRequestDTO, onConflict: @escaping(() -> Void), completion: @escaping (() -> Void)) { @@ -30,7 +30,27 @@ extension CreateZipViewModel { primaryButtonText: StringLiterals.Alert.CreateZipConflict.primaryButton, primaryButtonHandler: onConflict ) - + + default: + result.handleNetworkResult { _ in + completion() + } + } + } + } + + func postSharedZip(_ data: PostZipRequestDTO, zipId: Int, + onConflict: @escaping(() -> Void), + completion: @escaping (() -> Void)) { + NetworkService.shared.zipService.postSharedZip(zipId: zipId, requestBody: data) { result in + switch result { + case .conflict: + UIApplication.showAlert(titleText: StringLiterals.Alert.CreateZipConflict.title, + subText: StringLiterals.Alert.CreateZipConflict.sub, + primaryButtonText: StringLiterals.Alert.CreateZipConflict.primaryButton, + primaryButtonHandler: onConflict + ) + default: result.handleNetworkResult { _ in completion() diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiDetail/View/HankkiDetailViewController.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiDetail/View/HankkiDetailViewController.swift index 066aa733..1279418e 100644 --- a/Hankkijogbo/Hankkijogbo/Present/HankkiDetail/View/HankkiDetailViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiDetail/View/HankkiDetailViewController.swift @@ -317,7 +317,7 @@ extension HankkiDetailViewController { if let zipId = notification.userInfo?["zipId"] as? Int { self.showBlackToast(message: StringLiterals.Toast.addToMyZipBlack) { [self] in - let hankkiListViewController = HankkiListViewController(.myZip, zipId: zipId) + let hankkiListViewController = ZipDetailViewController(zipId: zipId) navigationController?.pushViewController(hankkiListViewController, animated: true) } } diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/BaseHankkiListViewController.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/BaseHankkiListViewController.swift new file mode 100644 index 00000000..b642286a --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/BaseHankkiListViewController.swift @@ -0,0 +1,140 @@ +// +// ZipHeaderCollectionView.swift +// Hankkijogbo +// +// Created by 심서현 on 7/10/24. +// + +import UIKit + +class BaseHankkiListViewController: BaseViewController, NetworkResultDelegate { + + // MARK: - Properties + + let cellHeight: CGFloat = 102 + + let viewModel: HankkiListViewModel = HankkiListViewModel() + + // MARK: - UI Properties + + lazy var emptyView: EmptyView = EmptyView(text: "") + + let hankkiTableView = UITableView(frame: .zero, style: .grouped) + + // MARK: - Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + + setupRegister() + setupDelegate() + + bindViewModel() + } + + // MARK: - setup UI + + override func setupStyle() { + hankkiTableView.do { + $0.backgroundColor = .hankkiWhite + $0.isEditing = false + $0.bounces = true + $0.alwaysBounceVertical = true + $0.separatorStyle = .none + } + + emptyView.do { + $0.isHidden = true + } + } + + override func setupHierarchy() { + view.addSubviews(hankkiTableView, emptyView) + } + + override func setupLayout() { + hankkiTableView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + emptyView.snp.makeConstraints { + $0.centerY.equalTo(UIScreen.getDeviceHeight() / 2) + $0.centerX.equalToSuperview() + } + } + + // MARK: - method + func bindViewModel() { + viewModel.reloadCollectionView = { [weak self] in + DispatchQueue.main.async { + self?.emptyView.isHidden = (self?.viewModel.hankkiList.count != 0) + self?.hankkiTableView.reloadData() + } + } + } +} + +private extension BaseHankkiListViewController { + + func setupRegister() { + hankkiTableView.register(ZipHeaderTableView.self, forHeaderFooterViewReuseIdentifier: ZipHeaderTableView.className) + hankkiTableView.register(ZipFooterTableView.self, forHeaderFooterViewReuseIdentifier: ZipFooterTableView.className) + hankkiTableView.register(HankkiListTableViewCell.self, forCellReuseIdentifier: HankkiListTableViewCell.className) + } + + func setupDelegate() { + hankkiTableView.delegate = self + hankkiTableView.dataSource = self + viewModel.delegate = self + } + +} + +extension BaseHankkiListViewController: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return viewModel.hankkiList.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: HankkiListTableViewCell.className, + for: indexPath + ) as? HankkiListTableViewCell else { return UITableViewCell() } + + cell.dataBind(viewModel.hankkiList[indexPath.item], + isFinal: viewModel.hankkiList.count - 1 == indexPath.item) + return cell + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return cellHeight + } +} + +extension BaseHankkiListViewController: UITableViewDelegate { + /// 터치시 식당 디테일로 이동 + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + let hankkiDetailViewModel: HankkiDetailViewModel = HankkiDetailViewModel(hankkiId: viewModel.hankkiList[indexPath.item].id) + let hankkiDetailViewController = HankkiDetailViewController(viewModel: hankkiDetailViewModel) + + navigationController?.pushViewController(hankkiDetailViewController, animated: true) + } +} + +extension BaseHankkiListViewController { + + /// Home View로 이동하는 함수 + func navigateToHomeView() { + var rootViewController = self.view.window?.rootViewController + + if let navigationController = rootViewController as? UINavigationController { + rootViewController = navigationController.viewControllers.first + } + if let tabBarController = rootViewController as? UITabBarController { + tabBarController.selectedIndex = 0 + } + + navigationController?.popToRootViewController(animated: true) + } +} diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/HankkiListTableViewCell.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/HankkiListTableViewCell.swift index 7da68695..1e281da9 100644 --- a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/HankkiListTableViewCell.swift +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/HankkiListTableViewCell.swift @@ -186,7 +186,7 @@ final class HankkiListTableViewCell: BaseTableViewCell { } extension HankkiListTableViewCell { - func dataBind(_ data: Model, isFinal: Bool, isLikeButtonDisable: Bool) { + func dataBind(_ data: Model, isFinal: Bool, isLikeButtonDisable: Bool = true) { self.data = data categoryLabel.text = data.category diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipFooterTableView.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipFooterTableView.swift index 29a8ef6c..f8ee90b1 100644 --- a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipFooterTableView.swift +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipFooterTableView.swift @@ -11,7 +11,7 @@ final class ZipFooterTableView: UITableViewHeaderFooterView { // MARK: - Properties - weak var viewController: HankkiListViewController? + weak var viewController: BaseHankkiListViewController? // MARK: - UI Components diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipHeaderTableView.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipHeaderTableView.swift index cc3eabd2..5b6203a2 100644 --- a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipHeaderTableView.swift +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/Cell/ZipHeaderTableView.swift @@ -9,6 +9,7 @@ import UIKit extension ZipHeaderTableView { struct Model { + let id: Int let name: String let title: String let details: [String] @@ -18,8 +19,9 @@ extension ZipHeaderTableView { final class ZipHeaderTableView: UITableViewHeaderFooterView { // MARK: - Properties - + var showAlert: ((String) -> Void)? + var shareZip: (() -> Void)? // MARK: - UI Properties @@ -161,11 +163,13 @@ private extension ZipHeaderTableView { } @objc func shareButtonDidTap() { - UIApplication.showAlert(titleText: StringLiterals.Alert.DevelopShare.title, - subText: StringLiterals.Alert.DevelopShare.sub, - primaryButtonText: StringLiterals.Alert.DevelopShare.primaryButton) + guard let shareZip = shareZip else { return } + shareZip() } - +} + +// MARK: - UI setting을 돕는 함수들 +private extension ZipHeaderTableView { func setupTagStackView(_ tagList: [String]) { tagList.forEach { createTagChipView($0) } } @@ -203,9 +207,11 @@ private extension ZipHeaderTableView { } extension ZipHeaderTableView { - func dataBind(_ data: Model?) { + func dataBind(_ data: Model?, isShareButtonHidden: Bool, shareZip: @escaping ()-> Void) { + self.shareZip = shareZip headerLabel.text = data?.title setupTagStackView(data?.details ?? []) nameLabel.text = data?.name + shareButton.isHidden = isShareButtonHidden } } diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewController.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewController.swift index a9333592..8b0ad0cd 100644 --- a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewController.swift @@ -1,126 +1,46 @@ // -// ZipHeaderCollectionView.swift +// HankkiListViewController.swift // Hankkijogbo // -// Created by 심서현 on 7/10/24. +// Created by 심서현 on 12/20/24. // import UIKit -final class HankkiListViewController: BaseViewController, NetworkResultDelegate { +final class HankkiListViewController: BaseHankkiListViewController { // MARK: - Properties - private var isHeaderSetting: Bool = false - let type: HankkiListViewControllerType - let zipId: Int? + private let type: HankkiListViewControllerType - let viewModel: HankkiListViewModel = HankkiListViewModel() - - // MARK: - UI Properties - - private let hankkiTableView = UITableView(frame: .zero, style: .grouped) - private lazy var emptyView = EmptyView( - text: type.emptyViewLabel, - buttonText: type == .myZip ? StringLiterals.HankkiList.moreButton : nil, - buttonAction: type == .myZip ? self.navigateToHomeView : nil - ) + // MARK: - UI Components // MARK: - Life Cycle - init(_ type: HankkiListViewControllerType, zipId: Int?) { + init(_ type: BaseHankkiListViewController.HankkiListViewControllerType) { self.type = type - self.zipId = zipId super.init() + + self.emptyView = EmptyView(text: type.emptyViewLabel) } - required init?(coder: NSCoder) { + @MainActor required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func viewDidLoad() { - super.viewDidLoad() - - setupRegister() - setupDelegate() - - bindViewModel() - } - override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - setupNavigationBar() - if type == .myZip { - viewModel.getZipDetail(zipId: zipId ?? 0) - } else { - // detail같은, 이전 뷰에서 좋아요가 취소되는 경우를 고려합니다. - if type == .liked && !viewModel.hankkiList.isEmpty { - viewModel.updateMeHankkiList() - return - } - viewModel.getMeHankkiList(type.userTargetType) - } - } - - // MARK: - setup UI - - override func setupStyle() { - hankkiTableView.do { - $0.backgroundColor = .hankkiWhite - $0.isEditing = false - $0.bounces = true - $0.alwaysBounceVertical = true - $0.separatorStyle = .none - } - - emptyView.do { - $0.isHidden = true - } - } - - override func setupHierarchy() { - view.addSubviews(hankkiTableView, emptyView) - } - - override func setupLayout() { - hankkiTableView.snp.makeConstraints { - $0.edges.equalToSuperview() - } - emptyView.snp.makeConstraints { - $0.centerY.equalTo(type.headrViewHeight + (UIScreen.getDeviceHeight() - type.headrViewHeight) / 2) - $0.centerX.equalToSuperview() + if type == .liked && !viewModel.hankkiList.isEmpty { + viewModel.updateMeHankkiList() + return } + viewModel.getMeHankkiList(type.userTargetType) } } private extension HankkiListViewController { - private func bindViewModel() { - viewModel.reloadCollectionView = { [weak self] in - DispatchQueue.main.async { - self?.emptyView.isHidden = (self?.viewModel.hankkiList.count != 0) - self?.hankkiTableView.reloadData() - } - if self?.type == .myZip && !(self?.isHeaderSetting ?? false) { - guard let headerView = self?.hankkiTableView.headerView(forSection: 0) as? ZipHeaderTableView else { return } - headerView.dataBind(self?.viewModel.zipInfo ?? nil) - self?.isHeaderSetting = true - } - } - } - - func setupRegister() { - hankkiTableView.register(ZipHeaderTableView.self, forHeaderFooterViewReuseIdentifier: ZipHeaderTableView.className) - hankkiTableView.register(ZipFooterTableView.self, forHeaderFooterViewReuseIdentifier: ZipFooterTableView.className) - hankkiTableView.register(HankkiListTableViewCell.self, forCellReuseIdentifier: HankkiListTableViewCell.className) - } - - func setupDelegate() { - hankkiTableView.delegate = self - hankkiTableView.dataSource = self - viewModel.delegate = self - } func setupNavigationBar() { let type: HankkiNavigationType @@ -131,114 +51,65 @@ private extension HankkiListViewController { mainTitle: .string(self.type.navigationTitle), rightButton: .string(""), rightButtonAction: {}, - backgroundColor: self.type.navigationColor + backgroundColor: UIColor.hankkiWhite ) if let navigationController = navigationController as? HankkiNavigationController { navigationController.setupNavigationBar(forType: type) } } -} - -extension HankkiListViewController: UITableViewDataSource { - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModel.hankkiList.count - } - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: HankkiListTableViewCell.className, - for: indexPath - ) as? HankkiListTableViewCell else { return UITableViewCell() } - - cell.dataBind(viewModel.hankkiList[indexPath.item], - isFinal: viewModel.hankkiList.count - 1 == indexPath.item, - isLikeButtonDisable: self.type != .liked) - cell.delegate = self - return cell + func deleteLike(_ id: Int) { + viewModel.deleteHankkiHeart(id: id) } - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 102 + func postLike(_ id: Int) { + viewModel.postHankkiHeart(id: id) } +} + +extension HankkiListViewController { - /// 나의 족보 리스트 헤더 세팅 + // 헤더 설정 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - if self.type != .myZip { - return nil - } - - let headerView = tableView.dequeueReusableHeaderFooterView( - withIdentifier: ZipHeaderTableView.className - ) - return headerView + return nil } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return self.type.headrViewHeight + return 0 } - /// 나의 족보 리스트 푸터 세팅 + // 푸터 설정 func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { - if self.type != .myZip || viewModel.hankkiList.count == 0 { - return nil - } - - let footerView = tableView.dequeueReusableHeaderFooterView( - withIdentifier: ZipFooterTableView.className - ) as? ZipFooterTableView ?? ZipFooterTableView(reuseIdentifier: ZipFooterTableView.className) - footerView.viewController = self - return footerView + return nil } func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { - if self.type != .myZip || viewModel.hankkiList.count == 0 { - return 0 - } else { - return 112 - } - } - - func deleteLike(_ id: Int) { - viewModel.deleteHankkiHeart(id: id) + return 0 } - func postLike(_ id: Int) { - viewModel.postHankkiHeart(id: id) - } -} - -extension HankkiListViewController: UITableViewDelegate { - - /// 나의 족보 리스트 - /// 스와이프 해서 셀 지우기 설정 - func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - if self.type != .myZip { - return nil - } - - let deleteAction = UIContextualAction(style: .destructive, title: "삭제") { (_, _, completionHandler) in - self.deleteItem(at: indexPath) - completionHandler(true) - } - deleteAction.backgroundColor = .red500 + // cell data bind + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: HankkiListTableViewCell.className, + for: indexPath + ) as? HankkiListTableViewCell else { return UITableViewCell() } - let configuration = UISwipeActionsConfiguration(actions: [deleteAction]) - configuration.performsFirstActionWithFullSwipe = false - return configuration - } - - /// 나의 족보 리스트 - /// 헤더의 스크롤 막기 - func scrollViewDidScroll(_ scrollView: UIScrollView) { - if scrollView.contentOffset.y < 0 && self.type == .myZip { - scrollView.bounces = false + if type == .liked { + cell.dataBind(viewModel.hankkiList[indexPath.item], + isFinal: viewModel.hankkiList.count - 1 == indexPath.item, + isLikeButtonDisable: false) + cell.delegate = self + + return cell } else { - scrollView.bounces = true + cell.dataBind(viewModel.hankkiList[indexPath.item], + isFinal: viewModel.hankkiList.count - 1 == indexPath.item) + return cell } } - + /// 터치시 식당 디테일로 이동 - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let hankkiId = viewModel.hankkiList[indexPath.item].id pushToDetailWithHankkiNavigation(hankkiId: hankkiId) @@ -274,37 +145,3 @@ extension HankkiListViewController: HankkiListTableViewCellDelegate { } } } - -private extension HankkiListViewController { - /// 셀을 지우는 함수 - func deleteItem(at indexPath: IndexPath) { - let request: DeleteZipToHankkiRequestDTO = DeleteZipToHankkiRequestDTO(favoriteId: zipId ?? 0, storeId: viewModel.hankkiList[indexPath.item].id) - viewModel.deleteZipToHankki(requestBody: request) { - self.removeCellFromCollectionView(indexPath) - } - } - - private func removeCellFromCollectionView(_ indexPath: IndexPath) { - viewModel.hankkiList.remove(at: indexPath.row) - - hankkiTableView.beginUpdates() - hankkiTableView.deleteRows(at: [indexPath], with: .automatic) - hankkiTableView.endUpdates() - } -} - -extension HankkiListViewController { - /// Home View로 이동하는 함수 - func navigateToHomeView() { - var rootViewController = self.view.window?.rootViewController - - if let navigationController = rootViewController as? UINavigationController { - rootViewController = navigationController.viewControllers.first - } - if let tabBarController = rootViewController as? UITabBarController { - tabBarController.selectedIndex = 0 - } - - navigationController?.popToRootViewController(animated: true) - } -} diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewControllerType.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewControllerType.swift index d578341a..3259707d 100644 --- a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewControllerType.swift +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/HankkiListViewControllerType.swift @@ -7,38 +7,13 @@ import UIKit -extension HankkiListViewController { +extension BaseHankkiListViewController { enum HankkiListViewControllerType { - case myZip case reported case liked - var navigationColor: UIColor { - switch self { - case .myZip: - .red500 - case .reported, .liked: - .white - } - } - var headrViewHeight: CGFloat { - switch self { - case .myZip: - UIView.convertByAspectRatioHeight( - UIScreen.getDeviceWidth() - 22 * 2, - width: 329, - height: 231 - ) + 22 - - case .reported, .liked: - 0 - } - } - var navigationTitle: String { switch self { - case .myZip: - StringLiterals.Mypage.myZipList case .reported: StringLiterals.Mypage.HankkiList.reported case .liked: @@ -48,8 +23,6 @@ extension HankkiListViewController { var emptyViewLabel: String { switch self { - case .myZip: - StringLiterals.HankkiList.EmptyView.myZip case .reported: StringLiterals.HankkiList.EmptyView.reported case .liked: @@ -60,11 +33,32 @@ extension HankkiListViewController { var userTargetType: UserTargetType { switch self { case .reported: - .getMeHankkiReportList + .getMeHankkiReportList case .liked: - .getMeHankkiHeartList + .getMeHankkiHeartList + } + } + } + + enum ZipDetailCollectionViewType { + case myZip + case sharedZip + + var navigationTitle: String { + switch self { + case .myZip: + StringLiterals.Mypage.myZipList + case .sharedZip: + StringLiterals.SharedZip.navigation + } + } + + var isAddZipButton: Bool { + switch self { + case .sharedZip: + true default: - .getMeHankkiHeartList + false } } } diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/ZipDetailViewController.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/ZipDetailViewController.swift new file mode 100644 index 00000000..735b7058 --- /dev/null +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/View/ZipDetailViewController.swift @@ -0,0 +1,268 @@ +// +// ZipDetailViewController.swift +// Hankkijogbo +// +// Created by 심서현 on 12/20/24. +// + +import UIKit + +final class ZipDetailViewController: BaseHankkiListViewController { + + // MARK: - Properties + + private let type: ZipDetailCollectionViewType + private let zipId: Int + private var isHeaderSetting: Bool = false + private let headerViewHeight: CGFloat = UIView.convertByAspectRatioHeight(UIScreen.getDeviceWidth() - 22 * 2, + width: 329, + height: 231) + 22 + private let footerViewHeight: CGFloat = 112 + + // MARK: - UI Components + + private lazy var bottomButtonView: BottomButtonView = BottomButtonView(primaryButtonText: StringLiterals.SharedZip.addButton, + primaryButtonHandler: presentAddZipViewController, + isPrimaryButtonAble: true) + + // MARK: - Life Cycle + + init (zipId: Int, type: ZipDetailCollectionViewType = .myZip) { + self.type = type + self.zipId = zipId + super.init() + self.emptyView = EmptyView( + text: StringLiterals.HankkiList.EmptyView.myZip, + buttonText: StringLiterals.HankkiList.moreButton, + buttonAction: self.navigateToHomeView + ) + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + setupNavigationBar() + + getZipDetail() + } + + // MARK: - override + + override func bindViewModel() { + viewModel.reloadCollectionView = { [weak self] in + DispatchQueue.main.async { + self?.emptyView.isHidden = (self?.viewModel.hankkiList.count != 0) + self?.hankkiTableView.reloadData() + } + + self?.bindHeaderView() + } + } + + override func setupHierarchy() { + super.setupHierarchy() + + if type.isAddZipButton { + view.addSubview(bottomButtonView) + } + } + + override func setupLayout() { + super.setupLayout() + emptyView.snp.remakeConstraints { + $0.centerY.equalTo(headerViewHeight + (UIScreen.getDeviceHeight() - headerViewHeight) / 2) + $0.centerX.equalToSuperview() + } + + if type.isAddZipButton { + bottomButtonView.snp.makeConstraints { + $0.leading.trailing.equalTo(view.safeAreaLayoutGuide) + $0.bottom.equalToSuperview() + $0.height.equalTo(154) + } + } + } +} + +private extension ZipDetailViewController { + + /// 족보 정보 가져오기 + func getZipDetail() { + switch type { + case .myZip: + viewModel.getZipDetail(zipId: zipId) + case .sharedZip: + viewModel.getSharedZipDetail(zipId: zipId) + checkLogin() + } + } + + func bindHeaderView() { + // header 가 초기화 되지 않은 경우 진행 + if !(isHeaderSetting) { + + guard let headerView = hankkiTableView.headerView(forSection: 0) as? ZipHeaderTableView else { return } + + headerView.dataBind(viewModel.zipInfo ?? nil, + isShareButtonHidden: type == .sharedZip, + shareZip: shareZip) + + isHeaderSetting = true + } + } + + /// 족보 공유 + func shareZip() { + viewModel.shareZip { + UIApplication.showAlert(titleText: StringLiterals.Alert.NeedOneMoreHankkiToShare.title, + secondaryButtonText: StringLiterals.Alert.NeedOneMoreHankkiToShare.secondaryButton, + primaryButtonText: StringLiterals.Alert.NeedOneMoreHankkiToShare.primaryButton, + primaryButtonHandler: presentHomeView) + return + } + } + + func presentHomeView() { + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + if let window = windowScene.windows.first { + let navigationController = HankkiNavigationController(rootViewController: TabBarController()) + window.rootViewController = navigationController + } + } + } + + func setupNavigationBar() { + let type: HankkiNavigationType + + type = HankkiNavigationType( + hasBackButton: true, + hasRightButton: false, + mainTitle: .string(self.type.navigationTitle), + rightButton: .string(""), + rightButtonAction: {}, + backgroundColor: UIColor.red500 + ) + + if let navigationController = navigationController as? HankkiNavigationController { + navigationController.setupNavigationBar(forType: type) + } + } + + /// 셀을 지우는 함수 + func deleteItem(at indexPath: IndexPath) { + let request: DeleteZipToHankkiRequestDTO = DeleteZipToHankkiRequestDTO(favoriteId: zipId, storeId: viewModel.hankkiList[indexPath.item].id) + viewModel.deleteZipToHankki(requestBody: request) { + self.removeCellFromCollectionView(indexPath) + } + } + + func removeCellFromCollectionView(_ indexPath: IndexPath) { + viewModel.hankkiList.remove(at: indexPath.row) + + hankkiTableView.beginUpdates() + hankkiTableView.deleteRows(at: [indexPath], with: .automatic) + hankkiTableView.endUpdates() + } + + // 공유 받은 족보 -> 족보 저장 뷰 + func presentAddZipViewController() { + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootViewController = windowScene.windows.first?.rootViewController as? UINavigationController { + let addZipViewController = CreateZipViewController(isBottomSheetOpen: false, zipId: zipId, type: .sharedZip) + rootViewController.pushViewController(addZipViewController, animated: true) + } + } + + /// 로그인 여부 확인 + /// 비로그인 회원인 경우, 로그인 필요 경고를 띄운뒤 로그인 뷰로 이동한다 + func checkLogin() { + if !UserDefaults.standard.isLogin { + self.showAlert(titleText: StringLiterals.Alert.NeedLoginToSharedZip.title, + primaryButtonText: StringLiterals.Alert.NeedLoginToSharedZip.primaryButton, + primaryButtonHandler: UIApplication.resetApp) + } + } +} + +// MARK: - Delegate + +extension ZipDetailViewController { + + /// 헤더 설정 + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView = tableView.dequeueReusableHeaderFooterView( + withIdentifier: ZipHeaderTableView.className + ) + return headerView + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return headerViewHeight + } + + /// 푸터 설정 + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + if type == .sharedZip { + return nil + } + + if viewModel.hankkiList.isEmpty { + return nil + } + + let footerView = tableView.dequeueReusableHeaderFooterView( + withIdentifier: ZipFooterTableView.className + ) as? ZipFooterTableView ?? ZipFooterTableView(reuseIdentifier: ZipFooterTableView.className) + footerView.viewController = self + return footerView + } + + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + if type == .sharedZip { + return 100 + } + + if viewModel.hankkiList.isEmpty { + return 0 + } + + return footerViewHeight + } + + /// 스와이프 해서 셀 지우기 설정 + func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { + if self.type != .myZip { + return nil + } + + let deleteAction = UIContextualAction(style: .destructive, title: "삭제") { (_, _, completionHandler) in + self.deleteItem(at: indexPath) + completionHandler(true) + } + deleteAction.backgroundColor = .red500 + + let configuration = UISwipeActionsConfiguration(actions: [deleteAction]) + configuration.performsFirstActionWithFullSwipe = false + return configuration + } + + /// 헤더의 스크롤 막기 + func scrollViewDidScroll(_ scrollView: UIScrollView) { + if scrollView.contentOffset.y < 0 { + scrollView.bounces = false + } else { + scrollView.bounces = true + } + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if type == .myZip { + super.tableView(tableView, didSelectRowAt: indexPath) + } else { + return + } + } +} diff --git a/Hankkijogbo/Hankkijogbo/Present/HankkiList/ViewModel/HankkiListViewModel.swift b/Hankkijogbo/Hankkijogbo/Present/HankkiList/ViewModel/HankkiListViewModel.swift index c1644192..12192e3c 100644 --- a/Hankkijogbo/Hankkijogbo/Present/HankkiList/ViewModel/HankkiListViewModel.swift +++ b/Hankkijogbo/Hankkijogbo/Present/HankkiList/ViewModel/HankkiListViewModel.swift @@ -8,6 +8,10 @@ import Foundation import UIKit +import KakaoSDKCommon +import KakaoSDKShare +import KakaoSDKTemplate + final class HankkiListViewModel { weak var delegate: NetworkResultDelegate? @@ -25,10 +29,32 @@ final class HankkiListViewModel { extension HankkiListViewModel { func getZipDetail(zipId: Int) { - NetworkService.shared.zipService.getZipList(zipId: zipId) { result in + NetworkService.shared.zipService.getZipDetail(zipId: zipId) { result in + + result.handleNetworkResult(delegate: self.delegate) { response in + self.zipInfo = ZipHeaderTableView.Model(id: zipId, + name: UserDefaults.standard.getNickname(), + title: response.data.title, + details: response.data.details) + + self.hankkiList = response.data.stores.map { + return HankkiListTableViewCell.Model(id: $0.id, + name: $0.name, + imageURL: $0.imageUrl ?? "", + category: $0.category, + lowestPrice: $0.lowestPrice, + heartCount: $0.heartCount) + } + } + } + } + + func getSharedZipDetail(zipId: Int) { + NetworkService.shared.zipService.getSharedZipDetail(zipId: zipId) { result in result.handleNetworkResult(delegate: self.delegate) { response in - self.zipInfo = ZipHeaderTableView.Model(name: UserDefaults.standard.getNickname(), + self.zipInfo = ZipHeaderTableView.Model(id: zipId, + name: response.data.nickname, title: response.data.title, details: response.data.details) @@ -100,6 +126,45 @@ extension HankkiListViewModel { } } } + + func shareZip(handelHankkiListIsEmpty: () -> Void) { + + if hankkiList.isEmpty { + handelHankkiListIsEmpty() + return + } + + let templeteID: Int64 = Int64(StringLiterals.Kakao.zipShareTemplete) + + let imageURL: String = hankkiList[0].imageURL.isEmpty ? StringLiterals.SharedZip.zipShareDefaultImageURL : hankkiList[0].imageURL + + let templetArgs: [String: String] = ["IMAGE_URL": imageURL, + "FAVORITE_ID": String(zipInfo?.id ?? 0), + "NAME": hankkiList[0].name, + "SENDER": zipInfo?.name ?? ""] + + // 카카오톡이 있는지 확인합니다. + if ShareApi.isKakaoTalkSharingAvailable() { + ShareApi.shared.shareCustom(templateId: templeteID, templateArgs: templetArgs) { sharingResult, error in + if let error = error { + print("error : \(error)") + } else { + print("sharing is success") + guard let sharingResult else { return } + UIApplication.shared.open(sharingResult.url, options: [:], completionHandler: nil) + } + } + } else { + let url = StringLiterals.Kakao.storeUrl + if let url = URL(string: url), UIApplication.shared.canOpenURL(url) { + if #available(iOS 10.0, *) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } else { + UIApplication.shared.openURL(url) + } + } + } + } } private extension HankkiListViewModel { @@ -125,7 +190,7 @@ private extension HankkiListViewModel { } return store } - + self.hankkiList = updatedHankkiList } } diff --git a/Hankkijogbo/Hankkijogbo/Present/Home/View/Extension/FilteringButtonFunc.swift b/Hankkijogbo/Hankkijogbo/Present/Home/View/Extension/FilteringButtonFunc.swift index 4763185c..748ca92f 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Home/View/Extension/FilteringButtonFunc.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Home/View/Extension/FilteringButtonFunc.swift @@ -278,6 +278,12 @@ extension HomeViewController { } toggleCollectionView() } + + @objc func floatingButtonDidTap() { + let filteringBottomSheet = HankkiNavigationController(rootViewController: FilteringBottomSheetViewController()) + filteringBottomSheet.modalPresentationStyle = .overFullScreen + self.present(filteringBottomSheet, animated: true, completion: nil) + } } extension HomeViewController { diff --git a/Hankkijogbo/Hankkijogbo/Present/Home/View/FilteringBottomSheetViewController.swift b/Hankkijogbo/Hankkijogbo/Present/Home/View/FilteringBottomSheetViewController.swift index 0d044c36..030a230a 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Home/View/FilteringBottomSheetViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Home/View/FilteringBottomSheetViewController.swift @@ -18,8 +18,14 @@ final class FilteringBottomSheetViewController: BaseViewController { private var priceData: [GetPriceFilterData] = [] private var sortData: [GetSortOptionFilterData] = [] + private var selectedPriceValue: String? + private var selectedSortValue: String? + // MARK: - Components + private let dimmedView: UIView = UIView() + private let containerView: UIView = UIView() + private let priceTitleLabel: UILabel = UILabel() private let entireChipButton: UIButton = UIButton() private let less6000ChipButton: UIButton = UIButton() @@ -33,23 +39,38 @@ final class FilteringBottomSheetViewController: BaseViewController { private let sortChipStackView: UIStackView = UIStackView() private let applyButton: UIButton = UIButton() + private let divideLineView: CustomLineView = CustomLineView() override func viewDidLoad() { super.viewDidLoad() - + + setupAddTarget() bindViewModels() } override func setupHierarchy() { - view.addSubviews(priceTitleLabel, priceChipStackView, sortTitleLabel, sortChipStackView, applyButton) + view.addSubviews(dimmedView, containerView) - priceChipStackView.addArrangedSubviews(entireChipButton, less6000ChipButton, more6000ChipButton) + containerView.addSubviews( + priceTitleLabel, + priceChipStackView, + sortTitleLabel, + sortChipStackView, + divideLineView, + applyButton + ) + priceChipStackView.addArrangedSubviews(entireChipButton, less6000ChipButton, more6000ChipButton) sortChipStackView.addArrangedSubviews(latestChipButton, lowestChipButton, recommendChipButton) } override func setupLayout() { - self.view.snp.makeConstraints { + dimmedView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + containerView.snp.makeConstraints { + $0.bottom.width.equalToSuperview() $0.height.equalTo(defaultHeight) } @@ -79,6 +100,11 @@ final class FilteringBottomSheetViewController: BaseViewController { $0.width.equalTo(UIScreen.main.bounds.width) } + divideLineView.snp.makeConstraints { + $0.bottom.equalTo(applyButton.snp.top) + $0.width.equalToSuperview() + } + [entireChipButton, less6000ChipButton, more6000ChipButton, latestChipButton, lowestChipButton, recommendChipButton].forEach { $0.snp.makeConstraints { $0.height.equalTo(30) @@ -87,6 +113,21 @@ final class FilteringBottomSheetViewController: BaseViewController { } override func setupStyle() { + view.do { + $0.backgroundColor = .clear + } + + dimmedView.do { + $0.backgroundColor = .black.withAlphaComponent(0.67) + } + + containerView.do { + $0.isUserInteractionEnabled = true + $0.backgroundColor = .hankkiWhite + $0.layer.cornerRadius = 18 + $0.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] + } + [priceTitleLabel, sortTitleLabel].enumerated().forEach { index, label in label.do { $0.font = .setupPretendardStyle(of: .body4) @@ -117,13 +158,13 @@ final class FilteringBottomSheetViewController: BaseViewController { } } - private extension FilteringBottomSheetViewController { func defaultButtonStyle(button: UIButton) { button.do { - $0.makeRoundBorder(cornerRadius: 16, borderWidth: 1, borderColor: .gray300) + $0.makeRoundBorder(cornerRadius: 15, borderWidth: 1, borderColor: .gray300) $0.titleLabel?.font = .setupPretendardStyle(of: .caption1) $0.setTitleColor(.gray600, for: .normal) + $0.backgroundColor = .hankkiWhite $0.contentEdgeInsets = UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12) $0.sizeToFit() } @@ -131,7 +172,7 @@ private extension FilteringBottomSheetViewController { func selectedButtonStyle(button: UIButton) { button.do { - $0.makeRoundBorder(cornerRadius: 16, borderWidth: 1, borderColor: .red500) + $0.makeRoundBorder(cornerRadius: 15, borderWidth: 1, borderColor: .red500) $0.titleLabel?.font = .setupPretendardStyle(of: .caption1) $0.setTitleColor(.red500, for: .selected) $0.backgroundColor = .red100 @@ -139,9 +180,72 @@ private extension FilteringBottomSheetViewController { $0.sizeToFit() } } + + // buttonStackView 당 하나의 button만 눌리도록 제한하는 메소드 + func setButtonStateLimit(for selectedButton: UIButton, in stackView: UIStackView) { + let buttons = stackView.arrangedSubviews.compactMap { $0 as? UIButton } + for button in buttons { + if button == selectedButton { + button.isSelected = true + selectedButtonStyle(button: button) + } else { + button.isSelected = false + defaultButtonStyle(button: button) + } + } + } + + @objc func dimmedViewDidTap() { + containerView.snp.remakeConstraints { + $0.bottom.width.equalToSuperview() + $0.height.equalTo(0) + } + UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: { + self.dimmedView.alpha = 0.0 + self.view.layoutIfNeeded() + }, completion: { _ in + self.dismiss(animated: false, completion: nil) + }) + } + + @objc func filteringChipButtonDidTap(_ sender: UIButton) { + if priceChipStackView.arrangedSubviews.contains(sender) { + if let priceValue = sender.titleLabel?.text { selectedPriceValue = priceValue } + setButtonStateLimit(for: sender, in: priceChipStackView) + } else if sortChipStackView.arrangedSubviews.contains(sender) { + if let sortValue = sender.titleLabel?.text { selectedSortValue = sortValue } + setButtonStateLimit(for: sender, in: sortChipStackView) + } + } + + @objc func applyButtonDidTap() { + if let selectedPriceValue = selectedPriceValue, + let selectedPriceData = priceData.first(where: { $0.name == selectedPriceValue }) { + viewModel.priceCategory = selectedPriceData.tag + } else { viewModel.priceCategory = nil } + + + if let selectedSortValue = selectedSortValue, + let selectedSortData = sortData.first(where: { $0.name == selectedSortValue }) { + viewModel.sortOption = selectedSortData.tag + } else { viewModel.sortOption = nil } + +// viewModel.updateHankkiList() + dimmedViewDidTap() + } } private extension FilteringBottomSheetViewController { + func setupAddTarget() { + dimmedView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dimmedViewDidTap))) + + [entireChipButton, less6000ChipButton, more6000ChipButton, latestChipButton, lowestChipButton, recommendChipButton].forEach { button in + button.addTarget(self, action: #selector(filteringChipButtonDidTap(_:)), for: .touchUpInside) + } + + applyButton.addTarget(self, action: #selector(applyButtonDidTap), for: .touchUpInside) + } + func bindViewModels() { viewModel.getPriceCategoryFilterAPI { [weak self] success in guard let self = self else { return } diff --git a/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeView.swift b/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeView.swift index c5aecdb6..10fb7384 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeView.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeView.swift @@ -73,7 +73,7 @@ final class HomeView: BaseView { } bottomSheetView.snp.makeConstraints { - $0.bottom.equalToSuperview().offset(UIScreen.getDeviceHeight() * 0.4) + $0.bottom.equalToSuperview().offset(UIScreen.getDeviceHeight() * 0.5) } gradient.snp.makeConstraints { diff --git a/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeViewController.swift b/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeViewController.swift index bc8f2f73..d80b8be8 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Home/View/HomeViewController.swift @@ -177,6 +177,7 @@ extension HomeViewController { rootView.priceButton.addTarget(self, action: #selector(priceButtonDidTap), for: .touchUpInside) rootView.sortButton.addTarget(self, action: #selector(sortButtonDidTap), for: .touchUpInside) rootView.targetButton.addTarget(self, action: #selector(targetButtonDidTap), for: .touchUpInside) + rootView.filteringFloatingButton.addTarget(self, action: #selector(floatingButtonDidTap), for: .touchUpInside) } func presentUniversity() { @@ -209,7 +210,7 @@ extension HomeViewController { if let zipId = notification.userInfo?["zipId"] as? Int { self.showBlackToast(message: StringLiterals.Toast.addToMyZipBlack) { [self] in - let hankkiListViewController = HankkiListViewController(.myZip, zipId: zipId) + let hankkiListViewController = ZipDetailViewController(zipId: zipId) navigationController?.pushViewController(hankkiListViewController, animated: true) } } diff --git a/Hankkijogbo/Hankkijogbo/Present/Home/View/TotalListBottomSheetView.swift b/Hankkijogbo/Hankkijogbo/Present/Home/View/TotalListBottomSheetView.swift index 9b0da461..b17dcdf0 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Home/View/TotalListBottomSheetView.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Home/View/TotalListBottomSheetView.swift @@ -17,7 +17,7 @@ final class TotalListBottomSheetView: BaseView { var isExpanded: Bool = false var isBottomSheetUp: Bool = false - var defaultHeight: CGFloat = UIScreen.getDeviceHeight() * 0.4 + var defaultHeight: CGFloat = UIScreen.getDeviceHeight() * 0.3 var expandedHeight: CGFloat = UIScreen.getDeviceHeight() * 0.8 var data: [GetHankkiListData] = [] @@ -177,7 +177,7 @@ extension TotalListBottomSheetView { delay: 0, options: .curveEaseOut, animations: { - self.transform = .init(translationX: 0, y: -(UIScreen.getDeviceHeight() * 0.4)) + self.transform = .init(translationX: 0, y: -(UIScreen.getDeviceHeight() * 0.3)) }, completion: { [weak self] _ in guard let self = self else { return } self.isBottomSheetUp = true @@ -210,7 +210,7 @@ extension TotalListBottomSheetView { delay: 0, options: .curveEaseOut, animations: { - self.transform = .init(translationX: 0, y: (UIScreen.getDeviceHeight() * 0.4)) + self.transform = .init(translationX: 0, y: (UIScreen.getDeviceHeight() * 0.3)) }, completion: { _ in self.isBottomSheetUp = false }) diff --git a/Hankkijogbo/Hankkijogbo/Present/MyZipList/View/MyZipListBottomSheetViewController.swift b/Hankkijogbo/Hankkijogbo/Present/MyZipList/View/MyZipListBottomSheetViewController.swift index c30bc0c7..a0910ee2 100644 --- a/Hankkijogbo/Hankkijogbo/Present/MyZipList/View/MyZipListBottomSheetViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/MyZipList/View/MyZipListBottomSheetViewController.swift @@ -316,7 +316,7 @@ private extension MyZipListBottomSheetViewController { // 족보에 식당 추가를 성공햇을 경우 // black toast message 를 띄웁니다 UIApplication.showBlackToast(message: StringLiterals.Toast.addToMyZipBlack) { - let zipListViewController = HankkiListViewController(.myZip, zipId: zipId) + let zipListViewController = ZipDetailViewController(zipId: zipId) if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let rootViewController = windowScene.windows.first?.rootViewController as? UINavigationController { rootViewController.pushViewController(zipListViewController, animated: true) diff --git a/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageCollectionViewCellEnum.swift b/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageCollectionViewCellEnum.swift index c411e7b9..dc7a86e0 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageCollectionViewCellEnum.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageCollectionViewCellEnum.swift @@ -43,11 +43,11 @@ extension MypageViewController { case .option: switch itemIndex { case 0: - if let url = URL(string: StringLiterals.ExternalLink.OneonOne) { + if let url = URL(string: StringLiterals.ExternalLink.oneOnOne) { UIApplication.shared.open(url, options: [:]) } case 1: - if let url = URL(string: StringLiterals.ExternalLink.Terms) { + if let url = URL(string: StringLiterals.ExternalLink.terms) { UIApplication.shared.open(url, options: [:]) } case 2: diff --git a/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageViewController.swift b/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageViewController.swift index ff380a37..a4ca6bb8 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Mypage/View/MypageViewController.swift @@ -24,9 +24,9 @@ final class MypageViewController: BaseViewController { ] private let optionList: [MypageOptionCollectionViewCell.Model] = [ - MypageOptionCollectionViewCell.Model(title: StringLiterals.Mypage.Option.OneonOne), - MypageOptionCollectionViewCell.Model(title: StringLiterals.Mypage.Option.Terms), - MypageOptionCollectionViewCell.Model(title: StringLiterals.Mypage.Option.Logout) + MypageOptionCollectionViewCell.Model(title: StringLiterals.Mypage.Option.oneOnOne), + MypageOptionCollectionViewCell.Model(title: StringLiterals.Mypage.Option.terms), + MypageOptionCollectionViewCell.Model(title: StringLiterals.Mypage.Option.logout) ] // MARK: - UI Properties @@ -70,7 +70,7 @@ final class MypageViewController: BaseViewController { extension MypageViewController { func navigateToHankkiListViewController(_ type: HankkiListViewController.HankkiListViewControllerType) { - let hankkiListViewController = HankkiListViewController(type, zipId: nil) + let hankkiListViewController = HankkiListViewController(type) navigationController?.pushViewController(hankkiListViewController, animated: true) } } diff --git a/Hankkijogbo/Hankkijogbo/Present/Report/Complete/ReportCompleteViewController.swift b/Hankkijogbo/Hankkijogbo/Present/Report/Complete/ReportCompleteViewController.swift index 1fef78ab..99349ab7 100644 --- a/Hankkijogbo/Hankkijogbo/Present/Report/Complete/ReportCompleteViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/Report/Complete/ReportCompleteViewController.swift @@ -251,7 +251,7 @@ private extension ReportCompleteViewController { if let zipId = notification.userInfo?["zipId"] as? Int { self.showWhiteToast(message: StringLiterals.Toast.addToMyZipWhite) { [self] in - let hankkiListViewController = HankkiListViewController(.myZip, zipId: zipId) + let hankkiListViewController = ZipDetailViewController(zipId: zipId) navigationController?.pushViewController(hankkiListViewController, animated: true) } } diff --git a/Hankkijogbo/Hankkijogbo/Present/ZipList/View/ZipListViewController.swift b/Hankkijogbo/Hankkijogbo/Present/ZipList/View/ZipListViewController.swift index ec04c238..36d8d26b 100644 --- a/Hankkijogbo/Hankkijogbo/Present/ZipList/View/ZipListViewController.swift +++ b/Hankkijogbo/Hankkijogbo/Present/ZipList/View/ZipListViewController.swift @@ -130,7 +130,7 @@ private extension ZipListViewController { } func navigateToHankkiListViewController(zipId: Int) { - let hankkiListViewController = HankkiListViewController(.myZip, zipId: zipId) + let hankkiListViewController = ZipDetailViewController(zipId: zipId) navigationController?.pushViewController(hankkiListViewController, animated: true) } diff --git a/Hankkijogbo/Hankkijogbo/Present/ZipList/ViewModel/ZipListViewModel.swift b/Hankkijogbo/Hankkijogbo/Present/ZipList/ViewModel/ZipListViewModel.swift index 63eb543d..60ac704b 100644 --- a/Hankkijogbo/Hankkijogbo/Present/ZipList/ViewModel/ZipListViewModel.swift +++ b/Hankkijogbo/Hankkijogbo/Present/ZipList/ViewModel/ZipListViewModel.swift @@ -6,6 +6,7 @@ // import Foundation +import UIKit final class ZipListViewModel {