Skip to content

Commit 8518394

Browse files
committed
Feat: 감정 구슬 등록 버튼 레이아웃 조정 (#T3-167)
1 parent 51b9986 commit 8518394

4 files changed

Lines changed: 51 additions & 55 deletions

File tree

Projects/Presentation/Sources/Common/Extension/UIViewController+.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ extension UIViewController {
1616
case withProgressBar(step: Int) // 백버튼 + progress
1717
}
1818

19-
func configureCustomNavigationBar(navigationBarStyle: NavigationBarStyle) {
19+
func configureCustomNavigationBar(navigationBarStyle: NavigationBarStyle, backgroundColor: UIColor? = .white) {
2020
let safeArea = self.view.safeAreaLayoutGuide
2121
let navigationBar: UIView = customNavigationBar(navigationBarStyle: navigationBarStyle)
2222

23+
navigationBar.backgroundColor = backgroundColor
2324
self.view.addSubview(navigationBar)
2425
navigationBar.snp.makeConstraints { make in
2526
make.top.horizontalEdges.equalTo(safeArea)

Projects/Presentation/Sources/Common/View/TabBarView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ final public class TabBarView: UITabBarController {
4949
else { fatalError("mypageViewModel 의존성이 등록되지 않았습니다.") }
5050

5151
let homeView = HomeView(viewModel: homeViewModel)
52-
let recommendView = RecommendedRoutineView(viewModel: recommendedRoutineViewModel)
52+
let recommendView = RecommendedRoutineViewController(viewModel: recommendedRoutineViewModel)
5353
let mypageView = MypageView(viewModel: mypageViewModel)
5454

5555
homeView.tabBarItem = UITabBarItem(

Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineLevelButton.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import Domain
99
import UIKit
1010

1111
final class RoutineLevelButton: UIButton {
12-
1312
private enum Layout {
1413
static let stackViewSpacing: CGFloat = 5
1514
static let buttonLabelHeight: CGFloat = 20
@@ -44,14 +43,14 @@ final class RoutineLevelButton: UIButton {
4443

4544
buttonLabel.text = level?.title ?? "난이도 선택"
4645
buttonLabel.font = BitnagilFont(style: .body2, weight: .medium).font
47-
buttonLabel.textColor = BitnagilColor.gray60
46+
buttonLabel.textColor = BitnagilColor.gray40
4847

4948
chevronIcon.image = BitnagilIcon
5049
.chevronIcon(direction: .down)?
5150
.resizeAspectFit(to: CGSize(width: Layout.chevronImageSize, height: Layout.chevronImageSize))?
5251
.withRenderingMode(.alwaysTemplate)
5352
chevronIcon.contentMode = .center
54-
chevronIcon.tintColor = BitnagilColor.gray60
53+
chevronIcon.tintColor = BitnagilColor.gray40
5554
}
5655

5756
private func configureLayout() {

Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineView.swift renamed to Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineViewController.swift

Lines changed: 46 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// RecommendedRoutineView.swift
2+
// RecommendedRoutineViewController.swift
33
// Presentation
44
//
55
// Created by 최정인 on 7/12/25.
@@ -11,14 +11,15 @@ import Shared
1111
import SnapKit
1212
import UIKit
1313

14-
final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewModel> {
14+
final class RecommendedRoutineViewController: BaseViewController<RecommendedRoutineViewModel> {
1515
private enum Layout {
1616
static let horizontalMargin: CGFloat = 20
1717
static let bottomSheetHeight: CGFloat = 226
18-
static let categoryViewTopSpacing: CGFloat = 16
18+
static let categoryViewTopSpacing: CGFloat = 70
1919
static let categoryViewHeight: CGFloat = 36
2020
static let headerStackViewTrailingSpacing: CGFloat = 8
21-
static let headerStackViewTopSpacing: CGFloat = 18
21+
static let headerStackViewTopSpacing: CGFloat = 20
22+
static let headerStackViewTopMaxSpacing: CGFloat = 24
2223
static let headerStackViewHeight: CGFloat = 40
2324
static let recommendedRoutineStackViewSpacing: CGFloat = 12
2425
static let recommendedRoutineScrollViewTopSpacing: CGFloat = 12
@@ -50,10 +51,8 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
5051
private let dimmedView = UIView()
5152
private let floatingButton = FloatingButton()
5253
private let floatingMenu = FloatingMenuView()
53-
54-
private let toastMessageView = ToastMessageView()
55-
5654
private var cancellables: Set<AnyCancellable>
55+
5756
public override init(viewModel: RecommendedRoutineViewModel) {
5857
cancellables = []
5958
super.init(viewModel: viewModel)
@@ -70,12 +69,11 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
7069
}
7170

7271
override func configureAttribute() {
73-
title = "추천 루틴"
7472
categoryView.delegate = self
7573

76-
routineLabel.text = "루틴 목록"
77-
routineLabel.font = BitnagilFont(style: .body1, weight: .semiBold).font
78-
routineLabel.textColor = BitnagilColor.gray10
74+
routineLabel.text = "추천 루틴리스트"
75+
routineLabel.font = BitnagilFont(style: .body2, weight: .semiBold).font
76+
routineLabel.textColor = BitnagilColor.gray60
7977

8078
headerStackView.axis = .horizontal
8179

@@ -109,9 +107,12 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
109107

110108
override func configureLayout() {
111109
let safeArea = view.safeAreaLayoutGuide
112-
view.backgroundColor = .systemBackground
110+
view.backgroundColor = BitnagilColor.gray99
111+
navigationController?.setNavigationBarHidden(true, animated: false)
112+
configureCustomNavigationBar(navigationBarStyle: .withTitle(title: "추천 루틴"), backgroundColor: BitnagilColor.gray99)
113113

114114
view.addSubview(categoryView)
115+
view.addSubview(registerEmotionButton)
115116
view.addSubview(headerStackView)
116117
[routineLabel, levelButton].forEach {
117118
headerStackView.addArrangedSubview($0)
@@ -123,19 +124,24 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
123124
view.addSubview(floatingMenu)
124125
view.addSubview(floatingButton)
125126

126-
view.addSubview(toastMessageView)
127-
128127
categoryView.snp.makeConstraints { make in
129128
make.leading.equalTo(safeArea)
130129
make.trailing.equalTo(safeArea)
131130
make.top.equalTo(safeArea).offset(Layout.categoryViewTopSpacing)
132131
make.height.equalTo(Layout.categoryViewHeight)
133132
}
134133

134+
registerEmotionButton.snp.makeConstraints { make in
135+
make.leading.equalToSuperview().offset(20)
136+
make.trailing.equalToSuperview().inset(20)
137+
make.top.equalTo(categoryView.snp.bottom).offset(20)
138+
make.height.equalTo(Layout.registerEmotionButtonHeight)
139+
}
140+
135141
headerStackView.snp.makeConstraints { make in
136142
make.leading.equalTo(safeArea).offset(Layout.horizontalMargin)
137143
make.trailing.equalTo(safeArea).inset(Layout.headerStackViewTrailingSpacing)
138-
make.top.equalTo(categoryView.snp.bottom).offset(Layout.headerStackViewTopSpacing)
144+
make.top.equalTo(registerEmotionButton.snp.bottom).offset(Layout.headerStackViewTopSpacing)
139145
make.height.equalTo(Layout.headerStackViewHeight)
140146
}
141147

@@ -176,19 +182,14 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
176182
dimmedView.snp.makeConstraints { make in
177183
make.edges.equalToSuperview()
178184
}
179-
180-
toastMessageView.snp.makeConstraints { make in
181-
make.centerX.equalToSuperview()
182-
make.bottom.equalTo(safeArea.snp.bottom).offset(-Layout.toastMessageBottomSpacing)
183-
}
184185
}
185186

186187
override func bind() {
187188
viewModel.output.selectedCategoryPublisher
188189
.receive(on: DispatchQueue.main)
189190
.sink { [weak self] selectedCategory in
190-
self?.showEmotionButton(isShowEmotionButton: selectedCategory == .recommendation)
191191
self?.categoryView.updateSelectedCategory(selectedCategory: selectedCategory)
192+
self?.showEmotionButton(isShowEmotionButton: selectedCategory == .recommendation)
192193
}
193194
.store(in: &cancellables)
194195

@@ -204,7 +205,7 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
204205
.sink { [weak self] isExistEmotion in
205206
if isExistEmotion {
206207
self?.isExistEmotion = isExistEmotion
207-
self?.registerEmotionButton.isHidden = true
208+
self?.showEmotionButton(isShowEmotionButton: false)
208209
}
209210
}
210211
.store(in: &cancellables)
@@ -241,24 +242,20 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
241242

242243
// 감정 등록 버튼을 보이거나 숨겨줍니다.
243244
private func showEmotionButton(isShowEmotionButton: Bool) {
244-
guard !isExistEmotion else {
245-
registerEmotionButton.isHidden = true
246-
return
247-
}
248-
249-
guard isShowEmotionButton else {
250-
registerEmotionButton.isHidden = true
251-
return
252-
}
253-
guard !recommendedRoutineStackView.arrangedSubviews.contains(registerEmotionButton) else {
254-
registerEmotionButton.isHidden = false
255-
return
256-
}
245+
let safeArea = view.safeAreaLayoutGuide
246+
let showingEmotionButton = isShowEmotionButton && !isExistEmotion
247+
registerEmotionButton.isHidden = !showingEmotionButton
257248

258-
recommendedRoutineStackView.addArrangedSubview(registerEmotionButton)
259-
registerEmotionButton.snp.makeConstraints { make in
260-
make.leading.trailing.equalToSuperview()
261-
make.height.equalTo(Layout.registerEmotionButtonHeight)
249+
headerStackView.snp.remakeConstraints { make in
250+
make.leading.equalTo(safeArea).offset(Layout.horizontalMargin)
251+
make.trailing.equalTo(safeArea).inset(Layout.headerStackViewTrailingSpacing)
252+
make.height.equalTo(Layout.headerStackViewHeight)
253+
254+
if showingEmotionButton {
255+
make.top.equalTo(registerEmotionButton.snp.bottom).offset(Layout.headerStackViewTopSpacing)
256+
} else {
257+
make.top.equalTo(categoryView.snp.bottom).offset(Layout.headerStackViewTopMaxSpacing)
258+
}
262259
}
263260
}
264261

@@ -282,18 +279,17 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
282279
}
283280

284281
// MARK: RoutineCategoryViewDelegate
285-
extension RecommendedRoutineView: RoutineCategoryViewDelegate {
282+
extension RecommendedRoutineViewController: RoutineCategoryViewDelegate {
286283
func routineCategoryView(_ sender: RoutineCategoryView, didSelectCategory category: RoutineCategoryType) {
287284
viewModel.action(input: .selectCategory(selectedCategory: category))
288285
}
289286
}
290287

291288
// MARK: RecommendedRoutineCardViewDelegate
292-
extension RecommendedRoutineView: RecommendedRoutineCardViewDelegate {
289+
extension RecommendedRoutineViewController: RecommendedRoutineCardViewDelegate {
293290
func recommendedRoutineCardView(_ sender: RecommendedRoutineCardView, didTapRecommendedRoutine routine: RecommendedRoutine) {
294-
guard let routineCreationViewModel = DIContainer.shared.resolve(type: RoutineCreationViewModel.self) else {
295-
fatalError("routineCreationViewModel 의존성이 등록되지 않았습니다.")
296-
}
291+
guard let routineCreationViewModel = DIContainer.shared.resolve(type: RoutineCreationViewModel.self)
292+
else { fatalError("routineCreationViewModel 의존성이 등록되지 않았습니다.") }
297293

298294
let routineCreationView = RoutineCreationView(viewModel: routineCreationViewModel, recommendRoutineId: routine.id)
299295
routineCreationView.hidesBottomBarWhenPushed = true
@@ -302,7 +298,7 @@ extension RecommendedRoutineView: RecommendedRoutineCardViewDelegate {
302298
}
303299

304300
// MARK: SelectableItemTableViewDelegate
305-
extension RecommendedRoutineView: SelectableItemTableViewDelegate {
301+
extension RecommendedRoutineViewController: SelectableItemTableViewDelegate {
306302
func selectableItemTableView<T: SelectableItem & CaseIterable & Equatable>(_ sender: SelectableItemTableView<T>, didSelectItem: T?) {
307303
guard let didSelectLevel = didSelectItem as? RoutineLevelType?
308304
else { return }
@@ -312,19 +308,19 @@ extension RecommendedRoutineView: SelectableItemTableViewDelegate {
312308
}
313309

314310
// MARK: FloatingMenuViewDelegate
315-
extension RecommendedRoutineView: FloatingMenuViewDelegate {
311+
extension RecommendedRoutineViewController: FloatingMenuViewDelegate {
316312
func floatingMenuDidTapRegisterRoutineButton(_ sender: FloatingMenuView) {
317313
toggleFloatingButton()
318-
guard let routineCreationViewModel = DIContainer.shared.resolve(type: RoutineCreationViewModel.self) else {
319-
fatalError("routineCreationViewModel 의존성이 등록되지 않았습니다.")
320-
}
314+
guard let routineCreationViewModel = DIContainer.shared.resolve(type: RoutineCreationViewModel.self)
315+
else { fatalError("routineCreationViewModel 의존성이 등록되지 않았습니다.") }
316+
321317
let routineCreationView = RoutineCreationView(viewModel: routineCreationViewModel)
322318
routineCreationView.hidesBottomBarWhenPushed = true
323319
self.navigationController?.pushViewController(routineCreationView, animated: true)
324320
}
325321
}
326322

327-
extension RecommendedRoutineView: RegisterEmotionButtonViewDelegate {
323+
extension RecommendedRoutineViewController: RegisterEmotionButtonViewDelegate {
328324
func registerEmotionButtonViewDidTapRegisterButton(_ sender: RegisterEmotionButtonView) {
329325
guard let emotionRegisterViewModel = DIContainer.shared.resolve(type: EmotionRegisterViewModel.self)
330326
else { fatalError("emotionRegisterViewModel 의존성이 등록되지 않았습니다.") }

0 commit comments

Comments
 (0)