Skip to content

Comments

Style/#48 selectroutineview 구현#54

Merged
sum130 merged 3 commits intodevelopfrom
style/#48-selectroutineview
Jan 14, 2026
Merged

Style/#48 selectroutineview 구현#54
sum130 merged 3 commits intodevelopfrom
style/#48-selectroutineview

Conversation

@sum130
Copy link
Contributor

@sum130 sum130 commented Jan 13, 2026

🔗 연결된 이슈

📄 작업 내용

  • SelectRoutineView 구현했습니다!
  • ChallengeCoordinatorView에서 기존의 네비바hidden도 설정했습니다.
  • 루틴칩의 선택상태를 관리할 수 있도록 selectedRoutine 변수를 state로 두었습니다.
  • gif에서 보면 뒤로 2번 이동하는데 각각 백버튼이랑 x버튼 눌렀을 때 보여주는 겁니당
구현 내용 IPhone 16 pro IPhone 13 mini
GIF

💻 주요 코드 설명

  • extension SelectRoutineView
private extension SelectRoutineView {
    func routineChip(title: String, type: RoutineType) -> some View {
        SelectionChip(title: title, isSelected: Binding(get: {selectedRoutine == type},
                                                        set: {isSelected in selectedRoutine = isSelected ? type : nil}))
    }
}
  • RoutineType 하나만 선택 가능하도록 SelectionChip은 Bool 값만 알도록 하고 실제 선택 상태는 SelectRoutineView가 관리하도록 했습니다.
  • get은 어떤 칩이 선택됐는지 알고
  • set에서는 칩을 눌렀을 때 상태를 변경하도록 나눴습니당

@sum130 sum130 requested a review from a team January 13, 2026 14:15
@sum130 sum130 self-assigned this Jan 13, 2026
@sum130 sum130 requested review from soseoyo12, wotjs020708 and y-eonee and removed request for a team January 13, 2026 14:15
@sum130 sum130 linked an issue Jan 13, 2026 that may be closed by this pull request
1 task
@sum130 sum130 added the Style UI 구현 label Jan 13, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

챌린지 네비게이션에 challengeProgress 경로를 추가하고 탭바 숨김 토글을 경로별로 설정했으며, SelectRoutine 뷰를 루틴 선택 칩 UI로 재구성하고 로딩 이미지 자산, ChallengeProgressView 및 ViewFactory 팩토리를 추가했습니다.

Changes

