diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index 52ff1bfa..51394f90 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ A3BC2F2B2962C3D500198261 /* GoalRewardInfoVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BC2F2A2962C3D500198261 /* GoalRewardInfoVC.swift */; }; A3BC2F2D2962C3F200198261 /* ActivityRecordInfoVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BC2F2C2962C3F200198261 /* ActivityRecordInfoVC.swift */; }; A3BC2F2F2962C40A00198261 /* UploadedCourseInfoVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BC2F2E2962C40A00198261 /* UploadedCourseInfoVC.swift */; }; + A3BC2F322962E0DB00198261 /* GoalRewardInfoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BC2F312962E0DB00198261 /* GoalRewardInfoModel.swift */; }; + A3BC2F34296303A600198261 /* GoalRewardInfoCVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BC2F33296303A600198261 /* GoalRewardInfoCVC.swift */; }; CE17F02D2961BBA100E1DED0 /* ColorLiterals.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE17F02C2961BBA100E1DED0 /* ColorLiterals.swift */; }; CE17F0332961BEF800E1DED0 /* Pretendard-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = CE17F02F2961BEF800E1DED0 /* Pretendard-Medium.otf */; }; CE17F0342961BEF800E1DED0 /* Pretendard-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = CE17F0302961BEF800E1DED0 /* Pretendard-Bold.otf */; }; @@ -87,6 +89,8 @@ A3BC2F2A2962C3D500198261 /* GoalRewardInfoVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoalRewardInfoVC.swift; sourceTree = ""; }; A3BC2F2C2962C3F200198261 /* ActivityRecordInfoVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityRecordInfoVC.swift; sourceTree = ""; }; A3BC2F2E2962C40A00198261 /* UploadedCourseInfoVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadedCourseInfoVC.swift; sourceTree = ""; }; + A3BC2F312962E0DB00198261 /* GoalRewardInfoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoalRewardInfoModel.swift; sourceTree = ""; }; + A3BC2F33296303A600198261 /* GoalRewardInfoCVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoalRewardInfoCVC.swift; sourceTree = ""; }; CE17F02C2961BBA100E1DED0 /* ColorLiterals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorLiterals.swift; sourceTree = ""; }; CE17F02F2961BEF800E1DED0 /* Pretendard-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Medium.otf"; sourceTree = ""; }; CE17F0302961BEF800E1DED0 /* Pretendard-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Bold.otf"; sourceTree = ""; }; @@ -202,6 +206,7 @@ A3BC2F292962C39F00198261 /* InfoVC */ = { isa = PBXGroup; children = ( + A3BC2F302962E08400198261 /* GoalRewardInfoCollectionView */, A3BC2F2A2962C3D500198261 /* GoalRewardInfoVC.swift */, A3BC2F2C2962C3F200198261 /* ActivityRecordInfoVC.swift */, A3BC2F2E2962C40A00198261 /* UploadedCourseInfoVC.swift */, @@ -209,6 +214,15 @@ path = InfoVC; sourceTree = ""; }; + A3BC2F302962E08400198261 /* GoalRewardInfoCollectionView */ = { + isa = PBXGroup; + children = ( + A3BC2F312962E0DB00198261 /* GoalRewardInfoModel.swift */, + A3BC2F33296303A600198261 /* GoalRewardInfoCVC.swift */, + ); + path = GoalRewardInfoCollectionView; + sourceTree = ""; + }; CE17F02E2961BEAE00E1DED0 /* Fonts */ = { isa = PBXGroup; children = ( @@ -831,6 +845,7 @@ CE665612295D92E400C64E12 /* UserDefaultWrapper.swift in Sources */, CE665610295D92C200C64E12 /* setTextLineHeight.swift in Sources */, CE6655E2295D87EB00C64E12 /* UIImage+.swift in Sources */, + A3BC2F322962E0DB00198261 /* GoalRewardInfoModel.swift in Sources */, CEC2A68C2962AE1B00160BF7 /* RNStartMarker.swift in Sources */, CE5875A4296015D2005D967E /* Encodable+.swift in Sources */, CEEC6B4B2961D89700D00E1E /* CustomNavigationBar.swift in Sources */, @@ -838,6 +853,7 @@ CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */, CE6655D2295D862A00C64E12 /* Publisher+Driver.swift in Sources */, CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, + A3BC2F34296303A600198261 /* GoalRewardInfoCVC.swift in Sources */, CEB8416E2962C45300BF8080 /* LocationSearchResultTVC.swift in Sources */, CE6655CA295D84DD00C64E12 /* UserDefaultKeyList.swift in Sources */, CE6655F2295D894D00C64E12 /* UIView+.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoCollectionView/GoalRewardInfoCVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoCollectionView/GoalRewardInfoCVC.swift new file mode 100644 index 00000000..6fbe6d0e --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoCollectionView/GoalRewardInfoCVC.swift @@ -0,0 +1,68 @@ +// +// GoalRewardInfoCVC.swift +// Runnect-iOS +// +// Created by 몽이 누나 on 2023/01/02. +// + +import UIKit +import SnapKit +import Then + +// MARK: - GoalRewardInfoCVC + +final class GoalRewardInfoCVC: UICollectionViewCell { + + // MARK: - UI Components + + private let containerView = UIView() + private let stampImageView = UIImageView() + private let stampStandardLabel = UILabel().then { + $0.textColor = .g1 + $0.font = .b7 + } + + // MARK: - Life Cycles + + override init(frame: CGRect) { + super.init(frame: frame) + setLayout() + } + + required init(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension GoalRewardInfoCVC { + + // MARK: - Layout Helpers + + private func setLayout() { + contentView.addSubviews(stampImageView, stampStandardLabel) + + contentView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.centerX.equalToSuperview() + make.leading.equalToSuperview() + make.height.equalTo(112) + } + + stampImageView.snp.makeConstraints { make in + make.top.leading.trailing.equalToSuperview() + make.width.equalTo(90) + } + + stampStandardLabel.snp.makeConstraints { make in + make.top.equalTo(stampImageView.snp.bottom).offset(8) + make.centerX.equalToSuperview() + } + } + + // MARK: - General Helpers + + func dataBind(model: GoalRewardInfoModel) { + stampImageView.image = model.stampImg + stampStandardLabel.text = model.stampStandard + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoCollectionView/GoalRewardInfoModel.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoCollectionView/GoalRewardInfoModel.swift new file mode 100644 index 00000000..61202843 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoCollectionView/GoalRewardInfoModel.swift @@ -0,0 +1,13 @@ +// +// GoalRewardInfoModel.swift +// Runnect-iOS +// +// Created by 몽이 누나 on 2023/01/02. +// + +import UIKit + +struct GoalRewardInfoModel { + let stampImg: UIImage + let stampStandard: String +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift index 6922d4dc..77cc6cea 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift @@ -6,18 +6,163 @@ // import UIKit +import SnapKit +import Then final class GoalRewardInfoVC: UIViewController { - + + // MARK: - Variables + + var stampList: [GoalRewardInfoModel] = [ + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampC1, stampStandard: "그리기 스타터"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampC2, stampStandard: "그리기 중수"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampC3, stampStandard: "그리기 마스터"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampS1, stampStandard: "스크랩 베이비"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampS2, stampStandard: "스크랩 어린이"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampS3, stampStandard: "스크랩 어른이"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampP1, stampStandard: "새싹 업로더"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampP2, stampStandard: "중수 업로더"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampP3, stampStandard: "인플루언서"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampR1, stampStandard: "달리기 유망주"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampR2, stampStandard: "아마추어 선수"), + GoalRewardInfoModel(stampImg: ImageLiterals.imgStampR2, stampStandard: "마라톤 선수") + ] + + // MARK: - Constants + + final let stampInset: UIEdgeInsets = UIEdgeInsets(top: 32, left: 34, bottom: 10, right: 34) + final let stampLineSpacing: CGFloat = 20 + final let stampItemSpacing: CGFloat = 26 + final let stampCellHeight: CGFloat = 112 + + // MARK: - UI Components + + private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton).setTitle("목표 보상") + private let stampTopView = UIView() + + private let stampImage = UIImageView().then { + $0.image = ImageLiterals.imgStamp + } + + private let stampExcourageLabel = UILabel().then { + $0.text = "다양한 코스를 달리며 러닝 스탬프를 모아봐요" + $0.textColor = .g2 + $0.font = .b4 + } + + private lazy var stampCollectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.isScrollEnabled = true + collectionView.showsVerticalScrollIndicator = false + collectionView.delegate = self + collectionView.dataSource = self + + return collectionView + }() + + // MARK: - View Life Cycle + override func viewDidLoad() { super.viewDidLoad() + setNavigationBar() setUI() - // Do any additional setup after loading the view. + setLayout() + register() } } extension GoalRewardInfoVC { + + // MARK: - Layout Helpers + + private func setNavigationBar() { + view.addSubview(navibar) + + navibar.snp.makeConstraints { make in + make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.height.equalTo(48) + } + } + private func setUI() { view.backgroundColor = .w1 + stampCollectionView.backgroundColor = .m3 + } + + private func setLayout() { + view.addSubviews(stampTopView, stampCollectionView) + + stampTopView.snp.makeConstraints { make in + make.top.equalTo(navibar.snp.bottom) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.height.equalTo(235) + } + + stampTopView.addSubviews(stampImage, stampExcourageLabel) + + stampImage.snp.makeConstraints { make in + make.top.equalToSuperview() + make.centerX.equalToSuperview() + make.width.equalTo(181) + make.height.equalTo(167) + } + + stampExcourageLabel.snp.makeConstraints { make in + make.top.equalTo(stampImage.snp.bottom).offset(16) + make.centerX.equalToSuperview() + } + + stampCollectionView.snp.makeConstraints { make in + make.top.equalTo(stampTopView.snp.bottom) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalToSuperview() + } + } + + // MARK: - General Helpers + + private func register() { + stampCollectionView.register(GoalRewardInfoCVC.self, + forCellWithReuseIdentifier: GoalRewardInfoCVC.className) + } +} + +// MARK: - UICollectionViewDelegateFlowLayout + +extension GoalRewardInfoVC: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let screenWidth = UIScreen.main.bounds.width + let tripleCellWidth = screenWidth - stampInset.left - stampInset.right - stampItemSpacing * 2 + return CGSize(width: tripleCellWidth / 3, height: 112) + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return stampLineSpacing + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return stampLineSpacing + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + return stampInset + } +} + +// MARK: - UICollectionViewDataSource + +extension GoalRewardInfoVC: UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return stampList.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let stampCell = collectionView.dequeueReusableCell(withReuseIdentifier: GoalRewardInfoCVC.className, for: indexPath) as? GoalRewardInfoCVC else { return UICollectionViewCell()} + stampCell.dataBind(model: stampList[indexPath.item]) + return stampCell } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift index 03b13596..933123bd 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift @@ -80,7 +80,7 @@ final class MyPageVC: UIViewController { $0.addGestureRecognizer(tap) } - // MARK: - View Life Cycle + // MARK: - override func viewDidLoad() { super.viewDidLoad()