Skip to content

[FEAT/#42] 챌린지 루틴 선택 뷰 스크린 구현 #91

Merged
hyeminililo merged 9 commits intodevelopfrom
feat/#42-challenge-view
Jan 19, 2026
Merged

[FEAT/#42] 챌린지 루틴 선택 뷰 스크린 구현 #91
hyeminililo merged 9 commits intodevelopfrom
feat/#42-challenge-view

Conversation

@hyeminililo
Copy link
Copy Markdown
Contributor

@hyeminililo hyeminililo commented Jan 19, 2026

Related issue 🛠

Work Description ✏️

  • 챌린지 뷰 스크린 구현

Screenshot 📸

Screen_Recording_20260119_172151_Cherrish.mp4

Uncompleted Tasks 😅

N/A

To Reviewers 📢

챌린지 뷰 스크린을 구현하면서 UI State를 조금 변경했습니다 ! 그리고 에뮬레이터로 실행했을 때와 실물기기로 했을 때 기기 대응이 돼서 그런지 미션칩 크기가 조오금 다르더라고요 ,,!! 편히 확인해주세요요 !!

Summary by CodeRabbit

  • 새로운 기능

    • 도전 루틴 선택 화면 추가
    • 여러 루틴 항목 표시 및 선택/토글 가능
    • 최소 하나 선택 시 활성화되는 "다음" 버튼
    • 화면 미리보기 추가로 선택 동작 및 비활성 상태 확인 가능
  • 개선 / 리팩터

    • 루틴 선택 상태를 불변 리스트 기반으로 통합 관리
    • 모델의 선택 필드에 기본값 추가로 사용 편의성 개선

✏️ Tip: You can customize this high-level summary in your review settings.

- ChallengeRoutine 모델 기본값 부여
- UI에 Model과 겹치는 부분 삭제 및 변경
- 챌린지 뷰모델 선ㅇ너
- 챌린지 뷰모델을 스크린에 적용
@hyeminililo hyeminililo self-assigned this Jan 19, 2026
@hyeminililo hyeminililo requested a review from a team as a code owner January 19, 2026 08:27
@hyeminililo hyeminililo added FEAT✨ 새로운 기능 구현 혜민🍒 혜민 담당 labels Jan 19, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 19, 2026

Walkthrough

Hilt 주입된 ViewModel과 Compose 라우트가 추가되어 ImmutableList 기반 UiState로 루틴 목록을 초기화·관리하고, 항목 선택 토글 및 선택 유무에 따라 하단 "다음" 버튼 동작이 연결됩니다.

Changes

Cohort / File(s) 변경 사항
화면 라우트 및 컴포저블
app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineScreen.kt
공개 Composable ChallengeRoutineRoute 추가: Hilt ViewModel 연결, uiState 수집 및 UiState.Success 시 내부 ChallengeRoutineScreen 렌더링. 내부 ChallengeRoutineScreen은 상단 바, 온보딩 본문, 선택 토글과 하단 "다음" 버튼(선택 여부에 따라 활성화) 구현 및 Preview 추가.
ViewModel 및 상태 관리
app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt, app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineUiState.kt
신규 ChallengeRoutineViewModel 추가: _uiState: MutableStateFlow<UiState<...>> 초기화(Loading → Success with immutable routines), 공개 uiState: StateFlow<...>, onRoutineClick(id)로 항목 선택 토글, onNextClick(), onBackClick(), onCloseClick() 추가. UiState 구조 변경: routines: ImmutableList<ChallengeRoutineModel>로 통합, 파생 속성 selectedRoutineisSelected 추가.
모델 변경
app/src/main/java/com/cherrish/android/presentation/challenge/routine/model/ChallengeRoutineModel.kt
ChallengeRoutineModelisSelected: Boolean = false 기본값 추가(옵셔널화).

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant UI as ChallengeRoutineScreen
    participant VM as ChallengeRoutineViewModel
    participant State as StateFlow\<UiState\>

    User->>UI: 루틴 항목 클릭
    UI->>VM: onRoutineClick(id)
    VM->>State: _uiState 업데이트 (routines 선택 토글)
    State-->>UI: 변경된 uiState 방출
    UI->>UI: 리컴포지션, 버튼 활성화 재계산
    User->>UI: "다음" 버튼 클릭
    UI->>VM: onNextClick()
    VM->>VM: selectedRoutine 조회 (현재는 추가 동작 미구현)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • nhyeonii
  • usuuhyn
🚥 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 설명은 저장소의 템플릿 구조를 따르고 관련 이슈, 작업 내용, 스크린샷, 미완료 작업, 리뷰어 메모를 포함하고 있습니다.
Linked Issues check ✅ Passed PR은 #42의 모든 주요 요구사항을 충족합니다: UI 조립, 단일 선택 로직, ViewModel 상태 관리, 선택 상태에 따른 버튼 활성화, 이벤트 연결이 모두 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항은 #42에 명시된 챌린지 뷰 스크린 구현 범위 내에 있으며, 범위를 벗어난 변경은 없습니다.

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

✨ Finishing touches
  • 📝 Generate docstrings

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
Copy Markdown
Contributor

@nhyeonii nhyeonii left a comment

Choose a reason for hiding this comment

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

고생하셧숩 ~~ 리뷰 확인 부탁해용ㅇ

) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

when (uiState) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
when (uiState) {
when (val state = uiState) {

P1 : 요거 이렇게 바꾸줘구 아래 ChallengeRoutineScreen에 uiState = state.data로 넘겨주는 거 오땡요 ??
when 표현식에서 subject를 변수로 바인딩하면 Kotlin의 스마트 캐스팅이 자동으로 적용되어 is UiState.Success 분기 내에서 state.data에 바로 접근할 수 잇더용 !! 반면 지금 혜민이가 작성한 방식은 이미 is 체크를 통해 타입을 검증했음에도 불구하고 명시적으로 as 캐스팅을 해야 하고 제네릭 타입까지 모두 적어줘야 해서 코드가 장황해지는 느낌이 잇답니당..ㅜㅜ 스마트 캐스팅을 활용하는 첫 번째 방식이 더 안전하고 가독성도 좋다고 생각해요!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

오오 저도 이 as 캐스팅이 조금 고민하면서 적었는데 너무 좋은거같아요 !!! 언니가 말한대로 수정해볼게요오 ~~!!

image

Comment on lines +17 to +19
private val _uiState =
MutableStateFlow<UiState<ChallengeRoutineUiState>>(UiState.Loading)
val uiState = _uiState.asStateFlow()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
private val _uiState =
MutableStateFlow<UiState<ChallengeRoutineUiState>>(UiState.Loading)
val uiState = _uiState.asStateFlow()
private val _uiState = MutableStateFlow<UiState<ChallengeRoutineUiState>>(UiState.Loading)
val uiState: StateFlow<UiState<ChallengeRoutineUiState>> = _uiState.asStateFlow()

P1 : 이렇게 수정하는거 어떄요 ?! 외부에 노출되는 타입을 명확히 하기 위해 StateFlow 타입을 명시해주는 게 좋을 것 같수 ~~ViewModel 내부 변경 가능성과 캡슐화 의도가 코드에 더 잘 드러나궁요

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

넘 좋아용 친절한 설명과 이유 감사드립니당 ~~!!! 이렇게 바꿔볼게요 !!

}

private fun loadRoutines() {
_uiState.value = UiState.Success(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 : 상태 변경은 value 직접 접근보다 update / updateSuccess를 사용하는 게 좋을 것 같아욤
원자적 업데이트가 보장되고 UiState 구조에 맞는 상태 변경 의도가 코드에 더 잘 드러난답니동

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

넵 !!! 상태 변경 말씀하신대로 변경해볼게요 !!! 감사합니둥

@hyeminililo hyeminililo changed the title [FEAT/#42] 챌린지 뷰 스크린 구현 [FEAT/#42] 챌린지 루틴 선택 뷰 스크린 구현 Jan 19, 2026
Copy link
Copy Markdown
Contributor

@sohee6989 sohee6989 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!!

modifier = Modifier.padding(horizontal = 24.dp)
)

Spacer(Modifier.weight(30f))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p1: 이거 height로!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

했습니다 !

.padding(paddingValues)
.navigationBarsPadding()
) {
Spacer(Modifier.weight(44f))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p1: 여기 dp로!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

굿!

}

fun onNextClick() {
val selectedRoutine = _uiState.value
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p1: selectedRoutine 값을 얻는 과정ㅇ을 Model에서 얻게끔 하는거 어떠세요?
그러면서 밑에 있는 값들도 관리해서 처리해주면 될 것 같아요!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

했는데 와주세요 정답이길 ~~

Copy link
Copy Markdown

@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: 3

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineScreen.kt`:
- Line 69: Replace the local recomputation "val isSelected =
uiState.routines.any { it.isSelected }" in the ChallengeRoutineScreen composable
with the existing aggregate property on the state: use "uiState.isSelected"
directly; update any usages that reference the local isSelected to reference
uiState.isSelected instead to remove duplicated logic and ensure consistency
with ChallengeRoutineUiState.

In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt`:
- Around line 58-60: 함수명 오타로 인해 일관성이 깨져 있으니 ChallengeRoutineViewModel의
onBackCLick 함수를 onBackClick으로 이름을 변경하세요; 즉 기존의 fun onBackCLick() { }를 fun
onBackClick() { }로 바꾸고 클래스 내부와 프로젝트 전반에서 이 함수명을 호출하는 모든 참조(예: 호출부, 레이아웃 바인딩, 테스트
등)를 함께 업데이트하여 컴파일 오류가 나지 않도록 하세요.
- Around line 49-56: The local variable selectedRoutine in onNextClick is
declared but never used; either remove the declaration or, if you plan to use it
for future navigation, replace it with a clear TODO comment referencing
navigation (e.g., TODO: navigate with selectedRoutine) so the intent is
preserved; locate the unused variable in ChallengeRoutineViewModel.onNextClick
(check _uiState and UiState.Success branches) and apply the change accordingly.
🧹 Nitpick comments (2)
app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt (1)

26-37: 데이터 레이어 분리 고려

현재 루틴 데이터가 ViewModel에 하드코딩되어 있습니다. MVP 단계에서는 괜찮지만, 향후 서버 연동이나 테스트 용이성을 위해 Repository 패턴으로 분리하는 것을 고려해 보세요.

app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineScreen.kt (1)

37-56: Loading/Failure 상태 UI 추가 권장

현재 UiState.LoadingUiState.Failure 상태에서 아무런 UI가 표시되지 않습니다. 사용자 경험을 위해 로딩 인디케이터나 에러 메시지를 표시하는 것이 좋습니다.

♻️ 예시 구현
     when (val state = uiState) {
         is UiState.Loading -> {
+            // 로딩 인디케이터 표시
+            Box(
+                modifier = Modifier.fillMaxSize(),
+                contentAlignment = Alignment.Center
+            ) {
+                CircularProgressIndicator()
+            }
         }

         is UiState.Failure -> {
+            // 에러 상태 표시
         }

onCloseClick: () -> Unit,
modifier: Modifier = Modifier
) {
val isSelected = uiState.routines.any { it.isSelected }
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 19, 2026

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

중복 계산 제거 - uiState.isSelected 활용

ChallengeRoutineUiState에 이미 isSelected 프로퍼티가 정의되어 있습니다. 로컬에서 다시 계산하는 대신 해당 프로퍼티를 직접 사용하면 코드 중복을 줄이고 일관성을 유지할 수 있습니다.

♻️ 제안하는 수정
-    val isSelected = uiState.routines.any { it.isSelected }
+    val isSelected = uiState.isSelected
📝 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
val isSelected = uiState.routines.any { it.isSelected }
val isSelected = uiState.isSelected
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineScreen.kt`
at line 69, Replace the local recomputation "val isSelected =
uiState.routines.any { it.isSelected }" in the ChallengeRoutineScreen composable
with the existing aggregate property on the state: use "uiState.isSelected"
directly; update any usages that reference the local isSelected to reference
uiState.isSelected instead to remove duplicated logic and ensure consistency
with ChallengeRoutineUiState.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

래빗이 인정 ~~

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@nhyeonii 감사합니다! 😊 중복 계산을 제거하면 코드가 더 간결하고 유지보수하기 쉬워질 거예요.


🧠 Learnings used
Learnt from: nhyeonii
Repo: TEAM-Cherrish/Cherrish-Android PR: 41
File: app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt:30-39
Timestamp: 2026-01-12T19:49:33.128Z
Learning: In the Cherrish-Android codebase, Screen composables that receive a `paddingValues: PaddingValues` parameter from Scaffold must apply it to their root container's modifier (e.g., `.padding(paddingValues)`) before applying additional padding, to avoid layout overlap with system bars.

Comment on lines +49 to +56
fun onNextClick() {
val state = _uiState.value

if (state !is UiState.Success) return
if (!state.data.isSelected) return

val selectedRoutine = state.data.selectedRoutine!!
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

사용되지 않는 변수 제거 필요

selectedRoutine 변수가 선언만 되고 사용되지 않습니다. 향후 네비게이션 로직 구현 시 필요하다면 TODO 주석을 남기거나, 현재로서는 제거하는 것이 좋습니다.

🔧 제안하는 수정
     fun onNextClick() {
         val state = _uiState.value

         if (state !is UiState.Success) return
         if (!state.data.isSelected) return

-        val selectedRoutine = state.data.selectedRoutine!!
+        // TODO: 선택된 루틴으로 다음 화면 네비게이션 구현
+        // val selectedRoutine = state.data.selectedRoutine!!
     }
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt`
around lines 49 - 56, The local variable selectedRoutine in onNextClick is
declared but never used; either remove the declaration or, if you plan to use it
for future navigation, replace it with a clear TODO comment referencing
navigation (e.g., TODO: navigate with selectedRoutine) so the intent is
preserved; locate the unused variable in ChallengeRoutineViewModel.onNextClick
(check _uiState and UiState.Success branches) and apply the change accordingly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

래빗이 말이 마즘 그리고 소희언니가 얘기햇던것 처럼 모델활용해서 써주면 좋을 걱 가튿네 이건 서버 연결할때 로직 연결해도 괜찮은거 가틈!!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@nhyeonii 네, 맞습니다! 👍

서버 연결 시 실제 네비게이션 로직을 구현할 때 selectedRoutine 모델을 활용하시면 됩니다. 현재는 TODO 주석으로 의도를 명확히 해두시거나, 서버 작업 시점에 함께 구현하셔도 괜찮습니다.

서버 연동 시 선택된 루틴 정보를 다음 화면으로 전달하거나 API 호출에 사용하실 때 해당 로직을 추가하시면 되겠네요! 😊

Comment on lines +58 to +60
fun onBackCLick() {
}
fun onCloseClick() {}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

함수명 오타 수정 필요

onBackCLick에서 'L'이 대문자입니다. onCloseClick과 일관성을 위해 onBackClick으로 수정해 주세요.

🔧 제안하는 수정
-    fun onBackCLick() {
+    fun onBackClick() {
     }
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt`
around lines 58 - 60, 함수명 오타로 인해 일관성이 깨져 있으니 ChallengeRoutineViewModel의
onBackCLick 함수를 onBackClick으로 이름을 변경하세요; 즉 기존의 fun onBackCLick() { }를 fun
onBackClick() { }로 바꾸고 클래스 내부와 프로젝트 전반에서 이 함수명을 호출하는 모든 참조(예: 호출부, 레이아웃 바인딩, 테스트
등)를 함께 업데이트하여 컴파일 오류가 나지 않도록 하세요.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

반영 플리즈 ~~

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

@nhyeonii, 네, 바로 적용해드리겠습니다!

Task: Fix onBackCLick typo

  • Rename onBackCLick to onBackClick in ChallengeRoutineViewModel.kt
  • Find and update all call sites that reference the old function name

🏁 Script executed:

#!/bin/bash
# Find all usages of onBackCLick (with capital L typo)
rg -n 'onBackCLick' --type kotlin

Length of output: 278


@nhyeonii, 검색 결과 2곳에서 수정이 필요합니다. 두 파일 모두 업데이트해드리겠습니다!

Task: Fix onBackCLick typo

  • Rename onBackCLick to onBackClick in ChallengeRoutineViewModel.kt
  • Update the call site in ChallengeRoutineScreen.kt

💡 For code changes across multiple files, use @coderabbitai plan in an issue comment

Copy link
Copy Markdown
Contributor

@sohee6989 sohee6989 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
Copy Markdown

@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: 2

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt`:
- Around line 26-35: The loadRoutines() call uses updateSuccess which only
mutates when currentState is UiState.Success, so with the initial _uiState.value
== UiState.Loading the state never changes; replace the updateSuccess call in
loadRoutines() with an explicit assignment to _uiState.value =
UiState.Success(ChallengeRoutineUiState(...)) (or add/use an extension that
transitions Loading→Success), ensuring you populate ChallengeRoutineUiState with
the persistentListOf items and reference the same ChallengeRoutineModel IDs used
previously.
- Around line 58-60: Implement navigation emission from
ChallengeRoutineViewModel by adding a navigation StateFlow: define a sealed
class NavigationEvent { object Back; object Close } (or similar), add a private
MutableStateFlow<NavigationEvent?> _navigationEvent = MutableStateFlow(null) and
expose val navigationEvent: StateFlow<NavigationEvent?> = _navigationEvent;
update onBackClick() to set _navigationEvent.value = NavigationEvent.Back and
onCloseClick() to set _navigationEvent.value = NavigationEvent.Close, and ensure
the Route composable collects navigationEvent and clears it after handling (set
null) so navigation occurs once; alternatively remove the methods if they’re
unused.
♻️ Duplicate comments (1)
app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt (1)

49-56: 사용되지 않는 selectedRoutine 정리 필요 (중복 지적)

Line 55의 selectedRoutine가 사용되지 않습니다. 네비게이션에 쓸 예정이면 TODO 주석을 남기고, 아니면 제거해 주세요.

🧹 제안 수정
-        val selectedRoutine = state.data.selectedRoutine!!
+        // TODO: 선택된 루틴으로 다음 화면 네비게이션 구현
+        // val selectedRoutine = state.data.selectedRoutine!!

Comment on lines +26 to +35
private fun loadRoutines() {
_uiState.updateSuccess {
ChallengeRoutineUiState(
routines = persistentListOf(
ChallengeRoutineModel(id = 1L, routine = "피부 컨디션"),
ChallengeRoutineModel(id = 2L, routine = "생활 습관"),
ChallengeRoutineModel(id = 3L, routine = "체형 관리"),
ChallengeRoutineModel(id = 4L, routine = "웰니스 · 마음챙김")
)
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# updateSuccess 확장 함수 구현 확인
rg -n -C3 'fun\s+.*updateSuccess' --type kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 204


🏁 Script executed:

# ChallengeRoutineViewModel의 _uiState 초기값 확인
rg -n -C5 'class ChallengeRoutineViewModel' --type kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 100


🏁 Script executed:

# UiState의 구조 확인
rg -n -C5 'sealed class.*UiState' --type kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 100


🏁 Script executed:

# updateSuccess 확장 함수 구현 확인 (타입 지정 없이 검색)
rg -n -C3 'fun\s+.*updateSuccess' --glob '*.kt'

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 841


🏁 Script executed:

# ChallengeRoutineViewModel 파일 찾기 및 내용 확인
fd 'ChallengeRoutineViewModel.kt' -type f | head -1 | xargs -I {} sh -c 'wc -l {} && cat -n {}'

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 244


🏁 Script executed:

# UiState 정의 찾기
rg -n 'sealed class.*UiState|class.*UiState' --glob '*.kt' -A 5

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 5150


🏁 Script executed:

# updateSuccess 전체 구현 확인
cat -n app/src/main/java/com/cherrish/android/core/common/extension/StateFlowExt.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 685


🏁 Script executed:

# UiState 제너릭 정의 찾기
rg -n 'sealed class UiState|class UiState' --glob '*.kt' -A 10

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 56


🏁 Script executed:

# ChallengeRoutineViewModel 전체 내용 확인
cat -n app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 2469


updateSuccess는 Success 상태에서만 동작하므로 초기 Loading 상태에서 데이터 업데이트 불가

초기값이 UiState.Loading(line 19)인데, updateSuccess 확장 함수(StateFlowExt.kt line 11)는 currentState is UiState.Success일 때만 데이터를 업데이트합니다. 따라서 loadRoutines()에서 updateSuccess를 호출해도 상태가 Loading에서 벗어나지 못합니다.

해결 방법: _uiState.value = UiState.Success(data) 사용 또는 Loading → Success 전환을 담당하는 별도의 확장 함수가 필요합니다.

🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt`
around lines 26 - 35, The loadRoutines() call uses updateSuccess which only
mutates when currentState is UiState.Success, so with the initial _uiState.value
== UiState.Loading the state never changes; replace the updateSuccess call in
loadRoutines() with an explicit assignment to _uiState.value =
UiState.Success(ChallengeRoutineUiState(...)) (or add/use an extension that
transitions Loading→Success), ensuring you populate ChallengeRoutineUiState with
the persistentListOf items and reference the same ChallengeRoutineModel IDs used
previously.

Comment on lines +58 to +60
fun onBackClick() {
}
fun onCloseClick() {}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, search for onBackClick and onCloseClick call sites
rg -n -C2 'onBackClick|onCloseClick' --type kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 100


🏁 Script executed:

# Also, let's examine the ChallengeRoutineViewModel.kt file to see the full context
wc -l app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 175


🏁 Script executed:

# Check the ViewModel structure and UiState pattern
head -100 app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 2042


🏁 Script executed:

# Search for onBackClick and onCloseClick call sites without type filter
rg -n -C3 'onBackClick|onCloseClick'

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 11670


🏁 Script executed:

# Let's also check the Composable function that uses this ViewModel
fd -e kt -path '*/challenge/routine*' | head -20

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 242


🏁 Script executed:

# Check for typical navigation event patterns in other ViewModels
rg -n 'sealed class.*Event|data class.*Event|_event.*MutableStateFlow' --type kotlin | head -20

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 295


🏁 Script executed:

# Let's examine the ChallengeRoutineScreen.kt to see how navigation might be expected
cat -n app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineScreen.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 5458


🏁 Script executed:

# Look for navigation event patterns - check if other ViewModels use sealed classes for navigation
rg -n 'sealed class.*Event' --max-count 10

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 56


🏁 Script executed:

# Check if there's a NavController or navigation callback expected from the Screen composition
rg -n 'NavController|onNavigate|navController' app/src/main/java/com/cherrish/android/presentation/challenge/routine/

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 56


🏁 Script executed:

# Check for navigation event patterns in other presentation files
rg -n '_event|NavigationEvent|NavEvent' app/src/main/java/com/cherrish/android/presentation/ | head -20

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 56


🏁 Script executed:

# Check how ChallengeRoutineRoute is called - look for parent composables that might handle navigation
rg -n 'ChallengeRoutineRoute' app/src/main/java/com/cherrish/android/presentation/

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 199


🏁 Script executed:

# Look at other ViewModels to see how they handle navigation
fd -path '*/presentation/*ViewModel.kt' -exec grep -l 'fun on.*Click\|fun onBack\|fun onClose' {} \; | head -5

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 242


🏁 Script executed:

# Let me check the full context of ChallengeRoutineRoute to see if there's any place for navigation handling
cat -n app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineScreen.kt | head -60

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 2796


🏁 Script executed:

# Check if there's a pattern in other screens - look for how other routes handle back/close navigation
find app/src/main/java/com/cherrish/android/presentation -name '*Route.kt' -o -name '*Screen.kt' | head -10

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 800


🏁 Script executed:

# Check another screen to see the navigation pattern - let's look at OnboardingScreen
cat -n app/src/main/java/com/cherrish/android/presentation/onboarding/OnboardingScreen.kt | head -100

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 4653


🏁 Script executed:

# Let's search for how these methods are typically implemented - look for onBackClick implementations in ViewModel files
rg -n 'fun onBackClick|fun onCloseClick' app/src/main/java/com/cherrish/android/presentation/ -A 3

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 539


🏁 Script executed:

# Let's check OnboardingViewModel to see how it handles navigation events
cat -n app/src/main/java/com/cherrish/android/presentation/onboarding/OnboardingViewModel.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 492


🏁 Script executed:

# Search for any parent navigation composition that might use ChallengeRoutineRoute
rg -n 'ChallengeRoutineRoute' app/src/main/java/com/cherrish/android/

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 199


🏁 Script executed:

# Check if there's a common pattern for navigation callbacks in Route composables
rg -n 'fun.*Route.*\(.*onBack|fun.*Route.*\(.*onClose|fun.*Route.*\(.*onNavigate' app/src/main/java/com/cherrish/android/presentation/ -B 2 | head -40

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 56


뒤로/닫기 버튼의 동작이 구현되지 않아 네비게이션이 작동하지 않습니다

onBackClick()onCloseClick() 메서드가 비어 있어 사용자가 버튼을 눌러도 화면 전환이 일어나지 않습니다. PR 목표의 "화면 전환 이벤트 연결" 요구사항을 충족하려면 다음 중 하나를 구현해야 합니다:

  • ViewModel에서 NavigationEvent를 StateFlow로 내보내 Route에서 처리하기
  • Route 컴포저블에 네비게이션 콜백 파라미터(onBack, onClose)를 추가하여 상위에서 처리하기
  • 또는 이 메서드들이 필요하지 않다면 제거하기
🧰 Tools
🪛 detekt (1.23.8)

[warning] 58-59: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)


[warning] 60-60: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/routine/ChallengeRoutineViewModel.kt`
around lines 58 - 60, Implement navigation emission from
ChallengeRoutineViewModel by adding a navigation StateFlow: define a sealed
class NavigationEvent { object Back; object Close } (or similar), add a private
MutableStateFlow<NavigationEvent?> _navigationEvent = MutableStateFlow(null) and
expose val navigationEvent: StateFlow<NavigationEvent?> = _navigationEvent;
update onBackClick() to set _navigationEvent.value = NavigationEvent.Back and
onCloseClick() to set _navigationEvent.value = NavigationEvent.Close, and ensure
the Route composable collects navigationEvent and clears it after handling (set
null) so navigation occurs once; alternatively remove the methods if they’re
unused.

@hyeminililo hyeminililo merged commit d53d3d9 into develop Jan 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FEAT✨ 새로운 기능 구현 혜민🍒 혜민 담당

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 챌린지 뷰 컴포넌트 조립

3 participants