Cohort / File(s) 변경 사항
코디네이터 네비게이션 변경
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift, Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinator.swift
ChallengeRoutechallengeProgress 케이스 추가; ChallengeCoordinatorView@EnvironmentObject private var tabBarCoordinator: TabBarCoordinator 추가; 경로별로 onAppear에서 tabBarCoordinator.isTabbarHidden 토글; navigationDestination들에 .navigationBarBackButtonHidden() 적용
SelectRoutine 뷰 리워크
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift
RoutineType 열거형 및 @State selectedRoutine 추가; 루틴 선택용 SelectionChip 2×2 그리드로 UI 재구성; Next 버튼 활성화 로직(nextButtonState) 및 Next 액션이 코디네이터의 로딩 네비게이션 호출 트리거
로딩 뷰 및 헬퍼 추가/수정
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift, Cherrish-iOS/Cherrish-iOS/Assets.xcassets/ChallengeImage/loading.imageset/Contents.json
LoadingView 레이아웃 재구성(CherrishNavigationBar, 헤더 등) 및 뷰 확장 highlight(...) 추가; loading.svg 자산 추가
진행 화면 추가 및 팩토리 연결
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeProgressView.swift, Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift
ChallengeProgressView 파일 추가(간단한 View); ViewFactoryProtocol/ViewFactorymakeChallengeProgressView() 구현 추가
메타/헤더 변경
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeView.swift
파일 헤더 작성자 주석 변경(기능적 변경 없음)

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant SelectRoutineView
  participant ChallengeCoordinatorView
  participant TabBarCoordinator
  participant LoadingView
  participant ChallengeProgressView

  User->>SelectRoutineView: 루틴 선택 및 Next 탭
  SelectRoutineView->>ChallengeCoordinatorView: navigate(to: .loading)
  ChallengeCoordinatorView->>TabBarCoordinator: onAppear -> isTabbarHidden = true
  ChallengeCoordinatorView->>LoadingView: present .loading
  LoadingView-->>ChallengeCoordinatorView: 완료 이벤트
  ChallengeCoordinatorView->>ChallengeProgressView: navigate(to: .challengeProgress)
  ChallengeProgressView->>TabBarCoordinator: onAppear -> isTabbarHidden = false
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • soseoyo12
  • y-eonee
  • wotjs020708
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 선택된 루틴 뷰 구현이라는 주요 변경사항을 명확하게 설명하고 있습니다.
Description check ✅ Passed PR 설명에서 SelectRoutineView 구현, ChallengeCoordinatorView 수정, selectedRoutine 상태 관리 등 변경사항을 충분히 설명하고 있습니다.
Linked Issues check ✅ Passed PR은 #48의 요구사항인 챌린지 루틴선택뷰 구현을 완료했으며, SelectRoutineView, RoutineType 열거형, 라우팅 추가 등을 포함합니다.
Out of Scope Changes check ✅ Passed 대부분의 변경사항이 SelectRoutineView 구현 및 관련 네비게이션 설정으로 #48과 직접 관련이 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch style/#48-selectroutineview

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift:
- Around line 17-33: The switch in ChallengeCoordinatorView that calls
ViewFactory.shared.makeChallengeView(), makeStartChallengeView(),
makeSelectRoutineView(), makeLoadingView(), and makeSelectMissionView() repeats
.navigationBarBackButtonHidden() for every case; refactor by applying
.navigationBarBackButtonHidden() once to the entire navigationDestination result
(or wrap the created views in a single ViewModifier) so each case returns the
raw view from ViewFactory.shared.* without the modifier and the modifier is
applied once outside the switch.
- Line 36: The NavigationStack currently uses .ignoresSafeArea(.all), which can
let child views like StartChallengeView render under notches/Dynamic Island and
bypass their fixed padding (e.g., 84.adjustedH); change the NavigationStack to
stop ignoring all safe areas (either remove .ignoresSafeArea(.all) or restrict
it to a specific edge such as .ignoresSafeArea(.container, edges: .bottom) ),
and update child views (StartChallengeView and other descendants) to respect
safe area insets by using safe-area-aware padding or reading safeAreaInsets
(replace fixed top padding with a safeArea-based padding) so content cannot be
obscured on devices with Dynamic Island/notches.

In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift:
- Line 23: Remove the redundant explicit nil assignment on the optional state
property by changing the declaration of selectedRoutine in SelectRoutineView
(the @State private var selectedRoutine: RoutineType? = nil line) to omit "=
nil" so it relies on Swift's default nil initialization for optional types.
- Around line 12-17: Enum declaration "RoutineType" is missing a space before
the opening brace; update the enum definition (enum RoutineType) to follow Swift
style by adding a single space before the "{" so it reads "enum RoutineType {",
keeping the existing cases unchanged.
- Around line 36-46: The HStack and VStack declarations lack a space before
their opening braces; update the UI container declarations (HStack and
VStack(alignment: .leading)) to follow Swift style by inserting a space before
the `{` (e.g., change "HStack{" and "VStack(alignment: .leading){" to include a
space), ensuring consistent formatting across the SelectRoutineView.swift
snippet.
- Around line 8-11: Remove the duplicate import by keeping a single "import
SwiftUI" at the top of SelectRoutineView (the SelectRoutineView struct/file) and
delete the extra duplicate import statement so SwiftUI is only imported once;
verify there are no other duplicate import lines in that file.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 822c9c8 and b8b53ec.

