|
| 1 | +// |
| 2 | +// EmotionRegisterView.swift |
| 3 | +// Presentation |
| 4 | +// |
| 5 | +// Created by 최정인 on 7/28/25. |
| 6 | +// |
| 7 | + |
| 8 | +import Combine |
| 9 | +import Shared |
| 10 | +import SnapKit |
| 11 | +import UIKit |
| 12 | + |
| 13 | +final class EmotionRegisterView: BaseViewController<EmotionRegisterViewModel> { |
| 14 | + |
| 15 | + private enum Layout { |
| 16 | + static let mainLabelTopSpacing: CGFloat = 32 |
| 17 | + static let mainLabelHeight: CGFloat = 30 |
| 18 | + static let subLabelTopSpacing: CGFloat = 6 |
| 19 | + static let subLabelHeight: CGFloat = 28 |
| 20 | + static let emotionOrbCellWidth: CGFloat = 96 |
| 21 | + static let emotionOrbCellHeight: CGFloat = 126 |
| 22 | + static let emotionOrbCollectionViewItemSpacing: CGFloat = 13 |
| 23 | + static let emotionOrbCollectionViewLineSpacing: CGFloat = 28 |
| 24 | + static let emotionOrbCollectionViewTopSpacing: CGFloat = 56 |
| 25 | + static let emotionOrbCollectionViewHorizontalMargin: CGFloat = 30 |
| 26 | + static let emotionOrbCollectionViewHeight: CGFloat = 280 |
| 27 | + } |
| 28 | + |
| 29 | + private let mainLabel = UILabel() |
| 30 | + private let subLabel = UILabel() |
| 31 | + private var emotionOrbCollectionView: UICollectionView = { |
| 32 | + let layout = UICollectionViewFlowLayout() |
| 33 | + layout.itemSize = CGSize(width: Layout.emotionOrbCellWidth, height: Layout.emotionOrbCellHeight) |
| 34 | + layout.minimumInteritemSpacing = Layout.emotionOrbCollectionViewItemSpacing |
| 35 | + layout.minimumLineSpacing = Layout.emotionOrbCollectionViewLineSpacing |
| 36 | + layout.sectionInset = .zero |
| 37 | + |
| 38 | + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) |
| 39 | + return collectionView |
| 40 | + }() |
| 41 | + |
| 42 | + private var cancellables: Set<AnyCancellable> |
| 43 | + |
| 44 | + override init(viewModel: EmotionRegisterViewModel) { |
| 45 | + cancellables = [] |
| 46 | + super.init(viewModel: viewModel) |
| 47 | + } |
| 48 | + |
| 49 | + required init?(coder: NSCoder) { |
| 50 | + fatalError("init(coder:) has not been implemented") |
| 51 | + } |
| 52 | + |
| 53 | + override func viewDidLoad() { |
| 54 | + super.viewDidLoad() |
| 55 | + } |
| 56 | + |
| 57 | + override func viewWillAppear(_ animated: Bool) { |
| 58 | + super.viewWillAppear(animated) |
| 59 | + configureNavigationBar(navigationStyle: .withBackButton(title: "")) |
| 60 | + } |
| 61 | + |
| 62 | + override func configureAttribute() { |
| 63 | + mainLabel.text = "오늘의 감정구슬을 골라보세요" |
| 64 | + mainLabel.textAlignment = .center |
| 65 | + mainLabel.font = BitnagilFont(style: .title2, weight: .bold).font |
| 66 | + mainLabel.textColor = BitnagilColor.navy500 |
| 67 | + |
| 68 | + subLabel.text = "감정구슬을 등록하면 루틴을 추천받아요!" |
| 69 | + subLabel.textAlignment = .center |
| 70 | + subLabel.font = BitnagilFont(style: .subtitle1, weight: .regular).font |
| 71 | + subLabel.textColor = BitnagilColor.navy300 |
| 72 | + |
| 73 | + emotionOrbCollectionView.backgroundColor = .clear |
| 74 | + |
| 75 | + emotionOrbCollectionView.delegate = self |
| 76 | + emotionOrbCollectionView.dataSource = self |
| 77 | + emotionOrbCollectionView.register(EmotionOrbCollectionViewCell.self, forCellWithReuseIdentifier: EmotionOrbCollectionViewCell.className) |
| 78 | + } |
| 79 | + |
| 80 | + override func configureLayout() { |
| 81 | + let safeArea = view.safeAreaLayoutGuide |
| 82 | + view.backgroundColor = .systemBackground |
| 83 | + |
| 84 | + view.addSubview(mainLabel) |
| 85 | + view.addSubview(subLabel) |
| 86 | + view.addSubview(emotionOrbCollectionView) |
| 87 | + |
| 88 | + mainLabel.snp.makeConstraints { make in |
| 89 | + make.top.equalTo(safeArea).offset(Layout.mainLabelTopSpacing) |
| 90 | + make.horizontalEdges.equalTo(safeArea) |
| 91 | + make.height.equalTo(Layout.mainLabelHeight) |
| 92 | + } |
| 93 | + |
| 94 | + subLabel.snp.makeConstraints { make in |
| 95 | + make.top.equalTo(mainLabel.snp.bottom).offset(Layout.subLabelTopSpacing) |
| 96 | + make.horizontalEdges.equalTo(safeArea) |
| 97 | + make.height.equalTo(Layout.subLabelHeight) |
| 98 | + } |
| 99 | + |
| 100 | + emotionOrbCollectionView.snp.makeConstraints { make in |
| 101 | + make.top.equalTo(subLabel.snp.bottom).offset(Layout.emotionOrbCollectionViewTopSpacing) |
| 102 | + make.leading.equalTo(safeArea).offset(Layout.emotionOrbCollectionViewHorizontalMargin) |
| 103 | + make.trailing.equalTo(safeArea).inset(Layout.emotionOrbCollectionViewHorizontalMargin) |
| 104 | + make.height.equalTo(Layout.emotionOrbCollectionViewHeight) |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + override func bind() { |
| 109 | + viewModel.output.registerEmotionResultPublisher |
| 110 | + .receive(on: DispatchQueue.main) |
| 111 | + .sink { [weak self] registerEmotionResult in |
| 112 | + if registerEmotionResult { |
| 113 | + // TODO: 추천 루틴 화면 보여주기 |
| 114 | + BitnagilLogger.log(logType: .error, message: "감정 등록 성공") |
| 115 | + } else { |
| 116 | + BitnagilLogger.log(logType: .error, message: "감정 등록 실패") |
| 117 | + } |
| 118 | + } |
| 119 | + .store(in: &cancellables) |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +// MARK: UICollectionViewDelegate |
| 124 | +extension EmotionRegisterView: UICollectionViewDelegate { |
| 125 | + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| 126 | + let selectedEmotionType = EmotionType.allCases[indexPath.item] |
| 127 | + viewModel.action(input: .selectEmotion(emotion: selectedEmotionType)) |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | +// MARK: UICollectionViewDataSource |
| 132 | +extension EmotionRegisterView: UICollectionViewDataSource { |
| 133 | + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| 134 | + return EmotionType.allCases.count |
| 135 | + } |
| 136 | + |
| 137 | + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| 138 | + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EmotionOrbCollectionViewCell.className, for: indexPath) as? EmotionOrbCollectionViewCell |
| 139 | + else { return UICollectionViewCell() } |
| 140 | + |
| 141 | + let emotion = EmotionType.allCases[indexPath.item] |
| 142 | + cell.configureCell(emotion: emotion) |
| 143 | + return cell |
| 144 | + } |
| 145 | +} |
0 commit comments