-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
84e95aa
commit 8f26a18
Showing
5 changed files
with
343 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
iOS/Projects/Features/Record/Sources/ExerciseSelectScene/View/ExerciseCardCell.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// | ||
// ExerciseCardCell.swift | ||
// RecordFeature | ||
// | ||
// Created by MaraMincho on 11/16/23. | ||
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved. | ||
// | ||
|
||
import DesignSystem | ||
import UIKit | ||
|
||
// MARK: - ExerciseCardCell | ||
|
||
class ExerciseCardCell: UICollectionViewCell { | ||
static let identifier = "ExerciseCardCell" | ||
|
||
override init(frame: CGRect) { | ||
super.init(frame: frame) | ||
shadowDecorate() | ||
backgroundColor = .white | ||
setupConstraints() | ||
} | ||
|
||
override var isSelected: Bool { | ||
didSet { | ||
if isSelected { | ||
makeSelectUI() | ||
} else { | ||
makeDeslectUI() | ||
} | ||
} | ||
} | ||
|
||
private let exerciseIconDescriptionLagel: UILabel = { | ||
let label = UILabel() | ||
label.font = UIFont.preferredFont(forTextStyle: .title3) | ||
label.textAlignment = .center | ||
label.text = "달리기에용" | ||
label.contentMode = .scaleAspectFit | ||
|
||
label.translatesAutoresizingMaskIntoConstraints = false | ||
return label | ||
}() | ||
|
||
private let exerciseIcon: UIImageView = { | ||
let config = UIImage.SymbolConfiguration(font: .systemFont(ofSize: 120)) | ||
let icon = UIImage(systemName: "figure.run", withConfiguration: config) | ||
let imageView = UIImageView(image: icon) | ||
imageView.contentMode = .scaleAspectFit | ||
imageView.tintColor = DesignSystemColor.primaryText | ||
|
||
imageView.translatesAutoresizingMaskIntoConstraints = false | ||
return imageView | ||
}() | ||
|
||
required init?(coder: NSCoder) { | ||
super.init(coder: coder) | ||
} | ||
} | ||
|
||
private extension ExerciseCardCell { | ||
func setupConstraints() { | ||
contentView.addSubview(exerciseIconDescriptionLagel) | ||
exerciseIconDescriptionLagel.bottomAnchor | ||
.constraint(equalTo: contentView.bottomAnchor, constant: -12).isActive = true | ||
exerciseIconDescriptionLagel.leadingAnchor | ||
.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true | ||
exerciseIconDescriptionLagel.trailingAnchor | ||
.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true | ||
|
||
contentView.addSubview(exerciseIcon) | ||
exerciseIcon.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true | ||
exerciseIcon.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true | ||
exerciseIcon.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5).isActive = true | ||
exerciseIcon.bottomAnchor.constraint(equalTo: exerciseIconDescriptionLagel.topAnchor, constant: -15).isActive = true | ||
} | ||
|
||
func shadowDecorate() { | ||
let radius: CGFloat = 10 | ||
contentView.layer.cornerRadius = radius | ||
contentView.layer.borderWidth = 1 | ||
contentView.layer.borderColor = UIColor.clear.cgColor | ||
contentView.layer.masksToBounds = true | ||
|
||
layer.shadowColor = UIColor.black.cgColor | ||
layer.shadowOffset = CGSize(width: 0, height: 1.0) | ||
layer.shadowRadius = 2.0 | ||
layer.shadowOpacity = 0.5 | ||
layer.masksToBounds = false | ||
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath | ||
layer.cornerRadius = radius | ||
} | ||
|
||
func makeSelectUI() { | ||
exerciseIcon.tintColor = DesignSystemColor.main03 | ||
exerciseIcon.makeShadow() | ||
exerciseIconDescriptionLagel.textColor = DesignSystemColor.main03 | ||
exerciseIconDescriptionLagel.font = .preferredFont(forTextStyle: .title3, with: .traitBold) | ||
} | ||
|
||
func makeDeslectUI() { | ||
exerciseIcon.tintColor = DesignSystemColor.primaryText | ||
exerciseIcon.disableShadow() | ||
exerciseIconDescriptionLagel.textColor = DesignSystemColor.primaryText | ||
exerciseIconDescriptionLagel.font = .preferredFont(forTextStyle: .title3) | ||
} | ||
} | ||
|
||
private extension UIImageView { | ||
func makeShadow() { | ||
layer.shadowColor = UIColor.black.cgColor | ||
layer.shadowOffset = CGSize(width: -2, height: 2) | ||
layer.shadowRadius = 2.0 | ||
layer.shadowOpacity = 0.3 | ||
layer.masksToBounds = false | ||
} | ||
|
||
func disableShadow() { | ||
layer.shadowOpacity = 0 | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
...ures/Record/Sources/ExerciseSelectScene/View/ExerciseEnvironmentSetupViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// | ||
// ExerciseEnvironmentSetupViewController.swift | ||
// RecordFeature | ||
// | ||
// Created by MaraMincho on 11/15/23. | ||
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved. | ||
// | ||
|
||
import DesignSystem | ||
import UIKit | ||
|
||
// MARK: - ExerciseEnvironmentSetupViewController | ||
|
||
public final class ExerciseEnvironmentSetupViewController: UIViewController { | ||
public init() { | ||
super.init(nibName: nil, bundle: nil) | ||
} | ||
|
||
public required init?(coder: NSCoder) { | ||
super.init(coder: coder) | ||
} | ||
|
||
override public func viewDidLoad() { | ||
super.viewDidLoad() | ||
setup() | ||
} | ||
|
||
override public func viewDidAppear(_ animated: Bool) { | ||
super.viewDidAppear(animated) | ||
|
||
insertTempSource() | ||
} | ||
|
||
lazy var contentNAV: UINavigationController = { | ||
let nav = UINavigationController(rootViewController: exerciseSelectView) | ||
|
||
return nav | ||
}() | ||
|
||
private let exerciseSelectView = ExerciseSelectViewController() | ||
|
||
private let pageControl: GWPageControl = { | ||
let pageControl = GWPageControl(count: Const.countOfPage) | ||
|
||
pageControl.translatesAutoresizingMaskIntoConstraints = false | ||
return pageControl | ||
}() | ||
|
||
var dataSource: UICollectionViewDiffableDataSource<Int, UUID>! | ||
var exerciseCardCollectionView: UICollectionView! | ||
} | ||
|
||
private extension ExerciseEnvironmentSetupViewController { | ||
func setup() { | ||
view.backgroundColor = .systemBackground | ||
setupConstraints() | ||
exerciseCardCollectionView = exerciseSelectView.exerciseCardCollectionView | ||
|
||
configureDataSource() | ||
} | ||
|
||
func configureDataSource() { | ||
dataSource = .init(collectionView: exerciseCardCollectionView, cellProvider: { collectionView, indexPath, _ in | ||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ExerciseCardCell.identifier, for: indexPath) | ||
return cell | ||
}) | ||
} | ||
|
||
func insertTempSource() { | ||
var snapshot = dataSource.snapshot() | ||
snapshot.deleteAllItems() | ||
snapshot.appendSections([0]) | ||
snapshot.appendItems([.init(), .init(), .init(), .init(), .init()]) | ||
|
||
dataSource.apply(snapshot) | ||
} | ||
|
||
func setupConstraints() { | ||
let safeArea = view.safeAreaLayoutGuide | ||
|
||
view.addSubview(pageControl) | ||
pageControl.topAnchor.constraint(equalTo: safeArea.topAnchor, constant: 10).isActive = true | ||
pageControl.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor, constant: 23).isActive = true | ||
pageControl.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: -23).isActive = true | ||
pageControl.heightAnchor.constraint(equalToConstant: 30).isActive = true | ||
|
||
view.addSubview(contentNAV.view) | ||
contentNAV.view.translatesAutoresizingMaskIntoConstraints = false | ||
contentNAV.view.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor).isActive = true | ||
contentNAV.view.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor).isActive = true | ||
contentNAV.view.topAnchor.constraint(equalTo: pageControl.bottomAnchor).isActive = true | ||
contentNAV.view.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor).isActive = true | ||
} | ||
|
||
enum Const { | ||
static let countOfPage = 2 | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
...jects/Features/Record/Sources/ExerciseSelectScene/View/ExerciseSelectViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// | ||
// ExerciseSelectViewController.swift | ||
// RecordFeature | ||
// | ||
// Created by MaraMincho on 11/16/23. | ||
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved. | ||
// | ||
|
||
import DesignSystem | ||
import UIKit | ||
|
||
// MARK: - ExerciseSelectViewController | ||
|
||
final class ExerciseSelectViewController: UIViewController { | ||
override init(nibName _: String?, bundle _: Bundle?) { | ||
super.init(nibName: nil, bundle: nil) | ||
} | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
setupConstraints() | ||
navigationController?.setNavigationBarHidden(true, animated: false) | ||
} | ||
|
||
required init?(coder: NSCoder) { | ||
super.init(coder: coder) | ||
} | ||
|
||
private let exerciseSelectDescriptionLabel: UILabel = { | ||
let label = UILabel() | ||
label.font = .preferredFont(forTextStyle: .title1, with: .traitBold) | ||
label.textAlignment = .left | ||
label.text = "1. 운동을 선택하세요" | ||
|
||
label.translatesAutoresizingMaskIntoConstraints = false | ||
return label | ||
}() | ||
|
||
lazy var exerciseCardCollectionView: UICollectionView = { | ||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: makeCollectionViewLayout()) | ||
collectionView.register(ExerciseCardCell.self, forCellWithReuseIdentifier: ExerciseCardCell.identifier) | ||
|
||
collectionView.translatesAutoresizingMaskIntoConstraints = false | ||
return collectionView | ||
}() | ||
|
||
private let nextButton: UIButton = { | ||
let button = UIButton() | ||
button.configurationUpdateHandler = UIButton.Configuration.main(label: "다음") | ||
|
||
button.translatesAutoresizingMaskIntoConstraints = false | ||
return button | ||
}() | ||
} | ||
|
||
private extension ExerciseSelectViewController { | ||
func makeCollectionViewLayout() -> UICollectionViewLayout { | ||
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1)) | ||
|
||
let item = NSCollectionLayoutItem(layoutSize: itemSize) | ||
item.contentInsets = .init( | ||
top: Const.CellInset, | ||
leading: Const.CellInset, | ||
bottom: Const.CellInset, | ||
trailing: Const.CellInset | ||
) | ||
|
||
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), | ||
heightDimension: .fractionalWidth(0.55)) | ||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) | ||
|
||
let section = NSCollectionLayoutSection(group: group) | ||
|
||
return UICollectionViewCompositionalLayout(section: section) | ||
} | ||
|
||
func setupConstraints() { | ||
let safeArea = view.safeAreaLayoutGuide | ||
|
||
view.addSubview(exerciseSelectDescriptionLabel) | ||
exerciseSelectDescriptionLabel.topAnchor.constraint(equalTo: safeArea.topAnchor).isActive = true | ||
exerciseSelectDescriptionLabel.leadingAnchor | ||
.constraint(equalTo: safeArea.leadingAnchor, constant: ConstraintsGuideLine.value).isActive = true | ||
exerciseSelectDescriptionLabel.trailingAnchor | ||
.constraint(equalTo: safeArea.trailingAnchor, constant: -ConstraintsGuideLine.value).isActive = true | ||
|
||
view.addSubview(exerciseCardCollectionView) | ||
exerciseCardCollectionView.topAnchor | ||
.constraint(equalTo: exerciseSelectDescriptionLabel.bottomAnchor, constant: 12).isActive = true | ||
exerciseCardCollectionView.leadingAnchor | ||
.constraint(equalTo: safeArea.leadingAnchor, constant: ConstraintsGuideLine.value).isActive = true | ||
exerciseCardCollectionView.trailingAnchor | ||
.constraint(equalTo: safeArea.trailingAnchor, constant: -ConstraintsGuideLine.value).isActive = true | ||
exerciseCardCollectionView.bottomAnchor | ||
.constraint(equalTo: view.bottomAnchor, constant: -15).isActive = true | ||
|
||
view.addSubview(nextButton) | ||
nextButton.leadingAnchor | ||
.constraint(equalTo: safeArea.leadingAnchor, constant: ConstraintsGuideLine.value).isActive = true | ||
nextButton.trailingAnchor | ||
.constraint(equalTo: safeArea.trailingAnchor, constant: -ConstraintsGuideLine.value).isActive = true | ||
nextButton.bottomAnchor | ||
.constraint(equalTo: safeArea.bottomAnchor, constant: -28).isActive = true | ||
} | ||
|
||
enum Const { | ||
static let CellInset: CGFloat = 5 | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
iOS/Projects/Shared/DesignSystem/Sources/ConstraintsGuideLine.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// | ||
// ConstraintsGuideLine.swift | ||
// DesignSystem | ||
// | ||
// Created by MaraMincho on 11/18/23. | ||
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
public enum ConstraintsGuideLine { | ||
public static let value: CGFloat = 23 | ||
} |