📒 Files selected for processing (2)
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift
🧰 Additional context used
🧬 Code graph analysis (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
  • body (9-17)
Cherrish-iOS/Cherrish-iOS/Presentation/Coordinator/AppCoordinatorProtocol.swift (1)
  • pop (22-24)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (1)
  • gray1000 (49-51)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift

[Warning] 10-10: Imports should be unique

(duplicate_imports)


[Warning] 23-23: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

🔇 Additional comments (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (3)

30-35: VStack()의 빈 괄호를 제거하고, 네비게이션 버튼 동작을 확인하세요.

  1. VStack()의 빈 괄호는 불필요합니다.
  2. PR 설명에 따르면 뒤로가기 버튼과 X 버튼의 네비게이션 동작이 다르게 보이는데 (two-step back navigation), 현재 leftButtonActionrightButtonAction이 동일하게 pop을 호출하고 있습니다. X 버튼은 챌린지 플로우 전체를 닫는 동작이 의도된 것인지 확인이 필요합니다.
♻️ VStack 수정 제안
-        VStack() {
+        VStack {
             CherrishNavigationBar(

48-59: 루틴 칩 그리드 레이아웃이 잘 구현되었습니다.

4개의 루틴 타입을 2x2 그리드로 배치하고, 일관된 spacing과 padding을 적용한 구현이 깔끔합니다.


72-77: routineChip 헬퍼 함수가 단일 선택 로직을 잘 캡슐화했습니다.

커스텀 Binding을 사용하여 선택 상태를 중앙에서 관리하는 패턴이 적절합니다. getter와 setter를 통해 selectedRoutine과 각 칩의 상태를 동기화하는 방식이 명확합니다.

Comment on lines +36 to +46
HStack{
VStack(alignment: .leading){
TypographyText("지금 나에게 가장 필요한\n관리 루틴을 선택해주세요.",
style: .title1_sb_18,
color: .gray1000
)
}
Spacer()
}
.padding(.top, 80.adjustedH)
.padding(.horizontal, 33.adjustedW)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

중괄호 앞에 공백을 추가하세요.

Swift 스타일 가이드에 따라 HStack{VStack(alignment: .leading){ 뒤에 공백이 필요합니다.

♻️ 수정 제안
-            HStack{
-                VStack(alignment: .leading){
+            HStack {
+                VStack(alignment: .leading) {
                     TypographyText("지금 나에게 가장 필요한\n관리 루틴을 선택해주세요.",
                         style: .title1_sb_18,
                         color: .gray1000
                     )
                 }
                 Spacer()
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
HStack{
VStack(alignment: .leading){
TypographyText("지금 나에게 가장 필요한\n관리 루틴을 선택해주세요.",
style: .title1_sb_18,
color: .gray1000
)
}
Spacer()
}
.padding(.top, 80.adjustedH)
.padding(.horizontal, 33.adjustedW)
HStack {
VStack(alignment: .leading) {
TypographyText("지금 나에게 가장 필요한\n관리 루틴을 선택해주세요.",
style: .title1_sb_18,
color: .gray1000
)
}
Spacer()
}
.padding(.top, 80.adjustedH)
.padding(.horizontal, 33.adjustedW)
🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift
around lines 36 - 46, The HStack and VStack declarations lack a space before
their opening braces; update the UI container declarations (HStack and
VStack(alignment: .leading)) to follow Swift style by inserting a space before
the `{` (e.g., change "HStack{" and "VStack(alignment: .leading){" to include a
space), ensuring consistent formatting across the SelectRoutineView.swift
snippet.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift:
- Around line 27-41: Duplicate tab bar hide logic appears in the switch cases
for selectRoutine, loading, and selectMission; centralize this by extracting the
hide behavior into one place: create a helper (e.g., a computed Bool or method
like shouldHideTabbar(for: currentRoute) or a ViewModifier hideTabbar()) and use
it to set tabBarCoordinator.isTabbarHidden = true once based on the route
instead of repeating it in each case; update references in
ChallengeCoordinatorView (cases selectRoutine, loading, selectMission) to rely
on that shared helper so future routes can be added by updating the single
list/logic.

In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift:
- Line 25: Fix the incomplete SwiftUI padding call in LoadingView: replace
`.padding(.horizontal,)` with either a no-value edge-only call
`.padding(.horizontal)` or provide a concrete CGFloat value like
`.padding(.horizontal, 16)` (choose whichever fits the intended layout) so the
code compiles; update the modifier on the view in LoadingView.swift accordingly.
- Around line 14-37: The VStack that starts at the top is closed too early (the
closing brace after .padding(.top, 113.adjustedH)); move that closing brace so
that Image(.loading), the following TypographyText calls, Spacer(), and the
final TypographyText are all inside the same outer VStack that contains
CherrishNavigationBar; also remove the stray trailing comma in
.padding(.horizontal,) and keep existing symbols:
CherrishNavigationBar(isDisplayRightButton:false, leftButtonAction:
challengeCoordinator.pop), the inner VStack with TypographyText lines,
Image(.loading), TypographyText("잠시만 기다려주세요!"), Spacer(), and
TypographyText("AI가 맞춤형 루틴을 제작하고 있어요.") so the layout renders as a single
vertical stack.

In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift:
- Line 21: Remove the redundant explicit nil initialization for the Optional
state property by changing the declaration of selectedRoutine so it relies on
Swift’s default nil for optionals; update the @State variable named
selectedRoutine: RoutineType? to omit the “= nil” initializer to satisfy
SwiftLint and simplify the code.
- Around line 10-15: Make RoutineType conform to CaseIterable and add a computed
property (e.g., koreanTitle or localizedTitle) that returns the Korean display
string for each case (skinCondition, lifeStyle, bodyShaping, wellness) so
callers can iterate all cases and get a human-readable title; update any UI code
that displays RoutineType to use this computed property instead of hardcoded
strings.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8b53ec and 1ab5be6.

⛔ Files ignored due to path filters (1)
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/ChallengeImage/loading.imageset/loading.svg is excluded by !**/*.svg
📒 Files selected for processing (8)
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/ChallengeImage/loading.imageset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeProgressView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinator.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift
🧰 Additional context used
🧬 Code graph analysis (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeProgressView.swift (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
  • body (9-17)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift (1)
Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift (6)
  • makeStartChallengeView (62-64)
  • makeChallengeView (50-52)
  • makeSelectRoutineView (66-68)
  • makeLoadingView (74-76)
  • makeSelectMissionView (70-72)
  • makeChallengeProgressView (78-80)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (4)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
  • body (9-17)
Cherrish-iOS/Cherrish-iOS/Presentation/Coordinator/AppCoordinatorProtocol.swift (1)
  • pop (22-24)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (1)
  • gray1000 (49-51)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinator.swift (1)
  • push (24-26)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
  • body (9-17)
Cherrish-iOS/Cherrish-iOS/Presentation/Coordinator/AppCoordinatorProtocol.swift (1)
  • pop (22-24)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (3)
  • red700 (89-91)
  • gray800 (41-43)
  • gray600 (33-35)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift

[Warning] 21-21: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

🔇 Additional comments (12)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeView.swift (1)

5-5: LGTM!

헤더의 작성자 정보가 업데이트되었습니다. 기능적 변경 사항은 없습니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeProgressView.swift (1)

10-14: LGTM!

ChallengeProgressView의 기본 구조가 프로젝트 컨벤션에 맞게 작성되었습니다. 현재는 플레이스홀더 구현이며, 추후 실제 UI 구현이 필요할 것으로 보입니다.

Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift (2)

22-22: LGTM!

프로토콜에 makeChallengeProgressView() 메서드가 올바르게 선언되었습니다. 기존 팩토리 메서드들과 일관된 패턴을 따르고 있습니다.


77-80: LGTM!

makeChallengeProgressView() 구현이 HomeView, ChallengeView 등 다른 간단한 뷰들과 동일한 패턴을 따르고 있습니다. 추후 ViewModel이 필요해지면 OnboardingView처럼 DIContainer를 통한 주입 패턴으로 확장할 수 있습니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinator.swift (1)

16-16: 라우트 구현 완료 확인됨

새로운 challengeProgress 라우트 케이스가 ChallengeCoordinator에서 정의되었으며, ChallengeCoordinatorView에서도 올바르게 처리되고 있습니다. ViewFactory를 통해 ChallengeProgressView를 생성하고 navigationBarBackButtonHidden()을 적용하는 기존 패턴과 일치합니다.

Cherrish-iOS/Cherrish-iOS/Assets.xcassets/ChallengeImage/loading.imageset/Contents.json (1)

1-12: 에셋 구성이 올바릅니다.

Xcode 에셋 카탈로그 형식이 정확하며, loading.svg 파일이 올바른 위치에 존재합니다. 이미지셋 디렉토리 구조가 완벽합니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift (2)

42-48: challengeProgress 경로 추가 확인

challengeProgress 경로에서 탭바를 다시 표시하는 로직이 올바르게 구현되었습니다. 챌린지 진행 화면에서 탭바가 보여야 하는 요구사항에 부합합니다.


52-52: ignoresSafeArea(.all) 적용 범위 확인 필요

전체 NavigationStack에 .ignoresSafeArea(.all)을 적용하면 노치/홈 인디케이터 영역까지 콘텐츠가 확장됩니다. 각 하위 뷰에서 safe area를 개별적으로 처리해야 하므로, 의도된 동작인지 확인이 필요합니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift (1)

15-18: 네비게이션 바 설정 확인

isDisplayRightButton: false로 오른쪽 버튼을 숨기고, 왼쪽 버튼은 pop 동작으로 설정되어 있습니다. 로딩 화면에서 사용자가 뒤로 가기를 할 수 있어야 하는지 UX 관점에서 확인이 필요합니다. 로딩 중 네비게이션을 허용하면 예기치 않은 상태가 발생할 수 있습니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (3)

29-33: 좌/우 버튼 동작 동일 여부 확인

leftButtonActionrightButtonAction 모두 challengeCoordinator.pop을 호출합니다. PR 설명에서 뒤로가기 버튼과 X 버튼의 네비게이션 동작이 다르다고 언급되어 있는데, 현재 구현은 동일한 동작을 수행합니다. 의도된 동작인지 확인이 필요합니다.


71-75: routineChip 헬퍼 함수 구현 우수

Binding의 getter/setter를 활용하여 단일 선택 동작을 깔끔하게 구현했습니다. SelectionChip은 Bool만 받고, SelectRoutineView가 어떤 RoutineType이 선택되었는지 중앙에서 관리하는 구조가 좋습니다.


61-63: 버튼 상태 바인딩 확인

CherrishButton.constant(nextButtonState)를 사용하고 있습니다. 만약 CherrishButton이 내부적으로 state를 변경하지 않는다면 괜찮지만, 변경이 필요한 경우 .constant 대신 @Binding을 사용해야 합니다.

Comment on lines 27 to 41
.onAppear() {
tabBarCoordinator.isTabbarHidden = true
}
case .loading:
ViewFactory.shared.makeLoadingView()
.navigationBarBackButtonHidden()
.onAppear() {
tabBarCoordinator.isTabbarHidden = true
}
case .selectMission:
ViewFactory.shared.makeSelectMissionView()
.navigationBarBackButtonHidden()
.onAppear() {
tabBarCoordinator.isTabbarHidden = true
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

탭바 숨김 로직 중복

selectRoutine, loading, selectMission 세 곳에서 동일한 isTabbarHidden = true 로직이 반복됩니다. 현재는 괜찮지만, 향후 경로가 추가될 때 유지보수를 위해 탭바를 숨겨야 하는 경로를 별도로 관리하는 방식을 고려해볼 수 있습니다.

🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift
around lines 27 - 41, Duplicate tab bar hide logic appears in the switch cases
for selectRoutine, loading, and selectMission; centralize this by extracting the
hide behavior into one place: create a helper (e.g., a computed Bool or method
like shouldHideTabbar(for: currentRoute) or a ViewModifier hideTabbar()) and use
it to set tabBarCoordinator.isTabbarHidden = true once based on the route
instead of repeating it in each case; update references in
ChallengeCoordinatorView (cases selectRoutine, loading, selectMission) to rely
on that shared helper so future routes can be added by updating the single
list/logic.

Comment on lines 10 to 15
enum RoutineType{
case skinCondition
case lifeStyle
case bodyShaping
case wellness
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

RoutineType enum 개선 제안

enum이 잘 정의되어 있습니다. 향후 확장성을 위해 CaseIterable 프로토콜 채택과 한글 타이틀을 위한 computed property 추가를 고려해보세요.

♻️ 개선 제안
-enum RoutineType{
+enum RoutineType: CaseIterable {
     case skinCondition
     case lifeStyle
     case bodyShaping
     case wellness
+    
+    var title: String {
+        switch self {
+        case .skinCondition: return "피부 컨디션"
+        case .lifeStyle: return "생활습관"
+        case .bodyShaping: return "체형 관리"
+        case .wellness: return "웰니스∙마음챙김"
+        }
+    }
 }
🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift
around lines 10 - 15, Make RoutineType conform to CaseIterable and add a
computed property (e.g., koreanTitle or localizedTitle) that returns the Korean
display string for each case (skinCondition, lifeStyle, bodyShaping, wellness)
so callers can iterate all cases and get a human-readable title; update any UI
code that displays RoutineType to use this computed property instead of
hardcoded strings.


@EnvironmentObject private var challengeCoordinator: ChallengeCoordinator

@State private var selectedRoutine: RoutineType? = nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Optional 변수의 nil 초기화 중복

SwiftLint 경고: Optional 변수를 nil로 초기화하는 것은 중복입니다. Swift에서 Optional은 기본값이 nil입니다.

♻️ 수정 제안
-    @State private var selectedRoutine: RoutineType? = nil
+    @State private var selectedRoutine: RoutineType?
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@State private var selectedRoutine: RoutineType? = nil
@State private var selectedRoutine: RoutineType?
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 21-21: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift
at line 21, Remove the redundant explicit nil initialization for the Optional
state property by changing the declaration of selectedRoutine so it relies on
Swift’s default nil for optionals; update the @State variable named
selectedRoutine: RoutineType? to omit the “= nil” initializer to satisfy
SwiftLint and simplify the code.

Copy link
Contributor

@soseoyo12 soseoyo12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어푸푸푸푸푸푸 익사하겠다 수고하셨습니다~

Copy link
Contributor

@wotjs020708 wotjs020708 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니담 코멘트 확인 부탁드려욤

Copy link
Contributor

@y-eonee y-eonee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

루틴 선택 토글안되게 하고 최근선택으로 들어가게만 수정해주면 될 것 같아요 수고하셨습니당

Comment on lines 20 to 22
HStack(spacing:0) {
TypographyText("피부 컨디션", style: .title1_sb_18, color: .red700)
TypographyText(" 관리 방향을 바탕으로", style: .title1_sb_18, color: .gray800)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 방법보다는 일부 텍스트만 컬러를 바꿀 수 있도록 익스텐션이나 다른 방법을 찾아보는게 좋을 것 같아요!!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

익스텐션으로 수정했습니당!

Comment on lines 30 to 36
Image(.loading)
.padding(.top, 17.adjustedH)
TypographyText("잠시만 기다려주세요!", style: .title2_sb_16, color: .gray800)
.padding(.top, 17.adjustedH)
Spacer()
TypographyText("AI가 맞춤형 루틴을 제작하고 있어요.", style: .body3_m_12, color: .gray600)
.padding(.bottom, 30.adjustedH)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

줄바꿈이랑 들여쓰기 한번만 맞춰주세용

case lifeStyle
case bodyShaping
case wellness
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

밑에 따로 타이틀을 하드코딩해두는 것보다는 여기서 변수로 작성해서 사용하는 것이 좋을 것 같아요

Comment on lines 73 to 74
SelectionChip(title: title, isSelected: Binding(get: {selectedRoutine == type},
set: {isSelected in selectedRoutine = isSelected ? type : nil}))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요기 isSelected에서 개행한번만 해주세여

@y-eonee y-eonee changed the title style: #48 selectroutineview 구현 Style/#48 selectroutineview 구현 Jan 14, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift`:
- Around line 35-45: The View extension named
highlight(highlightText:highlightColor:normalText:) is declared globally but
lives inside LoadingView.swift; either restrict its scope by changing it to a
private extension (private extension View { func highlight(...) -> some View {
... } }) if it’s only used in this file, or move the extension to a new shared
file (e.g., View+Highlight.swift) under your Global/Extension folder for
app-wide reuse; update call sites to use the same signature and keep the inner
implementation using TypographyText(highlightText, ...) unchanged.
♻️ Duplicate comments (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (2)

34-34: Optional 변수의 중복 nil 초기화를 제거하세요.

Swift에서 Optional 타입은 기본값이 nil이므로 명시적인 초기화가 불필요합니다.

♻️ 수정 제안
-    `@State` private var selectedRoutine: RoutineType? = nil
+    `@State` private var selectedRoutine: RoutineType?

47-48: 중괄호 앞에 공백을 추가하세요.

Swift 스타일 가이드에 따라 HStack{VStack(alignment: .leading){ 앞에 공백이 필요합니다.

♻️ 수정 제안
-            HStack{
-                VStack(alignment: .leading){
+            HStack {
+                VStack(alignment: .leading) {
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift (1)

14-32: 레이아웃 구조 오류: VStack이 조기에 닫혀 있습니다.

Line 24에서 VStack이 닫히지만 Image(.loading), TypographyText, Spacer 등의 요소들이 VStack 외부에 위치해 있습니다. SwiftUI의 body는 단일 View를 반환해야 하므로 컴파일 오류가 발생하거나 의도치 않은 레이아웃이 됩니다.

🐛 수정 제안: 모든 요소를 하나의 VStack으로 감싸기
     var body: some View {
         VStack(alignment: .center) {
            CherrishNavigationBar(
             isDisplayRightButton:false,
             leftButtonAction: challengeCoordinator.pop
            )
            VStack {
                highlight(highlightText: "피부 컨디션", normalText: "관리 방향을 바탕으로")
                TypographyText("TODO 미션을 만들고 있어요.", style: .title1_sb_18, color: .gray800)
            }
             .padding(.top, 113.adjustedH)
-       }
-        Image(.loading)
+            Image(.loading)
-            .padding(.top, 17.adjustedH)
+                .padding(.top, 17.adjustedH)
-        TypographyText("잠시만 기다려주세요!", style: .title2_sb_16, color: .gray800)
+            TypographyText("잠시만 기다려주세요!", style: .title2_sb_16, color: .gray800)
-            .padding(.top, 17.adjustedH)
+                .padding(.top, 17.adjustedH)
-        Spacer()
+            Spacer()
-        TypographyText("AI가 맞춤형 루틴을 제작하고 있어요.", style: .body3_m_12, color: .gray600)
+            TypographyText("AI가 맞춤형 루틴을 제작하고 있어요.", style: .body3_m_12, color: .gray600)
-            .padding(.bottom, 30.adjustedH)
+                .padding(.bottom, 30.adjustedH)
+        }
    }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ab5be6 and 464483b.

📒 Files selected for processing (3)
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift
  • Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift
🧰 Additional context used
🧬 Code graph analysis (2)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift (1)
Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift (6)
  • makeStartChallengeView (62-64)
  • makeChallengeView (50-52)
  • makeSelectRoutineView (66-68)
  • makeLoadingView (74-76)
  • makeSelectMissionView (70-72)
  • makeChallengeProgressView (78-80)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
  • body (9-17)
Cherrish-iOS/Cherrish-iOS/Presentation/Coordinator/AppCoordinatorProtocol.swift (1)
  • pop (22-24)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (3)
  • gray800 (41-43)
  • gray600 (33-35)
  • red700 (89-91)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift

[Warning] 34-34: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

🔇 Additional comments (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ChallengeCoordinatorView.swift (1)

17-45: LGTM! 이전 리뷰 피드백이 잘 반영되었습니다.

Group으로 감싸고 .navigationBarBackButtonHidden()을 한 번만 적용한 리팩토링이 적절합니다. 경로별 탭바 가시성 관리도 onAppear를 통해 올바르게 구현되었습니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (2)

83-92: 단일 선택 로직이 잘 구현되었습니다.

Binding을 활용한 칩 선택 관리가 적절합니다. guard isSelected else { return } 로직으로 인해 이미 선택된 칩을 다시 탭해도 선택 해제되지 않습니다. 다른 칩을 선택해야만 변경되는 동작이 의도된 것이라면 현재 구현이 적합합니다.


10-28: RoutineType enum이 잘 정의되었습니다.

각 케이스에 대한 title computed property가 적절하게 구현되어 UI에서 하드코딩을 피할 수 있습니다. 향후 확장성을 위해 CaseIterable 프로토콜 채택을 고려해볼 수 있습니다.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +35 to 45
extension View {
func highlight(
highlightText: String,
highlightColor: Color = .red700,
normalText: String
) -> some View {
HStack {
TypographyText(highlightText, style: .title1_sb_18, color: highlightColor)
TypographyText(normalText, style: .title1_sb_18, color: .gray800)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

View extension의 위치를 고려해보세요.

highlight extension이 LoadingView.swift에 정의되어 있지만, extension View로 선언되어 앱 전체에서 사용 가능합니다. 재사용성을 위해 Global/Extension 폴더로 이동하거나, 이 파일에서만 사용한다면 private extension으로 범위를 제한하는 것이 좋습니다.

♻️ 옵션 1: private으로 범위 제한
-extension View {
+private extension View {
     func highlight(
♻️ 옵션 2: Global/Extension으로 이동

View+Highlight.swift 파일을 Presentation/Global/Extension/ 폴더에 생성하여 다른 View extension들과 일관성을 유지하세요.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
extension View {
func highlight(
highlightText: String,
highlightColor: Color = .red700,
normalText: String
) -> some View {
HStack {
TypographyText(highlightText, style: .title1_sb_18, color: highlightColor)
TypographyText(normalText, style: .title1_sb_18, color: .gray800)
}
}
private extension View {
func highlight(
highlightText: String,
highlightColor: Color = .red700,
normalText: String
) -> some View {
HStack {
TypographyText(highlightText, style: .title1_sb_18, color: highlightColor)
TypographyText(normalText, style: .title1_sb_18, color: .gray800)
}
}
}
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/LoadingView.swift`
around lines 35 - 45, The View extension named
highlight(highlightText:highlightColor:normalText:) is declared globally but
lives inside LoadingView.swift; either restrict its scope by changing it to a
private extension (private extension View { func highlight(...) -> some View {
... } }) if it’s only used in this file, or move the extension to a new shared
file (e.g., View+Highlight.swift) under your Global/Extension folder for
app-wide reuse; update call sites to use the same signature and keep the inner
implementation using TypographyText(highlightText, ...) unchanged.

@sum130 sum130 merged commit fbe447b into develop Jan 14, 2026
1 check passed
@sum130 sum130 deleted the style/#48-selectroutineview branch January 14, 2026 14:28
Kimgyuilli pushed a commit that referenced this pull request Jan 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Style] 챌린지 루틴선택뷰

4 participants