77
88import Combine
99import Domain
10+ import Shared
1011import SnapKit
1112import UIKit
1213
@@ -26,19 +27,30 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
2627 static let recommendedRoutineStackViewBottomSpacing : CGFloat = 50
2728 static let routineCardHeight : CGFloat = 80
2829 static let registerEmotionButtonHeight : CGFloat = 52
30+ static let floatingButtonBottomSpacing : CGFloat = 19
31+ static let floatingButtonSize : CGFloat = 52
32+ static let floatingMenuBottomSpacing : CGFloat = 15
33+ static let floatingMenuHeight : CGFloat = 64
34+ static let floatingMenuWidth : CGFloat = 144
2935 }
3036
3137 private let categoryView = RoutineCategoryView ( )
3238 private let headerStackView = UIStackView ( )
3339 private let routineLabel = UILabel ( )
3440 private let levelButton = RoutineLevelButton ( )
3541 private let levelView = SelectableItemTableView < RoutineLevelType > ( items: RoutineLevelType . allCases. sorted ( by: { $0. id < $1. id } ) )
42+
3643 private let recommendedRoutineScrollView = UIScrollView ( )
3744 private let recommendedRoutineStackView = UIStackView ( )
3845 private var recommendedRoutineCards : [ Int : RecommendedRoutineCardView ] = [ : ]
3946 private let registerEmotionButton = RegisterEmotionButton ( )
40- private var cancellables : Set < AnyCancellable >
4147
48+ private var isShowingFloatinMenu : Bool = false
49+ private let dimmedView = UIView ( )
50+ private let floatingButton = FloatingButton ( )
51+ private let floatingMenu = FloatingMenuView ( )
52+
53+ private var cancellables : Set < AnyCancellable >
4254 public override init ( viewModel: RecommendedRoutineViewModel ) {
4355 cancellables = [ ]
4456 super. init ( viewModel: viewModel)
@@ -73,6 +85,20 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
7385
7486 recommendedRoutineStackView. axis = . vertical
7587 recommendedRoutineStackView. spacing = Layout . recommendedRoutineStackViewSpacing
88+
89+ floatingButton. addAction ( UIAction { [ weak self] _ in
90+ self ? . toggleFloatingButton ( )
91+ } , for: . touchUpInside)
92+
93+ floatingMenu. isHidden = true
94+ floatingMenu. delegate = self
95+
96+ dimmedView. isHidden = true
97+ dimmedView. backgroundColor = UIColor . black. withAlphaComponent ( 0.7 )
98+ dimmedView. alpha = 0
99+
100+ let tapGesture = UITapGestureRecognizer ( target: self , action: #selector( tappedDimmedView) )
101+ dimmedView. addGestureRecognizer ( tapGesture)
76102 }
77103
78104 public override func configureLayout( ) {
@@ -87,6 +113,10 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
87113 view. addSubview ( recommendedRoutineScrollView)
88114 recommendedRoutineScrollView. addSubview ( recommendedRoutineStackView)
89115
116+ view. addSubview ( dimmedView)
117+ view. addSubview ( floatingMenu)
118+ view. addSubview ( floatingButton)
119+
90120 categoryView. snp. makeConstraints { make in
91121 make. leading. equalTo ( safeArea)
92122 make. trailing. equalTo ( safeArea)
@@ -121,6 +151,23 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
121151 make. bottom. equalToSuperview ( ) . inset ( Layout . recommendedRoutineStackViewBottomSpacing)
122152 make. width. equalTo ( recommendedRoutineScrollView. snp. width)
123153 }
154+
155+ floatingButton. snp. makeConstraints { make in
156+ make. trailing. equalTo ( safeArea) . inset ( Layout . horizontalMargin)
157+ make. bottom. equalTo ( safeArea) . inset ( Layout . floatingButtonBottomSpacing)
158+ make. size. equalTo ( Layout . floatingButtonSize)
159+ }
160+
161+ floatingMenu. snp. makeConstraints { make in
162+ make. trailing. equalTo ( safeArea) . inset ( Layout . horizontalMargin)
163+ make. bottom. equalTo ( floatingButton. snp. top) . offset ( - Layout. floatingMenuBottomSpacing)
164+ make. height. equalTo ( Layout . floatingMenuHeight)
165+ make. width. equalTo ( Layout . floatingMenuWidth)
166+ }
167+
168+ dimmedView. snp. makeConstraints { make in
169+ make. edges. equalToSuperview ( )
170+ }
124171 }
125172
126173 public override func bind( ) {
@@ -162,6 +209,9 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
162209 }
163210
164211 private func showBottomSheet( ) {
212+ if isShowingFloatinMenu {
213+ toggleFloatingButton ( )
214+ }
165215 presentCustomBottomSheet ( contentViewController: levelView, maxHeight: Layout . bottomSheetHeight)
166216 }
167217
@@ -173,6 +223,23 @@ final class RecommendedRoutineView: BaseViewController<RecommendedRoutineViewMod
173223 make. height. equalTo ( Layout . registerEmotionButtonHeight)
174224 }
175225 }
226+
227+ private func toggleFloatingButton( ) {
228+ floatingButton. toggle ( )
229+ isShowingFloatinMenu. toggle ( )
230+
231+ floatingMenu. isHidden = !isShowingFloatinMenu
232+ dimmedView. isHidden = !isShowingFloatinMenu
233+
234+ UIView . animate ( withDuration: 0.2 , delay: 0 , options: [ . curveEaseOut] ) {
235+ self . dimmedView. alpha = self . isShowingFloatinMenu ? 1 : 0
236+ self . floatingMenu. alpha = self . isShowingFloatinMenu ? 1 : 0
237+ }
238+ }
239+
240+ @objc private func tappedDimmedView( ) {
241+ toggleFloatingButton ( )
242+ }
176243}
177244
178245// MARK: RoutineCategoryViewDelegate
@@ -198,3 +265,15 @@ extension RecommendedRoutineView: SelectableItemTableViewDelegate {
198265 levelButton. updateButton ( level: didSelectLevel)
199266 }
200267}
268+
269+ // MARK: FloatingMenuViewDelegate
270+ extension RecommendedRoutineView : FloatingMenuViewDelegate {
271+ func floatingMenuDidTapRegisterRoutineButton( _ sender: FloatingMenuView ) {
272+ toggleFloatingButton ( )
273+ guard let routineCreationViewModel = DIContainer . shared. resolve ( type: RoutineCreationViewModel . self) else {
274+ fatalError ( " routineCreationViewModel 의존성이 등록되지 않았습니다. " )
275+ }
276+ let routineCreationView = RoutineCreationView ( viewModel: routineCreationViewModel)
277+ self . navigationController? . pushViewController ( routineCreationView, animated: true )
278+ }
279+ }
0 commit comments