diff --git a/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Contents.json b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Colors.xcassets/Green.colorset/Contents.json b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Green10.colorset/Contents.json similarity index 100% rename from Projects/Presentation/Resources/Colors.xcassets/Green.colorset/Contents.json rename to Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Green10.colorset/Contents.json diff --git a/Projects/Presentation/Resources/Colors.xcassets/Pink.colorset/Contents.json b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Pink10.colorset/Contents.json similarity index 100% rename from Projects/Presentation/Resources/Colors.xcassets/Pink.colorset/Contents.json rename to Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Pink10.colorset/Contents.json diff --git a/Projects/Presentation/Resources/Colors.xcassets/Purple.colorset/Contents.json b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Purple10.colorset/Contents.json similarity index 100% rename from Projects/Presentation/Resources/Colors.xcassets/Purple.colorset/Contents.json rename to Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Purple10.colorset/Contents.json diff --git a/Projects/Presentation/Resources/Colors.xcassets/Skyblue.colorset/Contents.json b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Skyblue10.colorset/Contents.json similarity index 100% rename from Projects/Presentation/Resources/Colors.xcassets/Skyblue.colorset/Contents.json rename to Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Skyblue10.colorset/Contents.json diff --git a/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Yellow10.colorset/Contents.json b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Yellow10.colorset/Contents.json new file mode 100644 index 00000000..739956a9 --- /dev/null +++ b/Projects/Presentation/Resources/Colors.xcassets/RoutineCategory/Yellow10.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xC7", + "green" : "0xF5", + "red" : "0xFF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/Contents.json b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/Contents.json b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/Contents.json new file mode 100644 index 00000000..c25c4eaa --- /dev/null +++ b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "connect_icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "connect_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "connect_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon.png new file mode 100644 index 00000000..2f49ac38 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon@2x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon@2x.png new file mode 100644 index 00000000..31eaaa25 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon@2x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon@3x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon@3x.png new file mode 100644 index 00000000..5d2bb4ca Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/connect_icon.imageset/connect_icon@3x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/Contents.json b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/Contents.json new file mode 100644 index 00000000..5ac31698 --- /dev/null +++ b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "grow_icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "grow_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "grow_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon.png new file mode 100644 index 00000000..7cf95e3e Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon@2x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon@2x.png new file mode 100644 index 00000000..54ea18a1 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon@2x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon@3x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon@3x.png new file mode 100644 index 00000000..b1854e70 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/grow_icon.imageset/grow_icon@3x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/Contents.json b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/Contents.json new file mode 100644 index 00000000..87505c4f --- /dev/null +++ b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "outside_icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "outside_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "outside_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon.png new file mode 100644 index 00000000..c4ffb376 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon@2x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon@2x.png new file mode 100644 index 00000000..04c58776 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon@2x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon@3x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon@3x.png new file mode 100644 index 00000000..d3e5853f Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/outside_icon.imageset/outside_icon@3x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/Contents.json b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/Contents.json new file mode 100644 index 00000000..dffba124 --- /dev/null +++ b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "rest_icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "rest_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "rest_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon.png new file mode 100644 index 00000000..ee2d928c Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon@2x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon@2x.png new file mode 100644 index 00000000..4e6d4f51 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon@2x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon@3x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon@3x.png new file mode 100644 index 00000000..e986873a Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/rest_icon.imageset/rest_icon@3x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/Contents.json b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/Contents.json new file mode 100644 index 00000000..985657aa --- /dev/null +++ b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "shine_icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "shine_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "shine_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon.png new file mode 100644 index 00000000..5b10221b Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon@2x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon@2x.png new file mode 100644 index 00000000..05eafe1a Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon@2x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon@3x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon@3x.png new file mode 100644 index 00000000..c52a4aa8 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/shine_icon.imageset/shine_icon@3x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/Contents.json b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/Contents.json new file mode 100644 index 00000000..862e7973 --- /dev/null +++ b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "wakeup_icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "wakeup_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "wakeup_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon.png new file mode 100644 index 00000000..7dccdaff Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon@2x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon@2x.png new file mode 100644 index 00000000..31c01dc5 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon@2x.png differ diff --git a/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon@3x.png b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon@3x.png new file mode 100644 index 00000000..5e1a56e2 Binary files /dev/null and b/Projects/Presentation/Resources/Images.xcassets/RoutineCategory/wakeup_icon.imageset/wakeup_icon@3x.png differ diff --git a/Projects/Presentation/Sources/Common/Component/RoutineCardView.swift b/Projects/Presentation/Sources/Common/Component/RoutineCardView.swift new file mode 100644 index 00000000..36461d54 --- /dev/null +++ b/Projects/Presentation/Sources/Common/Component/RoutineCardView.swift @@ -0,0 +1,166 @@ +// +// RoutineCardView.swift +// Presentation +// +// Created by 최정인 on 8/16/25. +// + +import Domain +import SnapKit +import UIKit + +final class RoutineCardView: UIView { + private enum Layout { + static let horizontalMargin: CGFloat = 16 + static let cornerRadius: CGFloat = 12 + static let headerInfoStackViewSpacing: CGFloat = 10 + static let headerInfoStackViewTopSpacing: CGFloat = 14 + static let subRoutineStackViewSpacing: CGFloat = 2 + static let subRoutineStackViewTopSpacing: CGFloat = 10 + static let subRoutineStackViewBottomSpacing: CGFloat = 14 + static let subRoutineLabelHeight: CGFloat = 20 + static let categoryIconSize: CGFloat = 32 + static let plusImageSize: CGFloat = 24 + static let plusButtonTopSpacing: CGFloat = 14 + static let plusButtonTrailingSpacing: CGFloat = 7 + static let plusButtonSize: CGFloat = 32 + static let grayLineTopSpacing: CGFloat = 10 + static let grayLineHeight: CGFloat = 1 + } + + private let headerInfoStackView = UIStackView() + private let categoryIconView = RoutineCategoryIcon(routineCategory: .connection) + private let titleLabel = UILabel() + private let editButton = UIButton() + private let deleteButton = UIButton() + private let plusButton = UIButton() + private let grayLine = UIView() + private let subRoutineLabel = UILabel() + private let subRoutineStackView = UIStackView() + + init() { + super.init(frame: .zero) + configureAttribute() + configureLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configureAttribute() { + backgroundColor = .white + layer.masksToBounds = true + layer.cornerRadius = Layout.cornerRadius + + headerInfoStackView.axis = .horizontal + headerInfoStackView.spacing = Layout.headerInfoStackViewSpacing + + titleLabel.text = "개운하게 일어나기" + titleLabel.font = BitnagilFont(style: .body1, weight: .semiBold).font + titleLabel.textColor = BitnagilColor.gray10 + + let plusImage = BitnagilIcon.plusIcon? + .resizeAspectFit(to: CGSize(width: Layout.plusImageSize, height: Layout.plusImageSize)) + plusButton.setImage(plusImage, for: .normal) + plusButton.tintColor = BitnagilColor.gray10 + + grayLine.backgroundColor = BitnagilColor.gray97 + + subRoutineStackView.axis = .vertical + subRoutineStackView.spacing = Layout.subRoutineStackViewSpacing + + subRoutineLabel.text = "세부 루틴" + subRoutineLabel.font = BitnagilFont(style: .body2, weight: .medium).font + subRoutineLabel.textColor = BitnagilColor.gray40 + subRoutineLabel.snp.makeConstraints { make in + make.height.equalTo(Layout.subRoutineLabelHeight) + } + subRoutineStackView.addArrangedSubview(subRoutineLabel) + + ["물 마시기", "물 마시기", "물 마시기"].forEach { + let subRoutineTitleLabel = UILabel() + subRoutineTitleLabel.text = "• \($0)" + subRoutineTitleLabel.font = BitnagilFont(style: .body2, weight: .medium).font + subRoutineTitleLabel.textColor = BitnagilColor.gray40 + subRoutineTitleLabel.snp.makeConstraints { make in + make.height.equalTo(Layout.subRoutineLabelHeight) + } + subRoutineStackView.addArrangedSubview(subRoutineTitleLabel) + } + } + + private func configureLayout() { + [categoryIconView, titleLabel].forEach { + headerInfoStackView.addArrangedSubview($0) + } + addSubview(headerInfoStackView) + addSubview(plusButton) + addSubview(grayLine) + addSubview(subRoutineStackView) + + categoryIconView.snp.makeConstraints { make in + make.size.equalTo(Layout.categoryIconSize) + } + + headerInfoStackView.snp.makeConstraints { make in + make.top.equalToSuperview().offset(Layout.headerInfoStackViewTopSpacing) + make.leading.equalToSuperview().offset(Layout.horizontalMargin) + } + + plusButton.snp.makeConstraints { make in + make.top.equalToSuperview().offset(Layout.plusButtonTopSpacing) + make.trailing.equalToSuperview().inset(Layout.plusButtonTrailingSpacing) + make.size.equalTo(Layout.plusButtonSize) + } + + grayLine.snp.makeConstraints { make in + make.top.equalTo(headerInfoStackView.snp.bottom).offset(Layout.grayLineTopSpacing) + make.leading.equalToSuperview().offset(Layout.horizontalMargin) + make.trailing.equalToSuperview().inset(Layout.horizontalMargin) + make.height.equalTo(Layout.grayLineHeight) + } + + subRoutineStackView.snp.makeConstraints { make in + make.top.equalTo(grayLine.snp.bottom).offset(Layout.subRoutineStackViewTopSpacing) + make.leading.equalToSuperview().offset(Layout.horizontalMargin) + make.trailing.equalToSuperview().inset(Layout.horizontalMargin) + make.bottom.equalToSuperview().inset(Layout.subRoutineStackViewBottomSpacing) + } + } +} + +fileprivate class RoutineCategoryIcon: UIView { + private enum Layout { + static let cornerRadius: CGFloat = 3.76 + static let iconSize: CGFloat = 24 + } + + private let routineCategoryIcon = UIImageView() + private let routineCategory: RoutineCategoryType + init(routineCategory: RoutineCategoryType) { + self.routineCategory = routineCategory + super.init(frame: .zero) + configureAttribute() + configureLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configureAttribute() { + layer.masksToBounds = true + layer.cornerRadius = Layout.cornerRadius + backgroundColor = routineCategory.iconBackgroundColor ?? BitnagilColor.yellow10 + routineCategoryIcon.image = routineCategory.iconImage ?? BitnagilIcon.shineIcon + } + + private func configureLayout() { + addSubview(routineCategoryIcon) + routineCategoryIcon.snp.makeConstraints { make in + make.size.equalTo(Layout.iconSize) + make.center.equalToSuperview() + } + } +} diff --git a/Projects/Presentation/Sources/Common/Component/SelectableItemCell.swift b/Projects/Presentation/Sources/Common/Component/SelectableItemCell.swift index 21766370..649db925 100644 --- a/Projects/Presentation/Sources/Common/Component/SelectableItemCell.swift +++ b/Projects/Presentation/Sources/Common/Component/SelectableItemCell.swift @@ -5,6 +5,7 @@ // Created by 최정인 on 7/24/25. // +import SnapKit import UIKit final class SelectableItemCell: UITableViewCell { @@ -28,7 +29,7 @@ final class SelectableItemCell: UITableViewCell { private func configureAttribute() { titleLabel.font = BitnagilFont(style: .body1, weight: .regular).font - titleLabel.textColor = .black + titleLabel.textColor = BitnagilColor.gray10 let checkImage = BitnagilIcon.checkIcon? .resizeAspectFit(to: CGSize(width: Layout.checkIconSize, height: Layout.checkIconSize))? @@ -54,7 +55,24 @@ final class SelectableItemCell: UITableViewCell { } func configureCell(item: SelectableItem, isSelected: Bool) { - titleLabel.text = item.title checkIcon.isHidden = !isSelected + + guard let displayName = item.displayName else { + titleLabel.text = item.description + return + } + let attributedString = NSMutableAttributedString(string: item.description) + attributedString.addAttribute( + .font, + value: BitnagilFont(style: .body1, weight: .regular).font, + range: NSRange(location: 0, length: item.description.count)) + + if let range = item.description.range(of: displayName) { + let nsRange = NSRange(range, in: item.description) + attributedString.addAttributes([ + .font: BitnagilFont(style: .body1, weight: .semiBold).font + ], range: nsRange) + } + titleLabel.attributedText = attributedString } } diff --git a/Projects/Presentation/Sources/Common/DesignSystem/BitnagilColor.swift b/Projects/Presentation/Sources/Common/DesignSystem/BitnagilColor.swift index 99d3d01e..1b2318cb 100644 --- a/Projects/Presentation/Sources/Common/DesignSystem/BitnagilColor.swift +++ b/Projects/Presentation/Sources/Common/DesignSystem/BitnagilColor.swift @@ -34,17 +34,12 @@ enum BitnagilColor { static let gray98 = UIColor(named: "Gray98", in: bundle, compatibleWith: nil) static let gray99 = UIColor(named: "Gray99", in: bundle, compatibleWith: nil) - // MARK: - Green Color - static let green = UIColor(named: "Green", in: bundle, compatibleWith: nil) - - // MARK: - Pink Color - static let pink = UIColor(named: "Pink", in: bundle, compatibleWith: nil) - - // MARK: - Purple Color - static let purple = UIColor(named: "Purple", in: bundle, compatibleWith: nil) - - // MARK: - Skyblue Color - static let skyblue = UIColor(named: "Skyblue", in: bundle, compatibleWith: nil) + // MARK: - Category Color + static let green10 = UIColor(named: "Green10", in: bundle, compatibleWith: nil) + static let pink10 = UIColor(named: "Pink10", in: bundle, compatibleWith: nil) + static let purple10 = UIColor(named: "Purple10", in: bundle, compatibleWith: nil) + static let skyblue10 = UIColor(named: "Skyblue10", in: bundle, compatibleWith: nil) + static let yellow10 = UIColor(named: "Yellow10", in: bundle, compatibleWith: nil) // MARK: - Orange Colors static let orange25 = UIColor(named: "Orange25", in: bundle, compatibleWith: nil) @@ -77,10 +72,6 @@ enum BitnagilColor { static let navy800 = UIColor(named: "Navy800", in: bundle, compatibleWith: nil) static let navy900 = UIColor(named: "Navy900", in: bundle, compatibleWith: nil) - // MARK: - Green Color - - // MARK: - - // MARK: - LightBlue Colors static let lightBlue50 = UIColor(named: "LightBlue50", in: bundle, compatibleWith: nil) static let lightBlue75 = UIColor(named: "LightBlue75", in: bundle, compatibleWith: nil) diff --git a/Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift b/Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift index 64a713b1..4cac7326 100644 --- a/Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift +++ b/Projects/Presentation/Sources/Common/DesignSystem/BitnagilIcon.swift @@ -51,6 +51,14 @@ enum BitnagilIcon { static let divideLineIcon = UIImage(named: "divide_line_icon", in: bundle, with: nil) static let clearIcon = UIImage(named: "clear_icon", in: bundle, with: nil) + // MARK: - Routine Category Icons + static let wakeupIcon = UIImage(named: "wakeup_icon", in: bundle, with: nil) + static let shineIcon = UIImage(named: "shine_icon", in: bundle, with: nil) + static let growIcon = UIImage(named: "grow_icon", in: bundle, with: nil) + static let outsideIcon = UIImage(named: "outside_icon", in: bundle, with: nil) + static let connectIcon = UIImage(named: "connect_icon", in: bundle, with: nil) + static let restIcon = UIImage(named: "rest_icon", in: bundle, with: nil) + // MARK: - Tab Bar Icons static let homeIcon = UIImage(named: "home_fill_icon", in: bundle, with: nil) static let recommendIcon = UIImage(named: "recommend_fill_icon",in: bundle, with: nil) @@ -61,6 +69,7 @@ enum BitnagilIcon { // MARK: - Mypage Icons static let settingIcon = UIImage(named: "setting_icon", in: bundle, with: nil) static let exclamationFilledIcon = UIImage(named: "exclamation_filled_icon", in: bundle, with: nil) + // MARK: - Routine Creation Icons static let asteriskIcon = UIImage(named: "asterisk_icon", in: bundle, with: nil) static let deleteIcon = UIImage(named: "delete_icon", in: bundle, with: nil) diff --git a/Projects/Presentation/Sources/Common/Extension/UIViewController+.swift b/Projects/Presentation/Sources/Common/Extension/UIViewController+.swift index 8844bb4b..1bb97ed1 100644 --- a/Projects/Presentation/Sources/Common/Extension/UIViewController+.swift +++ b/Projects/Presentation/Sources/Common/Extension/UIViewController+.swift @@ -16,10 +16,11 @@ extension UIViewController { case withProgressBar(step: Int) // 백버튼 + progress } - func configureCustomNavigationBar(navigationBarStyle: NavigationBarStyle) { + func configureCustomNavigationBar(navigationBarStyle: NavigationBarStyle, backgroundColor: UIColor? = .white) { let safeArea = self.view.safeAreaLayoutGuide let navigationBar: UIView = customNavigationBar(navigationBarStyle: navigationBarStyle) + navigationBar.backgroundColor = backgroundColor self.view.addSubview(navigationBar) navigationBar.snp.makeConstraints { make in make.top.horizontalEdges.equalTo(safeArea) diff --git a/Projects/Presentation/Sources/Common/Protocol/SelectableItem.swift b/Projects/Presentation/Sources/Common/Protocol/SelectableItem.swift index a930a760..d43adc41 100644 --- a/Projects/Presentation/Sources/Common/Protocol/SelectableItem.swift +++ b/Projects/Presentation/Sources/Common/Protocol/SelectableItem.swift @@ -7,5 +7,6 @@ protocol SelectableItem { var id: Int { get } - var title: String { get } + var displayName: String? { get } + var description: String { get } } diff --git a/Projects/Presentation/Sources/Common/View/TabBarView.swift b/Projects/Presentation/Sources/Common/View/TabBarView.swift index 1f6cdcd4..2616c419 100644 --- a/Projects/Presentation/Sources/Common/View/TabBarView.swift +++ b/Projects/Presentation/Sources/Common/View/TabBarView.swift @@ -49,7 +49,7 @@ final public class TabBarView: UITabBarController { else { fatalError("mypageViewModel 의존성이 등록되지 않았습니다.") } let homeView = HomeView(viewModel: homeViewModel) - let recommendView = RecommendedRoutineView(viewModel: recommendedRoutineViewModel) + let recommendView = RecommendedRoutineViewController(viewModel: recommendedRoutineViewModel) let mypageView = MypageView(viewModel: mypageViewModel) homeView.tabBarItem = UITabBarItem( diff --git a/Projects/Presentation/Sources/Home/Model/RoutineSortType.swift b/Projects/Presentation/Sources/Home/Model/RoutineSortType.swift deleted file mode 100644 index b6013036..00000000 --- a/Projects/Presentation/Sources/Home/Model/RoutineSortType.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// RoutineSortType.swift -// Presentation -// -// Created by 최정인 on 7/24/25. -// - -enum RoutineSortType: SelectableItem, CaseIterable { - case complete - case incomplete - - var id: Int { - switch self { - case .complete: 1 - case .incomplete: 2 - } - } - - var title: String { - switch self { - case .complete: "완료한 루틴 순" - case .incomplete: "미완료한 루틴 순" - } - } -} diff --git a/Projects/Presentation/Sources/Home/View/HomeView.swift b/Projects/Presentation/Sources/Home/View/HomeView.swift index 710a8944..c380a656 100644 --- a/Projects/Presentation/Sources/Home/View/HomeView.swift +++ b/Projects/Presentation/Sources/Home/View/HomeView.swift @@ -573,16 +573,6 @@ extension HomeView: RoutineViewDelegate { } } -// MARK: SelectableItemTableViewDelegate -extension HomeView: SelectableItemTableViewDelegate { - func selectableItemTableView(_ sender: SelectableItemTableView, didSelectItem: T?) { - guard let sortType = didSelectItem as? RoutineSortType? - else { return } - - viewModel.action(input: .selectRoutineSortType(routineSortType: sortType)) - } -} - // MARK: WeekViewDelegate extension HomeView: WeekViewDelegate { func weekView(_ sender: WeekView, didSelectDate date: Date) { diff --git a/Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift b/Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift index e8e3172e..28db79b6 100644 --- a/Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift +++ b/Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift @@ -21,7 +21,6 @@ final class HomeViewModel: ViewModel { case deleteAllRoutine case updateRoutineCompletion(updatedRoutine: Routine) case refreshSelectedDateRoutine - case selectRoutineSortType(routineSortType: RoutineSortType?) } struct Output { @@ -44,7 +43,6 @@ final class HomeViewModel: ViewModel { private let selectedRoutineSubject = CurrentValueSubject(nil) private let deleteRoutineResultSubject = PassthroughSubject() private let updateRoutineCompletionResultSubject = PassthroughSubject() - private let routineSortTypeSubject = CurrentValueSubject(nil) private let calendar = Calendar.current private let today = Date() @@ -104,9 +102,6 @@ final class HomeViewModel: ViewModel { case .refreshSelectedDateRoutine: fetchDailyRoutine(for: selectedDateSubject.value) - - case .selectRoutineSortType(let routineSortType): - sortRoutine(routineSortType: routineSortType) } } @@ -309,19 +304,4 @@ final class HomeViewModel: ViewModel { } } } - - private func sortRoutine(routineSortType: RoutineSortType?) { - let dailyRoutines = routinesSubject.value - var sortedRoutines: [MainRoutine] - switch routineSortType { - case .complete: - sortedRoutines = dailyRoutines.sorted(by: { $0.isDone && !$1.isDone}) - case .incomplete: - sortedRoutines = dailyRoutines.sorted(by: { !$0.isDone && $1.isDone}) - case nil: - let dateKey = selectedDateSubject.value.convertToString(dateType: .yearMonthDate) - sortedRoutines = self.routines[dateKey] ?? [] - } - routinesSubject.send(sortedRoutines) - } } diff --git a/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineCategoryType.swift b/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineCategoryType+.swift similarity index 50% rename from Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineCategoryType.swift rename to Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineCategoryType+.swift index b1afcbf7..effff58b 100644 --- a/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineCategoryType.swift +++ b/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineCategoryType+.swift @@ -6,6 +6,7 @@ // import Domain +import UIKit extension RoutineCategoryType { var id: Int { @@ -31,4 +32,26 @@ extension RoutineCategoryType { case .growth: "성장해요" } } + + var iconImage: UIImage? { + switch self { + case .recommendation: nil + case .outdoor, .outdoorReport: BitnagilIcon.outsideIcon + case .wakeup: BitnagilIcon.wakeupIcon + case .connection: BitnagilIcon.connectIcon + case .rest: BitnagilIcon.restIcon + case .growth: BitnagilIcon.growIcon + } + } + + var iconBackgroundColor: UIColor? { + switch self { + case .recommendation: nil + case .outdoor, .outdoorReport: BitnagilColor.skyblue10 + case .wakeup: BitnagilColor.orange25 + case .connection: BitnagilColor.purple10 + case .rest: BitnagilColor.green10 + case .growth: BitnagilColor.pink10 + } + } } diff --git a/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineLevelType+.swift b/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineLevelType+.swift new file mode 100644 index 00000000..4e5535e7 --- /dev/null +++ b/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineLevelType+.swift @@ -0,0 +1,34 @@ +// +// RoutineLevelType.swift +// Presentation +// +// Created by 최정인 on 7/17/25. +// + +import Domain + +extension RoutineLevelType: SelectableItem { + var id: Int { + switch self { + case .easy: 1 + case .normal: 2 + case .hard: 3 + } + } + + var displayName: String? { + switch self { + case .easy: "난이도 하" + case .normal: "난이도 중" + case .hard: "난이도 상" + } + } + + var description: String { + switch self { + case .easy: "\(self.displayName ?? "") | 가볍게 할 수 있어요" + case .normal: "\(self.displayName ?? "") | 조금 신경써서 할 수 있어요" + case .hard: "\(self.displayName ?? "") | 의지를 다 잡고 할 수 있어요" + } + } +} diff --git a/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineLevelType.swift b/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineLevelType.swift deleted file mode 100644 index 0080bfe4..00000000 --- a/Projects/Presentation/Sources/RecommendedRoutine/Model/RoutineLevelType.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// RoutineLevelType.swift -// Presentation -// -// Created by 최정인 on 7/17/25. -// - -import Domain - -extension RoutineLevelType: SelectableItem { - var id: Int { - switch self { - case .easy: 1 - case .normal: 2 - case .hard: 3 - } - } - - var title: String { - switch self { - case .easy: "가볍게 할 수 있어요" - case .normal: "조금 신경써서 할 수 있어요" - case .hard: "의지를 다 잡고 할 수 있어요" - } - } -} diff --git a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RecommendedRoutineEmptyView.swift b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RecommendedRoutineEmptyView.swift new file mode 100644 index 00000000..bac5f519 --- /dev/null +++ b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RecommendedRoutineEmptyView.swift @@ -0,0 +1,59 @@ +// +// RecommendedRoutineEmptyView.swift +// Presentation +// +// Created by 최정인 on 8/17/25. +// + +import SnapKit +import UIKit + +final class RecommendedRoutineEmptyView: UIView { + private let stackView = UIStackView() + private let mainLabel = UILabel() + private let subLabel = UILabel() + + init() { + super.init(frame: .zero) + configureAttribute() + configureLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configureAttribute() { + stackView.axis = .vertical + stackView.spacing = 2 + + mainLabel.text = "해당 난이도 루틴이 없어요" + mainLabel.font = BitnagilFont(style: .subtitle1, weight: .semiBold).font + mainLabel.textColor = BitnagilColor.gray30 + mainLabel.textAlignment = .center + + subLabel.text = "다른 난이도를 살펴보거나 루틴을 추가해 보세요." + subLabel.font = BitnagilFont(style: .body2, weight: .regular).font + subLabel.textColor = BitnagilColor.gray70 + subLabel.textAlignment = .center + } + + private func configureLayout() { + addSubview(stackView) + [mainLabel, subLabel].forEach { + stackView.addArrangedSubview($0) + } + + stackView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + mainLabel.snp.makeConstraints { make in + make.height.equalTo(28) + } + + subLabel.snp.makeConstraints { make in + make.height.equalTo(20) + } + } +} diff --git a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RegisterEmotionButton.swift b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RegisterEmotionButton.swift deleted file mode 100644 index 24118571..00000000 --- a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RegisterEmotionButton.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// RegisterEmotionButton.swift -// Presentation -// -// Created by 최정인 on 7/12/25. -// - -import SnapKit -import UIKit - -final class RegisterEmotionButton: UIButton { - - private enum Layout { - static let borderWith: CGFloat = 1 - static let cornerRadius: CGFloat = 12 - static let plusIconImageSize: CGFloat = 10 - static let plusIconSize: CGFloat = 20 - static let plusIconLeadingSpacing: CGFloat = 24 - static let buttonLabelLeadingSpacing: CGFloat = 10 - } - - private let plusIcon = UIImageView() - private let buttonLabel = UILabel() - - override init(frame: CGRect) { - super.init(frame: frame) - configureAttribute() - configureLayout() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func configureAttribute() { - layer.borderWidth = Layout.borderWith - layer.cornerRadius = Layout.cornerRadius - layer.borderColor = BitnagilColor.navy100?.cgColor - - plusIcon.contentMode = .center - plusIcon.image = BitnagilIcon.plusIcon? - .resizeAspectFit(to: CGSize(width: Layout.plusIconImageSize, height: Layout.plusIconImageSize))? - .withRenderingMode(.alwaysTemplate) - plusIcon.tintColor = BitnagilColor.navy400 - - buttonLabel.text = "오늘의 감정 루틴 추천받기" - buttonLabel.font = BitnagilFont(style: .body2, weight: .medium).font - buttonLabel.textColor = BitnagilColor.navy400 - } - - private func configureLayout() { - addSubview(plusIcon) - addSubview(buttonLabel) - - plusIcon.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalToSuperview().offset(Layout.plusIconLeadingSpacing) - make.size.equalTo(Layout.plusIconSize) - } - - buttonLabel.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalTo(plusIcon.snp.trailing).offset(Layout.buttonLabelLeadingSpacing) - } - } -} diff --git a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RegisterEmotionButtonView.swift b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RegisterEmotionButtonView.swift new file mode 100644 index 00000000..378b1c13 --- /dev/null +++ b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RegisterEmotionButtonView.swift @@ -0,0 +1,93 @@ +// +// RegisterEmotionButtonView.swift +// Presentation +// +// Created by 최정인 on 8/15/25. +// + +import SnapKit +import UIKit + +protocol RegisterEmotionButtonViewDelegate: AnyObject { + func registerEmotionButtonViewDidTapRegisterButton(_ sender: RegisterEmotionButtonView) +} + +final class RegisterEmotionButtonView: UIView { + private enum Layout { + static let cornerRadius: CGFloat = 12 + static let emotionOrbImageViewLeadingSpacing: CGFloat = 13 + static let emotionOrbImageViewSize: CGFloat = 34 + static let registerEmotionLabelLeadingSpacing: CGFloat = 5 + static let registerEmotionButtonCornerRadius: CGFloat = 8 + static let registerEmotionButtonTrailingSpacing: CGFloat = 19 + static let registerEmotionButtonWidth: CGFloat = 74 + static let registerEmotionButtonHeight: CGFloat = 38 + } + + private let emotionOrbImageView = UIImageView() + private let registerEmotionLabel = UILabel() + private let registerEmotionButton = UIButton() + weak var delegate: RegisterEmotionButtonViewDelegate? + + init() { + super.init(frame: .zero) + configureAttribute() + configureLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configureAttribute() { + emotionOrbImageView.image = BitnagilGraphic.defaultEmotionGraphic + emotionOrbImageView.contentMode = .scaleAspectFit + + registerEmotionLabel.text = "내 기분에 맞는 루틴 추천받기" + registerEmotionLabel.font = BitnagilFont(style: .body2, weight: .semiBold).font + registerEmotionLabel.textColor = .white + + var buttonConfiguration = UIButton.Configuration.filled() + buttonConfiguration.baseBackgroundColor = BitnagilColor.orange500 + buttonConfiguration.background.cornerRadius = Layout.registerEmotionButtonCornerRadius + buttonConfiguration.attributedTitle = AttributedString( + "추천받기", + attributes: .init([.font: BitnagilFont(style: .caption1, weight: .semiBold).font])) + buttonConfiguration.baseForegroundColor = .white + registerEmotionButton.configuration = buttonConfiguration + registerEmotionButton.addAction( + UIAction { [weak self] _ in + guard let self else { return } + self.delegate?.registerEmotionButtonViewDidTapRegisterButton(self) + }, + for: .touchUpInside) + } + + private func configureLayout() { + backgroundColor = BitnagilColor.gray10 + layer.masksToBounds = true + layer.cornerRadius = Layout.cornerRadius + + [emotionOrbImageView, registerEmotionLabel, registerEmotionButton].forEach { + addSubview($0) + } + + emotionOrbImageView.snp.makeConstraints { make in + make.leading.equalToSuperview().offset(Layout.emotionOrbImageViewLeadingSpacing) + make.centerY.equalToSuperview() + make.size.equalTo(Layout.emotionOrbImageViewSize) + } + + registerEmotionLabel.snp.makeConstraints { make in + make.leading.equalTo(emotionOrbImageView.snp.trailing).offset(Layout.registerEmotionLabelLeadingSpacing) + make.centerY.equalToSuperview() + } + + registerEmotionButton.snp.makeConstraints { make in + make.trailing.equalToSuperview().inset(Layout.registerEmotionButtonTrailingSpacing) + make.centerY.equalToSuperview() + make.width.equalTo(Layout.registerEmotionButtonWidth) + make.height.equalTo(Layout.registerEmotionButtonHeight) + } + } +} diff --git a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineCategoryButton.swift b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineCategoryButton.swift index a7b30b25..81cd2c78 100644 --- a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineCategoryButton.swift +++ b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineCategoryButton.swift @@ -10,7 +10,6 @@ import SnapKit import UIKit final class RoutineCategoryButton: UIButton { - private let buttonHeight: CGFloat = 36 private let routineCategory: RoutineCategoryType private let categoryLabel = UILabel() @@ -33,11 +32,11 @@ final class RoutineCategoryButton: UIButton { } private func configureAttribute() { - backgroundColor = BitnagilColor.gray99 + backgroundColor = .white categoryLabel.text = routineCategory.title - categoryLabel.font = BitnagilFont(style: .caption1, weight: .regular).font - categoryLabel.textColor = BitnagilColor.navy100 + categoryLabel.font = BitnagilFont(style: .caption1, weight: .medium).font + categoryLabel.textColor = BitnagilColor.gray60 } private func configureLayout() { @@ -52,11 +51,11 @@ final class RoutineCategoryButton: UIButton { private func updateButtonAttribute() { let semiBoldFont = BitnagilFont(style: .caption1, weight: .semiBold).font - let regularFont = BitnagilFont(style: .caption1, weight: .regular).font + let mediumFont = BitnagilFont(style: .caption1, weight: .medium).font - backgroundColor = isChecked ? BitnagilColor.navy500 : BitnagilColor.gray99 - categoryLabel.font = isChecked ? semiBoldFont : regularFont - categoryLabel.textColor = isChecked ? .white : BitnagilColor.navy100 + backgroundColor = isChecked ? BitnagilColor.gray10 : .white + categoryLabel.font = isChecked ? semiBoldFont : mediumFont + categoryLabel.textColor = isChecked ? .white : BitnagilColor.gray60 } func updateButtonState(isChecked: Bool) { diff --git a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineLevelButton.swift b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineLevelButton.swift index b34e3023..c8c110f9 100644 --- a/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineLevelButton.swift +++ b/Projects/Presentation/Sources/RecommendedRoutine/View/Component/RoutineLevelButton.swift @@ -9,7 +9,6 @@ import Domain import UIKit final class RoutineLevelButton: UIButton { - private enum Layout { static let stackViewSpacing: CGFloat = 5 static let buttonLabelHeight: CGFloat = 20 @@ -42,16 +41,16 @@ final class RoutineLevelButton: UIButton { stackView.axis = .horizontal stackView.spacing = Layout.stackViewSpacing - buttonLabel.text = level?.title ?? "난이도 선택" + buttonLabel.text = level?.displayName ?? "난이도 선택" buttonLabel.font = BitnagilFont(style: .body2, weight: .medium).font - buttonLabel.textColor = BitnagilColor.gray60 + buttonLabel.textColor = BitnagilColor.gray40 chevronIcon.image = BitnagilIcon .chevronIcon(direction: .down)? .resizeAspectFit(to: CGSize(width: Layout.chevronImageSize, height: Layout.chevronImageSize))? .withRenderingMode(.alwaysTemplate) chevronIcon.contentMode = .center - chevronIcon.tintColor = BitnagilColor.gray60 + chevronIcon.tintColor = BitnagilColor.gray40 } private func configureLayout() { @@ -74,7 +73,7 @@ final class RoutineLevelButton: UIButton { } private func updateButtonLabel() { - buttonLabel.text = level?.title ?? "난이도 선택" + buttonLabel.text = level?.displayName ?? "난이도 선택" } func updateButton(level: RoutineLevelType?) { diff --git a/Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineView.swift b/Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineViewController.swift similarity index 74% rename from Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineView.swift rename to Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineViewController.swift index 76fb1886..57243647 100644 --- a/Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineView.swift +++ b/Projects/Presentation/Sources/RecommendedRoutine/View/RecommendedRoutineViewController.swift @@ -1,5 +1,5 @@ // -// RecommendedRoutineView.swift +// RecommendedRoutineViewController.swift // Presentation // // Created by 최정인 on 7/12/25. @@ -11,22 +11,23 @@ import Shared import SnapKit import UIKit -final class RecommendedRoutineView: BaseViewController { - +final class RecommendedRoutineViewController: BaseViewController { private enum Layout { static let horizontalMargin: CGFloat = 20 static let bottomSheetHeight: CGFloat = 226 - static let categoryViewTopSpacing: CGFloat = 16 + static let categoryViewTopSpacing: CGFloat = 70 static let categoryViewHeight: CGFloat = 36 static let headerStackViewTrailingSpacing: CGFloat = 8 - static let headerStackViewTopSpacing: CGFloat = 18 + static let headerStackViewTopSpacing: CGFloat = 20 + static let headerStackViewTopMaxSpacing: CGFloat = 24 static let headerStackViewHeight: CGFloat = 40 static let recommendedRoutineStackViewSpacing: CGFloat = 12 static let recommendedRoutineScrollViewTopSpacing: CGFloat = 12 static let recommendedRoutineScrollViewBottomSpacing: CGFloat = 10 static let recommendedRoutineStackViewBottomSpacing: CGFloat = 50 static let routineCardHeight: CGFloat = 80 - static let registerEmotionButtonHeight: CGFloat = 52 + static let registerEmotionButtonTopSpacing: CGFloat = 20 + static let registerEmotionButtonHeight: CGFloat = 66 static let floatingButtonBottomSpacing: CGFloat = 19 static let floatingButtonSize: CGFloat = 52 static let floatingMenuBottomSpacing: CGFloat = 15 @@ -44,17 +45,16 @@ final class RecommendedRoutineView: BaseViewController + public override init(viewModel: RecommendedRoutineViewModel) { cancellables = [] super.init(viewModel: viewModel) @@ -71,12 +71,11 @@ final class RecommendedRoutineView: BaseViewController(_ sender: SelectableItemTableView, didSelectItem: T?) { guard let didSelectLevel = didSelectItem as? RoutineLevelType? else { return } @@ -320,14 +321,25 @@ extension RecommendedRoutineView: SelectableItemTableViewDelegate { } // MARK: FloatingMenuViewDelegate -extension RecommendedRoutineView: FloatingMenuViewDelegate { +extension RecommendedRoutineViewController: FloatingMenuViewDelegate { func floatingMenuDidTapRegisterRoutineButton(_ sender: FloatingMenuView) { toggleFloatingButton() - guard let routineCreationViewModel = DIContainer.shared.resolve(type: RoutineCreationViewModel.self) else { - fatalError("routineCreationViewModel 의존성이 등록되지 않았습니다.") - } + guard let routineCreationViewModel = DIContainer.shared.resolve(type: RoutineCreationViewModel.self) + else { fatalError("routineCreationViewModel 의존성이 등록되지 않았습니다.") } + let routineCreationView = RoutineCreationViewController(viewModel: routineCreationViewModel) routineCreationView.hidesBottomBarWhenPushed = true self.navigationController?.pushViewController(routineCreationView, animated: true) } } + +extension RecommendedRoutineViewController: RegisterEmotionButtonViewDelegate { + func registerEmotionButtonViewDidTapRegisterButton(_ sender: RegisterEmotionButtonView) { + guard let emotionRegisterViewModel = DIContainer.shared.resolve(type: EmotionRegisterViewModel.self) + else { fatalError("emotionRegisterViewModel 의존성이 등록되지 않았습니다.") } + + let emotionRegisterView = EmotionRegisterView(viewModel: emotionRegisterViewModel) + emotionRegisterView.hidesBottomBarWhenPushed = true + self.navigationController?.pushViewController(emotionRegisterView, animated: true) + } +}