Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GWL-13] 운동 선택 화면 UI 구현 #59

Merged
merged 8 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions iOS/Projects/App/Sources/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import RecordFeature
import UIKit

final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//
// WorkoutCardCell.swift
// RecordFeature
//
// Created by MaraMincho on 11/16/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import DesignSystem
import UIKit

// MARK: - WorkoutCardCell

class WorkoutCardCell: UICollectionViewCell {
static let identifier = "WorkoutCardCell"

override init(frame: CGRect) {
super.init(frame: frame)
makeShadowAndRounded()
backgroundColor = DesignSystemColor.primaryBackGround
setupConstraints()
}

override var isSelected: Bool {
didSet {
if isSelected {
makeSelectUI()
} else {
makeDeslectUI()
}
}
}

private let workoutIconDescriptionLabel: 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 workoutIcon: 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 WorkoutCardCell {
func setupConstraints() {
contentView.addSubview(workoutIconDescriptionLabel)
workoutIconDescriptionLabel.bottomAnchor
.constraint(equalTo: contentView.bottomAnchor, constant: -12).isActive = true
workoutIconDescriptionLabel.leadingAnchor
.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
workoutIconDescriptionLabel.trailingAnchor
.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true

contentView.addSubview(workoutIcon)
workoutIcon.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
workoutIcon.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true
workoutIcon.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5).isActive = true
workoutIcon.bottomAnchor.constraint(equalTo: workoutIconDescriptionLabel.topAnchor, constant: -15).isActive = true
}

func makeShadowAndRounded() {
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() {
workoutIcon.tintColor = DesignSystemColor.main03
workoutIcon.makeShadow()

workoutIconDescriptionLabel.textColor = DesignSystemColor.main03
workoutIconDescriptionLabel.font = .preferredFont(forTextStyle: .title3, with: .traitBold)
}

func makeDeslectUI() {
workoutIcon.tintColor = DesignSystemColor.primaryText
workoutIcon.disableShadow()

workoutIconDescriptionLabel.textColor = DesignSystemColor.primaryText
workoutIconDescriptionLabel.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
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// WorkoutEnvironmentSetupViewController.swift
// RecordFeature
//
// Created by MaraMincho on 11/15/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import DesignSystem
import UIKit

// MARK: - WorkoutEnvironmentSetupViewController

public final class WorkoutEnvironmentSetupViewController: UIViewController {
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: workoutSelectView)

return nav
}()

private let workoutSelectView = WorkoutSelectViewController()

private let pageControl: GWPageControl = {
let pageControl = GWPageControl(count: Constant.countOfPage)

pageControl.translatesAutoresizingMaskIntoConstraints = false
return pageControl
}()

var dataSource: UICollectionViewDiffableDataSource<Int, UUID>!
var workoutCardCollectionView: UICollectionView!
}

private extension WorkoutEnvironmentSetupViewController {
func setup() {
view.backgroundColor = .systemBackground
setupViewHierarchyAndConstraints()
workoutCardCollectionView = workoutSelectView.workoutCardCollectionView

configureDataSource()
}

func configureDataSource() {
dataSource = .init(collectionView: workoutCardCollectionView, cellProvider: { collectionView, indexPath, _ in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WorkoutCardCell.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 setupViewHierarchyAndConstraints() {
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 Constant {
static let countOfPage = 2
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//
// WorkoutSelectViewController.swift
// RecordFeature
//
// Created by MaraMincho on 11/16/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import DesignSystem
import UIKit

// MARK: - WorkoutSelectViewController

final class WorkoutSelectViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupConstraints()
navigationController?.setNavigationBarHidden(true, animated: false)
}

private let workoutSelectDescriptionLabel: UILabel = {
let label = UILabel()
label.font = .preferredFont(forTextStyle: .title1, with: .traitBold)
label.textAlignment = .left
label.text = "1. 운동을 선택하세요"

label.translatesAutoresizingMaskIntoConstraints = false
return label
}()

lazy var workoutCardCollectionView: UICollectionView = {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: makeCollectionViewLayout())
collectionView.register(WorkoutCardCell.self, forCellWithReuseIdentifier: WorkoutCardCell.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 WorkoutSelectViewController {
func makeCollectionViewLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1))

let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(
top: Const.cellInsets,
leading: Const.cellInsets,
bottom: Const.cellInsets,
trailing: Const.cellInsets
)

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(workoutSelectDescriptionLabel)
workoutSelectDescriptionLabel.topAnchor.constraint(equalTo: safeArea.topAnchor).isActive = true
workoutSelectDescriptionLabel.leadingAnchor
.constraint(equalTo: safeArea.leadingAnchor, constant: ConstraintsGuideLine.value).isActive = true
workoutSelectDescriptionLabel.trailingAnchor
.constraint(equalTo: safeArea.trailingAnchor, constant: -ConstraintsGuideLine.value).isActive = true

view.addSubview(workoutCardCollectionView)
workoutCardCollectionView.topAnchor
.constraint(equalTo: workoutSelectDescriptionLabel.bottomAnchor, constant: 12).isActive = true
workoutCardCollectionView.leadingAnchor
.constraint(equalTo: safeArea.leadingAnchor, constant: ConstraintsGuideLine.value).isActive = true
workoutCardCollectionView.trailingAnchor
.constraint(equalTo: safeArea.trailingAnchor, constant: -ConstraintsGuideLine.value).isActive = true
workoutCardCollectionView.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 cellInsets: CGFloat = 5
}
}
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
}