diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index b5e17360..5b59a50e 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 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 */; }; + A3BC2F382963CE3700198261 /* ActivityRecordInfoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BC2F372963CE3700198261 /* ActivityRecordInfoModel.swift */; }; + A3BC2F3A2963D0ED00198261 /* ActivityRecordInfoTVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BC2F392963D0ED00198261 /* ActivityRecordInfoTVC.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 */; }; @@ -92,6 +94,8 @@ 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 = ""; }; + A3BC2F372963CE3700198261 /* ActivityRecordInfoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityRecordInfoModel.swift; sourceTree = ""; }; + A3BC2F392963D0ED00198261 /* ActivityRecordInfoTVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityRecordInfoTVC.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 = ""; }; @@ -208,6 +212,7 @@ A3BC2F292962C39F00198261 /* InfoVC */ = { isa = PBXGroup; children = ( + A3BC2F362963CD2100198261 /* ActivityRecordInfoTableView */, A3BC2F302962E08400198261 /* GoalRewardInfoCollectionView */, A3BC2F2A2962C3D500198261 /* GoalRewardInfoVC.swift */, A3BC2F2C2962C3F200198261 /* ActivityRecordInfoVC.swift */, @@ -225,6 +230,15 @@ path = GoalRewardInfoCollectionView; sourceTree = ""; }; + A3BC2F362963CD2100198261 /* ActivityRecordInfoTableView */ = { + isa = PBXGroup; + children = ( + A3BC2F372963CE3700198261 /* ActivityRecordInfoModel.swift */, + A3BC2F392963D0ED00198261 /* ActivityRecordInfoTVC.swift */, + ); + path = ActivityRecordInfoTableView; + sourceTree = ""; + }; CE17F02E2961BEAE00E1DED0 /* Fonts */ = { isa = PBXGroup; children = ( @@ -847,6 +861,7 @@ CEEC6B402961C55000D00E1E /* MyPageVC.swift in Sources */, CE665608295D921500C64E12 /* setImage.swift in Sources */, CE665612295D92E400C64E12 /* UserDefaultWrapper.swift in Sources */, + A3BC2F3A2963D0ED00198261 /* ActivityRecordInfoTVC.swift in Sources */, CE665610295D92C200C64E12 /* setTextLineHeight.swift in Sources */, CE6655E2295D87EB00C64E12 /* UIImage+.swift in Sources */, A3BC2F322962E0DB00198261 /* GoalRewardInfoModel.swift in Sources */, @@ -856,6 +871,7 @@ CE17F02D2961BBA100E1DED0 /* ColorLiterals.swift in Sources */, CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */, CE6655D2295D862A00C64E12 /* Publisher+Driver.swift in Sources */, + A3BC2F382963CE3700198261 /* ActivityRecordInfoModel.swift in Sources */, CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, A3BC2F34296303A600198261 /* GoalRewardInfoCVC.swift in Sources */, CEB8416E2962C45300BF8080 /* LocationSearchResultTVC.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Literal/ColorLiterals.swift b/Runnect-iOS/Runnect-iOS/Global/Literal/ColorLiterals.swift index dedf2a48..f98c942d 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Literal/ColorLiterals.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Literal/ColorLiterals.swift @@ -47,6 +47,10 @@ extension UIColor { static var m4: UIColor { return UIColor(hex: "#FFFFFF") } + + static var m5: UIColor { + return UIColor(hex: "#D5D4FF") + } } extension UIColor { diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoTableView/ActivityRecordInfoModel.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoTableView/ActivityRecordInfoModel.swift new file mode 100644 index 00000000..4bda198e --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoTableView/ActivityRecordInfoModel.swift @@ -0,0 +1,17 @@ +// +// ActivityRecordInfoModel.swift +// Runnect-iOS +// +// Created by 몽이 누나 on 2023/01/03. +// + +import Foundation + +struct ActivityRecordInfoModel { + let title: String + let place: String + let date: String + let distance: String + let runningTime: String + let averagePace: String +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoTableView/ActivityRecordInfoTVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoTableView/ActivityRecordInfoTVC.swift new file mode 100644 index 00000000..8d1c979e --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoTableView/ActivityRecordInfoTVC.swift @@ -0,0 +1,192 @@ +// +// ActivityRecordInfoTVC.swift +// Runnect-iOS +// +// Created by 몽이 누나 on 2023/01/03. +// + +import UIKit +import SnapKit +import Then + +final class ActivityRecordInfoTVC: UITableViewCell { + + // MARK: - UI Components + + private let activityRecordContainerView = UIView().then { + $0.layer.cornerRadius = 10 + $0.layer.borderWidth = 1 + $0.layer.borderColor = UIColor.m5.cgColor + } + + private let horizontalDivideLine = UIView() + private let firstVerticalDivideLine = UIView() + private let secondVerticalDivideLine = UIView() + + private let activityRecordMapImage = UIView().then { + $0.layer.cornerRadius = 10 + } + + private lazy var activityRecordTitleLabel = setBlackTitle() + private lazy var activityRecordPlaceLabel = setGreyTitle() + + private lazy var activityRecordVirticalBarLabel = setGreyTitle().then { + $0.text = "|" + } + + private lazy var activityRecordDateLabel = setGreyTitle() + + private lazy var activityRecordSubTitleStackView = UIStackView(arrangedSubviews: [activityRecordPlaceLabel, activityRecordVirticalBarLabel, activityRecordDateLabel]).then { + $0.axis = .horizontal + $0.spacing = 4 + } + + private lazy var activityRecordMainInfoStackView = UIStackView(arrangedSubviews: [activityRecordTitleLabel, activityRecordSubTitleStackView]).then { + $0.axis = .vertical + $0.alignment = .leading + $0.spacing = 7 + } + + private lazy var activityRecordTotalDistanceValueLabel = setBlackTitle() + private lazy var activityRecordRunningTimeValueLabel = setBlackTitle() + private lazy var activityRecordAveragePaceValueLabel = setBlackTitle() + + private lazy var activityRecordTotalDistanceLabel = setGreyTitle().then { + $0.text = "총 거리" + } + + private lazy var activityRecordRunningTimeLabel = setGreyTitle().then { + $0.text = "이동 시간" + } + + private lazy var activityRecordAveragePaceLabel = setGreyTitle().then { + $0.text = "평균 페이스" + } + + private lazy var activityRecordTotalDistanceStackView = setDetailInfoStakcView(title: activityRecordTotalDistanceLabel, value: activityRecordTotalDistanceValueLabel) + + private lazy var activityRecordRunningTimeStackView = setDetailInfoStakcView(title: activityRecordRunningTimeLabel, value: activityRecordRunningTimeValueLabel) + + private lazy var activityRecordAveragePaceStackView = setDetailInfoStakcView(title: activityRecordAveragePaceLabel, value: activityRecordAveragePaceValueLabel) + + private lazy var activityRecordSubInfoStackView = UIStackView(arrangedSubviews: [activityRecordTotalDistanceStackView, firstVerticalDivideLine, activityRecordRunningTimeStackView, secondVerticalDivideLine, activityRecordAveragePaceStackView]).then { + $0.axis = .horizontal + $0.distribution = .fillProportionally + } + + // MARK: - Life Cycles + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setUI() + setLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension ActivityRecordInfoTVC { + + // MARK: - Method + + func setDetailInfoStakcView(title: UIView, value: UIView) -> UIStackView { + let stackView = UIStackView(arrangedSubviews: [title, value]) + stackView.axis = .vertical + stackView.alignment = .center + stackView.spacing = 2 + return stackView + } + + func setBlackTitle() -> UILabel { + let label = UILabel() + label.textColor = .g1 + label.font = .h5 + return label + } + + func setGreyTitle() -> UILabel { + let label = UILabel() + label.textColor = .g2 + label.font = .b8 + return label + } +} + +extension ActivityRecordInfoTVC { + + // MARK: - Layout Helpers + + func setUI() { + activityRecordMapImage.backgroundColor = .g3 + horizontalDivideLine.backgroundColor = .g4 + firstVerticalDivideLine.backgroundColor = .g4 + secondVerticalDivideLine.backgroundColor = .g4 + } + + func setLayout() { + addSubview(activityRecordContainerView) + + activityRecordContainerView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.leading.trailing.equalToSuperview().inset(16) + make.height.equalTo(177) + } + + activityRecordContainerView.addSubviews( + activityRecordMapImage, + activityRecordMainInfoStackView, + horizontalDivideLine, + activityRecordSubInfoStackView + ) + + activityRecordMapImage.snp.makeConstraints { make in + make.top.equalToSuperview().offset(13) + make.leading.equalToSuperview().offset(15) + make.width.equalTo(86) + make.height.equalTo(85) + } + + activityRecordMainInfoStackView.snp.makeConstraints { make in + make.centerY.equalTo(activityRecordMapImage.snp.centerY) + make.leading.equalTo(activityRecordMapImage.snp.trailing).offset(14) + } + + horizontalDivideLine.snp.makeConstraints { make in + make.top.equalTo(activityRecordMapImage.snp.bottom).offset(8) + make.leading.trailing.equalToSuperview().inset(10) + make.height.equalTo(1) + } + + firstVerticalDivideLine.snp.makeConstraints { make in + make.width.equalTo(1) + } + + secondVerticalDivideLine.snp.makeConstraints { make in + make.width.equalTo(1) + } + + activityRecordSubInfoStackView.snp.makeConstraints { make in + make.top.equalTo(horizontalDivideLine.snp.bottom).offset(15) + make.width.equalToSuperview() + make.centerX.equalToSuperview() + } + } + + override func layoutSubviews() { + super.layoutSubviews() + contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 0, left: 0, bottom: 16, right: 0)) + } + + // MARK: - General Helpers + + func dataBind(model: ActivityRecordInfoModel) { + activityRecordTitleLabel.text = model.title + activityRecordPlaceLabel.text = model.place + activityRecordDateLabel.text = model.date + activityRecordTotalDistanceValueLabel.text = model.distance + activityRecordRunningTimeValueLabel.text = model.runningTime + activityRecordAveragePaceValueLabel.text = model.averagePace + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift index a51dbc40..85a7547e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift @@ -6,18 +6,98 @@ // import UIKit +import SnapKit +import Then final class ActivityRecordInfoVC: UIViewController { + + // MARK: - Properties + + var activityRecordList: [ActivityRecordInfoModel] = [ + ActivityRecordInfoModel(title: "석촌 호수 한 바퀴", place: "서울시 강동구", date: "2022.12.28", distance: "4.01 km", runningTime: "0:27:36", averagePace: "6'45\""), + ActivityRecordInfoModel(title: "석촌 호수 한 바퀴", place: "서울시 강동구", date: "2022.12.29", distance: "4.01 km", runningTime: "0:27:36", averagePace: "6'45\""), + ActivityRecordInfoModel(title: "석촌 호수 한 바퀴", place: "서울시 강동구", date: "2022.12.30", distance: "4.01 km", runningTime: "0:27:36", averagePace: "6'45\""), + ActivityRecordInfoModel(title: "석촌 호수 한 바퀴", place: "서울시 강동구", date: "2022.12.31", distance: "4.01 km", runningTime: "0:27:36", averagePace: "6'45\""), + ActivityRecordInfoModel(title: "석촌 호수 한 바퀴", place: "서울시 강동구", date: "2022.12.28", distance: "4.01 km", runningTime: "0:27:36", averagePace: "6'45\""), + ActivityRecordInfoModel(title: "석촌 호수 한 바퀴", place: "서울시 강동구", date: "2022.12.28", distance: "4.01 km", runningTime: "0:27:36", averagePace: "6'45\"") + ] + + // MARK: - UI Components + + private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton).setTitle("활동 기록") + + private lazy var activityRecordTableView = UITableView().then { + $0.showsVerticalScrollIndicator = false + $0.separatorStyle = .none + $0.delegate = self + $0.dataSource = self + } + // MARK: - View Life Cycle + override func viewDidLoad() { super.viewDidLoad() + setNavigationBar() setUI() - // Do any additional setup after loading the view. + setLayout() + register() } } extension ActivityRecordInfoVC { + + // 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 + activityRecordTableView.backgroundColor = .w1 + } + + private func setLayout() { + view.addSubview(activityRecordTableView) + + activityRecordTableView.snp.makeConstraints { make in + make.top.equalTo(navibar.snp.bottom).offset(16) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.bottom.equalToSuperview() + } + } + + // MARK: - General Helpers + + private func register() { + activityRecordTableView.register(ActivityRecordInfoTVC.self, forCellReuseIdentifier: ActivityRecordInfoTVC.className) + } +} + +// MARK: - UITableViewDelegate + +extension ActivityRecordInfoVC: UITableViewDelegate { + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 193 + } +} + +// MARK: - UITableViewDataSource + +extension ActivityRecordInfoVC: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return activityRecordList.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let activityRecordCell = tableView.dequeueReusableCell(withIdentifier: ActivityRecordInfoTVC.className, for: indexPath) as? ActivityRecordInfoTVC else { return UITableViewCell()} + activityRecordCell.selectionStyle = .none + activityRecordCell.dataBind(model: activityRecordList[indexPath.item]) + return activityRecordCell } }