Feat/#38 myinterststudy 구현#39
Hidden character warning
Conversation
Walkthrough사용자 선호 카테고리 기반 스터디 조회 및 필터 기능을 추가합니다. API/데이터계층, 저장소, 뷰모델, UI(목록 · 필터 화면)와 네비게이션, 사용자 선호 카테고리 매핑이 확장되었습니다. Changes
Sequence DiagramsequenceDiagram
participant User as "User"
participant MainNav as "MainNavHost"
participant VM as "PreferCategoryStudyViewModel"
participant UserRepo as "UserRepository"
participant StudyRepo as "StudyRepository"
participant StudySvc as "StudyService"
User->>MainNav: 관심사 메뉴 선택
MainNav->>VM: 화면 진입 (init)
VM->>UserRepo: getPreferCategories()
UserRepo-->>VM: List<StudyTheme?>
VM->>StudyRepo: getPreferCategoryStudies(category, filters, sort, cursor, size)
StudyRepo->>StudySvc: getPreferCategoryStudies(...)
StudySvc-->>StudyRepo: BaseResponse<StudyResponseDto>
StudyRepo-->>VM: Result<StudyResultList>
VM-->>MainNav: uiState (Success/Empty/Failure)
MainNav-->>User: 화면 렌더링
User->>MainNav: 필터 적용
MainNav->>VM: applyFilter(...)
VM->>StudyRepo: getPreferCategoryStudies(...) (필터 포함)
StudyRepo->>StudySvc: getPreferCategoryStudies(...)
StudySvc-->>StudyRepo: 필터된 결과
StudyRepo-->>VM: Result<StudyResultList>
VM-->>MainNav: 업데이트된 uiState
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In
`@data/study/src/main/java/com/umcspot/spot/study/repositoryimpl/StudyRepositoryImpl.kt`:
- Around line 94-96: The error log inside the onFailure block currently uses the
wrong method name; update the Log.e call in StudyRepositoryImpl (the onFailure
inside getPreferCategoryStudies) to use "getPreferCategoryStudies failed"
instead of "getPreferLocationStudies failed" so the log message matches the
getPreferCategoryStudies function and avoids confusion during debugging.
- Line 14: Remove the unused JUnit test import from the production repository
implementation: delete the import line "import
org.junit.experimental.categories.Category" in StudyRepositoryImpl
(StudyRepositoryImpl.kt), confirm there are no usages of Category in the file,
and run the build/compile to ensure no remaining test-only imports remain.
In `@feature/main/src/main/java/com/umcspot/spot/main/MainNavHost.kt`:
- Around line 173-178: The preferCategoryStudyGraph call sets onItemClick to an
empty lambda so clicks do nothing; update its onItemClick to forward the clicked
study id/item to the navigator like in jjimGraph by calling
navigator.navigateToStudyDetail(it) (or the appropriate parameter name) instead
of onItemClick = { } to enable navigation to the study detail screen.
In
`@feature/study/src/main/java/com/umcspot/spot/study/preferCategory/navigation/PreferCategoryStudyFilterNavigation.kt`:
- Around line 24-30: getBackStackEntry(PreferCategory) can throw if
PreferCategory isn't on the back stack; wrap the call to
navController.getBackStackEntry(PreferCategory) in a try-catch and provide a
safe fallback: if try succeeds use that parentEntry to obtain the
PreferCategoryStudyViewModel via hiltViewModel(parentEntry), otherwise obtain a
fallback ViewModel with hiltViewModel() (or explicitly navigate to
PreferCategory before showing the filter) and pass that categoryVm into
PreferCategoryStudyFilterScreen; update the code around
navController.getBackStackEntry, PreferCategoryStudyViewModel and
PreferCategoryStudyFilterScreen to use this safe pattern.
🧹 Nitpick comments (7)
feature/mypage/src/main/java/com/umcspot/spot/mypage/main/MyPageViewModel.kt (2)
40-40: 로그 태그가 클래스명과 불일치합니다.
"HomeViewModel"대신"MyPageViewModel"을 사용해야 디버깅 시 로그 필터링이 정확해집니다. 라인 60, 72에도 동일한 문제가 있습니다.♻️ 수정 제안
- Log.e("HomeViewModel", "loadMyPageInfo error", e) + Log.e("MyPageViewModel", "loadMyPageInfo error", e)라인 60:
- Log.e("HomeViewModel", "loadPreferredRegion error", e) + Log.e("MyPageViewModel", "loadPreferredRegion error", e)라인 72:
- Log.e("HomeViewModel", "loadPreferCategories error", e) + Log.e("MyPageViewModel", "loadPreferCategories error", e)
71-74: 주석 처리된 실패 상태 처리를 고려해 주세요.
onFailure블록에서 UI 상태 업데이트가 주석 처리되어 있어 사용자에게 에러 피드백이 제공되지 않습니다. 추후 적절한 에러 핸들링 구현이 필요합니다.feature/study/src/main/java/com/umcspot/spot/study/preferCategory/PreferCategoryStudyViewModel.kt (1)
82-141: CancellationException 재전파 권장
runCatching이 CancellationException을 포함한 모든 예외를 흡수하면, 취소 이후에도 UI 업데이트가 진행될 수 있습니다. 구조화된 동시성을 유지하려면 CancellationException은 반드시 재전파해야 합니다.이 문제는
load()(82-110줄)와loadNextPage()(112-142줄) 두 메서드 모두에서 발생합니다. 각 메서드의.onFailure블록에 CancellationException 재전파 로직을 추가하세요:.onFailure { e -> if (e is CancellationException) throw e Log.e("PreferCategoryStudyViewModel", "error", e) }
CancellationExceptionimport를 추가해야 합니다:import kotlinx.coroutines.CancellationExceptionfeature/study/src/main/java/com/umcspot/spot/study/preferCategory/PreferCategoryStudyScreen.kt (2)
228-251:items.indexOf(item)호출로 인한 O(n²) 성능 문제
items()내부에서indexOf를 호출하면 각 아이템마다 O(n) 검색이 발생하여 전체 O(n²) 복잡도가 됩니다.itemsIndexed를 사용하면 인덱스를 직접 받을 수 있습니다.♻️ 수정 제안
- items( - items = items, - key = { it.id } - ) { item -> + itemsIndexed( + items = items, + key = { _, item -> item.id } + ) { index, item -> Spacer(Modifier.padding(screenHeightDp(5.dp))) StudyListItem( item = item, modifier = Modifier .fillMaxWidth(), onClick = { onItemClick(item.id) } ) - if(items.indexOf(item) != items.lastIndex) { + if(index != items.lastIndex) { Spacer(Modifier.padding(screenHeightDp(5.dp))) HorizontalDivider( modifier = Modifier .fillMaxWidth(), color = SpotTheme.colors.G300, thickness = 1.dp ) } }
76-78: 사용되지 않는 import 문
kotlin.collections.lastIndex,kotlin.collections.orEmpty,kotlin.text.format은 명시적으로 import하지 않아도 Kotlin 표준 라이브러리에서 자동으로 사용 가능합니다.♻️ 제거 제안
-import kotlin.collections.lastIndex -import kotlin.collections.orEmpty -import kotlin.text.formatfeature/study/src/main/java/com/umcspot/spot/study/preferCategory/PreferCategoryStudyFilterScreen.kt (2)
66-66:acceptEnabled가 항상true로 하드코딩되어 있습니다.현재
buttonEnabled가 항상true이므로 버튼 활성화 로직이 무의미합니다. 필터 조건이 변경되었을 때만 버튼을 활성화하거나, 이 변수가 불필요하다면 제거하는 것을 고려해 주세요.♻️ 필터 변경 여부에 따른 버튼 활성화 예시
- val acceptEnabled = true + val acceptEnabled = draftRecruitingStatus != recruitingStatus || + draftFee != fee || + draftActivity != activity
197-197:screenHeightDp()사용이 일관되지 않습니다.다른 모든 Spacer에서는
screenHeightDp()를 사용하지만, 이 라인에서만 직접80.dp를 사용하고 있습니다. 다양한 화면 크기에서 일관된 레이아웃을 위해 수정이 필요합니다.♻️ 제안된 수정
- Spacer(Modifier.height(80.dp)) + Spacer(Modifier.height(screenHeightDp(80.dp)))
data/study/src/main/java/com/umcspot/spot/study/repositoryimpl/StudyRepositoryImpl.kt
Outdated
Show resolved
Hide resolved
data/study/src/main/java/com/umcspot/spot/study/repositoryimpl/StudyRepositoryImpl.kt
Show resolved
Hide resolved
| preferCategoryStudyGraph( | ||
| contentPadding = contentPadding, | ||
| onRegisterScrollToTop = onRegisterScrollToTop, | ||
| onItemClick = { }, | ||
| onFilterClick = { navigator.navController.navigateToPreferCategoryStudyFilter() }, | ||
| ) |
There was a problem hiding this comment.
onItemClick 콜백이 빈 람다로 설정되어 있습니다.
onItemClick = { }가 비어 있어 스터디 아이템 클릭 시 상세 페이지로 이동하지 않습니다. jjimGraph(라인 113)처럼 navigator.navigateToStudyDetail(it)로 연결해야 할 것으로 보입니다.
🔧 수정 제안
preferCategoryStudyGraph(
contentPadding = contentPadding,
onRegisterScrollToTop = onRegisterScrollToTop,
- onItemClick = { },
+ onItemClick = { navigator.navController.navigateToStudyDetail(it) },
onFilterClick = { navigator.navController.navigateToPreferCategoryStudyFilter() },
)📝 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.
| preferCategoryStudyGraph( | |
| contentPadding = contentPadding, | |
| onRegisterScrollToTop = onRegisterScrollToTop, | |
| onItemClick = { }, | |
| onFilterClick = { navigator.navController.navigateToPreferCategoryStudyFilter() }, | |
| ) | |
| preferCategoryStudyGraph( | |
| contentPadding = contentPadding, | |
| onRegisterScrollToTop = onRegisterScrollToTop, | |
| onItemClick = { navigator.navController.navigateToStudyDetail(it) }, | |
| onFilterClick = { navigator.navController.navigateToPreferCategoryStudyFilter() }, | |
| ) |
🤖 Prompt for AI Agents
In `@feature/main/src/main/java/com/umcspot/spot/main/MainNavHost.kt` around lines
173 - 178, The preferCategoryStudyGraph call sets onItemClick to an empty lambda
so clicks do nothing; update its onItemClick to forward the clicked study
id/item to the navigator like in jjimGraph by calling
navigator.navigateToStudyDetail(it) (or the appropriate parameter name) instead
of onItemClick = { } to enable navigation to the study detail screen.
| composable<PreferCategoryFilter> { | ||
| val parentEntry = remember(navController) { | ||
| navController.getBackStackEntry(PreferCategory) | ||
| } | ||
|
|
||
| val categoryVm: PreferCategoryStudyViewModel = hiltViewModel(parentEntry) | ||
| PreferCategoryStudyFilterScreen( |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
androidx navigation NavController getBackStackEntry behavior when destination is not on back stack
💡 Result:
Short answer: NavController.getBackStackEntry(...) requires the destination to be on the NavController's back stack and will throw an IllegalArgumentException if it is not. If you need a safe check, call getCurrentDestination() or inspect the back stack (or catch the exception) instead. [1][2]
Sources:
- NavController.getBackStackEntry docs (throws IllegalArgumentException if destination is not on the back stack). [1]
- Navigation/back stack guide (behavior of current destination and empty back stack). [2]
References:
[1] AndroidX Navigation — NavController.getBackStackEntry API.
[2] Android Developers — Navigation and the back stack guide.
🏁 Script executed:
find . -path "*/preferCategory/navigation*" -type fRepository: SPOTeam/Android-V2
Length of output: 291
🏁 Script executed:
cat -n ./feature/study/src/main/java/com/umcspot/spot/study/preferCategory/navigation/PreferCategoryStudyFilterNavigation.ktRepository: SPOTeam/Android-V2
Length of output: 1755
🏁 Script executed:
cat -n ./feature/study/src/main/java/com/umcspot/spot/study/preferCategory/navigation/PreferCategoryStudyNavigation.ktRepository: SPOTeam/Android-V2
Length of output: 1390
🏁 Script executed:
rg -A 5 -B 5 "preferCategoryStudyFilterGraph" --type kotlinRepository: SPOTeam/Android-V2
Length of output: 4357
🏁 Script executed:
cat -n ./feature/main/src/main/java/com/umcspot/spot/main/MainNavHost.kt | grep -A 30 "preferCategoryStudyGraph"Repository: SPOTeam/Android-V2
Length of output: 3026
PreferCategory가 백스택에 없을 때 크래시 발생 가능
getBackStackEntry(PreferCategory)는 해당 destination이 백스택에 없으면 IllegalArgumentException을 발생시킵니다. 현재 코드는 다음 두 가지 위험성이 있습니다:
- 필터 화면이 PreferCategory를 거치지 않고 진입될 수 있는 경로 존재 (깊은 링크, 상태 복원 등)
- 예외 처리 없이 백스택 엔트리를 직접 접근
다음 중 하나로 해결하세요:
- PreferCategory 진입을 강제하거나
navController.getBackStackEntry(PreferCategory)를 try-catch로 감싸고 안전한 폴백 처리 구현
🤖 Prompt for AI Agents
In
`@feature/study/src/main/java/com/umcspot/spot/study/preferCategory/navigation/PreferCategoryStudyFilterNavigation.kt`
around lines 24 - 30, getBackStackEntry(PreferCategory) can throw if
PreferCategory isn't on the back stack; wrap the call to
navController.getBackStackEntry(PreferCategory) in a try-catch and provide a
safe fallback: if try succeeds use that parentEntry to obtain the
PreferCategoryStudyViewModel via hiltViewModel(parentEntry), otherwise obtain a
fallback ViewModel with hiltViewModel() (or explicitly navigate to
PreferCategory before showing the filter) and pass that categoryVm into
PreferCategoryStudyFilterScreen; update the code around
navController.getBackStackEntry, PreferCategoryStudyViewModel and
PreferCategoryStudyFilterScreen to use this safe pattern.
Related issue 🛠
Work Description 📝
Screenshot 📸
Uncompleted Tasks 😅
PR Point 📌
트러블 슈팅 💥
Summary by CodeRabbit
새로운 기능
변경
✏️ Tip: You can customize this high-level summary in your review settings.