Conversation
- 홈 화면 검색바 아래 상세 탐색 진입 카드 추가 - DetailExploreDialogBottomSheet → DetailExploreActivity (Compose)로 전환 - 별점 기준을 단일값 → 0.0~5.0 범위 슬라이더로 변경 - 정보/키워드 탭, 커스텀 RangeSlider, S3 카테고리 이미지 연결
- ExploreFragment, fragment_explore.xml 삭제 - BottomNav 메뉴에서 menu_explore 항목 제거 - ic_main_explore drawable 및 main_ic_explore, explore_title, explore_detail_search_button 문자열 제거 - MainActivity FragmentType.EXPLORE 분기 제거
- 필터 버튼 클릭 시 finish() 처리로 변경하여 이전 DetailExploreActivity 상태를 그대로 사용 - DetailExploreResultDialogBottomSheet/InfoFragment/KeywordFragment 및 dialog/fragment xml 삭제 - DetailExploreResultViewModel에서 편집 관련 state 및 메서드 제거
- fragment_home.xml에서 관심글 섹션(빈/등록/추천) 3개 컨테이너 제거 - HomeFragment/HomeViewModel/HomeUiState에서 userInterestFeeds 관련 상태 및 메서드 제거 - UserInterestFeedAdapter/ViewHolder, item_user_interest_feed.xml 삭제 - FeedRepository.fetchUserInterestFeeds, FeedApi.getUserInterestFeeds, mapper, DTO, Entity 제거 (app + data/feed 모듈) - 관심글 관련 string 리소스 정리
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Walkthrough탐색(Explore) 탭 및 user-interest 피드 관련 네트워크·모델·매퍼·레포지토리·프래그먼트/레이아웃을 제거하고, Compose 기반의 DetailExplore Activity/스크린·컴포넌트(RatingRangeSlider, SelectableChip 등), ViewModel/UseCase/리소스 및 홈 진입로(상세검색 카드)로 전환했습니다. ChangesDetail Explore — 데이터형/API → 도메인 → UI 전환
Sequence Diagram(s)sequenceDiagram
participant User
participant Home as HomeFragment
participant Activity as DetailExploreActivity
participant VM as DetailExploreViewModel
participant UseCase as GetDetailExploreResultUseCase
participant Result as DetailExploreResultActivity
participant Browser
User->>Home: 홈의 상세검색 카드 탭
Home->>Activity: startActivity(DetailExploreActivity)
User->>Activity: 장르/상태/평점 범위/키워드 선택
Activity->>VM: updateSelected... (장르/상태/평점범위/키워드)
User->>Activity: 검색 CTA 클릭
Activity->>VM: 현재 필터값 요청
VM->>UseCase: invoke(genres, isCompleted, ratingStart, ratingEnd, keywordIds)
UseCase->>Activity: ExploreResult 반환
Activity->>Result: startActivity(DetailExploreResultActivity with filters)
alt 키워드 문의
Activity->>Browser: ACTION_VIEW(inquire_link)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
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🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@app/src/main/java/com/into/websoso/ui/detailExplore/component/DetailExploreKeywordTab.kt`:
- Around line 79-105: searchValue is kept only in local remember and you flip
search-mode too early via updateIsSearchKeywordProceeding(true), causing UI
desync; either lift search query and search-mode into the ViewModel or change
handlers so the ViewModel is only updated on actual search/clear actions.
Concretely: stop calling viewModel.updateIsSearchKeywordProceeding(true) on
every onValueChange, instead call viewModel.updateKeyword(searchValue.text) and
viewModel.updateIsSearchKeywordProceeding(true) only from the onSearch handler
(and call viewModel.initSearchKeyword() and
updateIsSearchKeywordProceeding(false) on onClear); update usages around
searchValue, KeywordSearchField, viewModel.updateKeyword(),
viewModel.initSearchKeyword(), and viewModel.updateIsSearchKeywordProceeding()
accordingly so UI state remains authoritative in the ViewModel.
In
`@app/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreViewModel.kt`:
- Around line 32-40: The current separate LiveData fields _selectedRatingMin and
_selectedRatingMax cause intermediate inconsistent states when updated; replace
them with a single MutableLiveData holding a rating range object (e.g., data
class RatingRange(val min: Float, val max: Float)) named _selectedRatingRange
and expose selectedRatingRange: LiveData<RatingRange>; update all callers that
set either min or max to post a new RatingRange atomically via a helper like
updateRatingRange(newMin?, newMax?) and change dependent derived LiveData
(selectedRating, isInfoChipSelected, and any other mappings referenced around
selectedRating/selectedRatingMin/selectedRatingMax usages) to map from
selectedRatingRange instead of separate min/max LiveData so observers only see
consistent range updates.
In `@app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt`:
- Around line 159-165: On successful fetchPopularFeeds() handling in the
onSuccess lambda, reset the error flag on _uiState by copying uiState.value and
setting error = false in addition to updating popularFeeds (i.e., update
_uiState.value = uiState.value?.copy(popularFeeds =
popularFeeds.popularFeeds.chunked(3), error = false)), so a prior failure no
longer shows after a successful refresh; modify the onSuccess block around
fetchPopularFeeds() accordingly.
In
`@feature/library/src/main/java/com/into/websoso/feature/library/component/LibraryTopBar.kt`:
- Around line 36-46: The clickable icon in LibraryTopBar (Box/Image using
debouncedClickable and onSearchClick) currently has contentDescription = null
and lacks button semantics; update the Image (or the Box's Modifier) to provide
an accessible label and button semantics by replacing contentDescription = null
with a meaningful string (or stringResource) and adding a semantics modifier
that sets role = Role.Button and an onClick semantic that invokes onSearchClick
(or ensure semantics are merged so the existing debouncedClickable is exposed to
accessibility). This ensures the action is exposed to screen readers while
keeping the existing debouncedClickable behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6a488562-761a-468c-b4b6-6f8c566a023d
⛔ Files ignored due to path filters (1)
core/resource/src/main/res/drawable-xxhdpi/img_home_detail_search.pngis excluded by!**/*.png
📒 Files selected for processing (52)
app/src/main/AndroidManifest.xmlapp/src/main/java/com/into/websoso/data/mapper/FeedMapper.ktapp/src/main/java/com/into/websoso/data/model/UserInterestFeedsEntity.ktapp/src/main/java/com/into/websoso/data/remote/api/FeedApi.ktapp/src/main/java/com/into/websoso/data/remote/response/UserInterestFeedsResponseDto.ktapp/src/main/java/com/into/websoso/data/repository/FeedRepository.ktapp/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreActivity.ktapp/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreDialogBottomSheet.ktapp/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreScreen.ktapp/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreViewModel.ktapp/src/main/java/com/into/websoso/ui/detailExplore/component/DetailExploreAppBar.ktapp/src/main/java/com/into/websoso/ui/detailExplore/component/DetailExploreCtaButton.ktapp/src/main/java/com/into/websoso/ui/detailExplore/component/DetailExploreInfoTab.ktapp/src/main/java/com/into/websoso/ui/detailExplore/component/DetailExploreKeywordTab.ktapp/src/main/java/com/into/websoso/ui/detailExplore/component/RatingRangeSlider.ktapp/src/main/java/com/into/websoso/ui/detailExplore/component/SelectableChip.ktapp/src/main/java/com/into/websoso/ui/detailExplore/info/DetailExploreInfoFragment.ktapp/src/main/java/com/into/websoso/ui/detailExplore/info/model/Rating.ktapp/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreClickListener.ktapp/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreKeywordFragment.ktapp/src/main/java/com/into/websoso/ui/detailExplore/keyword/adapter/DetailExploreKeywordAdapter.ktapp/src/main/java/com/into/websoso/ui/detailExplore/keyword/adapter/DetailExploreKeywordViewHolder.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultActivity.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultDialogBottomSheet.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultInfoFragment.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultKeywordFragment.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultViewModel.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/model/DetailExploreResultUiState.ktapp/src/main/java/com/into/websoso/ui/main/MainActivity.ktapp/src/main/java/com/into/websoso/ui/main/explore/ExploreFragment.ktapp/src/main/java/com/into/websoso/ui/main/home/HomeFragment.ktapp/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.ktapp/src/main/java/com/into/websoso/ui/main/home/adpater/UserInterestFeedAdapter.ktapp/src/main/java/com/into/websoso/ui/main/home/adpater/UserInterestFeedViewHolder.ktapp/src/main/java/com/into/websoso/ui/main/home/model/HomeUiState.ktapp/src/main/res/layout/dialog_detail_explore.xmlapp/src/main/res/layout/fragment_detail_explore_info.xmlapp/src/main/res/layout/fragment_detail_explore_keyword.xmlapp/src/main/res/layout/fragment_detail_explore_result_info.xmlapp/src/main/res/layout/fragment_detail_explore_result_keyword.xmlapp/src/main/res/layout/fragment_explore.xmlapp/src/main/res/layout/fragment_home.xmlapp/src/main/res/layout/item_user_interest_feed.xmlapp/src/main/res/menu/menu_main_bnv.xmlcore/network/src/main/java/com/into/websoso/core/network/datasource/feed/model/response/UserInterestFeedsResponseDto.ktcore/resource/src/main/res/drawable/ic_main_explore.xmlcore/resource/src/main/res/drawable/ic_plus_novel.xmlcore/resource/src/main/res/values/strings.xmldata/feed/src/main/java/com/into/websoso/data/feed/mapper/FeedMapper.ktdata/feed/src/main/java/com/into/websoso/data/feed/model/UserInterestFeedsEntity.ktfeature/library/src/main/java/com/into/websoso/feature/library/LibraryScreen.ktfeature/library/src/main/java/com/into/websoso/feature/library/component/LibraryTopBar.kt
💤 Files with no reviewable changes (32)
- app/src/main/res/layout/dialog_detail_explore.xml
- app/src/main/java/com/into/websoso/data/remote/api/FeedApi.kt
- app/src/main/java/com/into/websoso/ui/detailExplore/info/model/Rating.kt
- app/src/main/java/com/into/websoso/data/model/UserInterestFeedsEntity.kt
- app/src/main/res/menu/menu_main_bnv.xml
- app/src/main/res/layout/fragment_detail_explore_info.xml
- core/network/src/main/java/com/into/websoso/core/network/datasource/feed/model/response/UserInterestFeedsResponseDto.kt
- core/resource/src/main/res/drawable/ic_main_explore.xml
- app/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreClickListener.kt
- app/src/main/java/com/into/websoso/ui/main/explore/ExploreFragment.kt
- app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt
- app/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreKeywordFragment.kt
- app/src/main/java/com/into/websoso/data/mapper/FeedMapper.kt
- data/feed/src/main/java/com/into/websoso/data/feed/model/UserInterestFeedsEntity.kt
- app/src/main/java/com/into/websoso/ui/main/home/adpater/UserInterestFeedAdapter.kt
- app/src/main/res/layout/item_user_interest_feed.xml
- app/src/main/res/layout/fragment_detail_explore_result_info.xml
- app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultDialogBottomSheet.kt
- app/src/main/java/com/into/websoso/ui/main/MainActivity.kt
- app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultInfoFragment.kt
- app/src/main/java/com/into/websoso/data/remote/response/UserInterestFeedsResponseDto.kt
- app/src/main/java/com/into/websoso/ui/detailExploreResult/model/DetailExploreResultUiState.kt
- app/src/main/java/com/into/websoso/ui/detailExplore/keyword/adapter/DetailExploreKeywordAdapter.kt
- app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultKeywordFragment.kt
- app/src/main/java/com/into/websoso/ui/main/home/adpater/UserInterestFeedViewHolder.kt
- data/feed/src/main/java/com/into/websoso/data/feed/mapper/FeedMapper.kt
- app/src/main/res/layout/fragment_explore.xml
- app/src/main/java/com/into/websoso/ui/detailExplore/keyword/adapter/DetailExploreKeywordViewHolder.kt
- app/src/main/res/layout/fragment_detail_explore_result_keyword.xml
- app/src/main/res/layout/fragment_detail_explore_keyword.xml
- app/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreDialogBottomSheet.kt
- app/src/main/java/com/into/websoso/ui/detailExplore/info/DetailExploreInfoFragment.kt
| var searchValue by remember { mutableStateOf(TextFieldValue("")) } | ||
|
|
||
| val selectedKeywords = remember(uiState.categories) { | ||
| uiState.categories.flatMap { it.keywords }.filter { it.isSelected } | ||
| } | ||
|
|
||
| Column(modifier = modifier.fillMaxWidth()) { | ||
| KeywordSearchField( | ||
| value = searchValue, | ||
| onValueChange = { value -> | ||
| searchValue = value | ||
| if (value.text.isEmpty()) { | ||
| viewModel.initSearchKeyword() | ||
| } else { | ||
| viewModel.updateIsSearchKeywordProceeding(true) | ||
| } | ||
| }, | ||
| onSearch = { | ||
| if (searchValue.text.isEmpty()) { | ||
| viewModel.initSearchKeyword() | ||
| } else { | ||
| viewModel.updateKeyword(searchValue.text) | ||
| } | ||
| }, | ||
| onClear = { | ||
| searchValue = TextFieldValue("") | ||
| viewModel.initSearchKeyword() |
There was a problem hiding this comment.
검색 입력과 검색모드를 로컬 상태로 두면 UI가 쉽게 어긋납니다.
searchValue가 remember에만 있고, updateIsSearchKeywordProceeding(true)를 타이핑 직후 호출해서 실제 검색 전에 결과 모드로 들어갑니다. 이 상태로 탭을 바꾸거나 reset하면 입력창은 비는데 이전 검색 결과가 남을 수 있습니다. 쿼리와 검색모드를 ViewModel로 올리거나, 최소한 검색 제출 시점까지는 결과 모드로 전환하지 않도록 조정해 주세요.
Also applies to: 116-136
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/into/websoso/ui/detailExplore/component/DetailExploreKeywordTab.kt`
around lines 79 - 105, searchValue is kept only in local remember and you flip
search-mode too early via updateIsSearchKeywordProceeding(true), causing UI
desync; either lift search query and search-mode into the ViewModel or change
handlers so the ViewModel is only updated on actual search/clear actions.
Concretely: stop calling viewModel.updateIsSearchKeywordProceeding(true) on
every onValueChange, instead call viewModel.updateKeyword(searchValue.text) and
viewModel.updateIsSearchKeywordProceeding(true) only from the onSearch handler
(and call viewModel.initSearchKeyword() and
updateIsSearchKeywordProceeding(false) on onClear); update usages around
searchValue, KeywordSearchField, viewModel.updateKeyword(),
viewModel.initSearchKeyword(), and viewModel.updateIsSearchKeywordProceeding()
accordingly so UI state remains authoritative in the ViewModel.
| feedRepository.fetchPopularFeeds() | ||
| }.onSuccess { popularFeeds -> | ||
| _uiState.value = uiState.value?.copy( | ||
| popularFeeds = popularFeeds.popularFeeds.chunked(3), | ||
| isInterestNovel = isUserInterestedInNovels(userInterestFeeds.message), | ||
| userInterestFeeds = userInterestFeeds.userInterestFeeds, | ||
| ) | ||
| }.onFailure { | ||
| _uiState.value = uiState.value?.copy( | ||
| error = true, | ||
| ) | ||
| _uiState.value = uiState.value?.copy(error = true) |
There was a problem hiding this comment.
갱신 성공 시 에러 플래그를 초기화하세요.
fetchPopularFeeds()가 성공해도 error를 다시 false로 돌리지 않아서, 이전 실패 후 새로고침이 성공하면 에러 UI가 계속 남을 수 있습니다.
간단한 수정안
}.onSuccess { popularFeeds ->
_uiState.value = uiState.value?.copy(
popularFeeds = popularFeeds.popularFeeds.chunked(3),
+ error = false,
)📝 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.
| feedRepository.fetchPopularFeeds() | |
| }.onSuccess { popularFeeds -> | |
| _uiState.value = uiState.value?.copy( | |
| popularFeeds = popularFeeds.popularFeeds.chunked(3), | |
| isInterestNovel = isUserInterestedInNovels(userInterestFeeds.message), | |
| userInterestFeeds = userInterestFeeds.userInterestFeeds, | |
| ) | |
| }.onFailure { | |
| _uiState.value = uiState.value?.copy( | |
| error = true, | |
| ) | |
| _uiState.value = uiState.value?.copy(error = true) | |
| feedRepository.fetchPopularFeeds() | |
| }.onSuccess { popularFeeds -> | |
| _uiState.value = uiState.value?.copy( | |
| popularFeeds = popularFeeds.popularFeeds.chunked(3), | |
| error = false, | |
| ) | |
| }.onFailure { | |
| _uiState.value = uiState.value?.copy(error = true) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt` around
lines 159 - 165, On successful fetchPopularFeeds() handling in the onSuccess
lambda, reset the error flag on _uiState by copying uiState.value and setting
error = false in addition to updating popularFeeds (i.e., update _uiState.value
= uiState.value?.copy(popularFeeds = popularFeeds.popularFeeds.chunked(3), error
= false)), so a prior failure no longer shows after a successful refresh; modify
the onSuccess block around fetchPopularFeeds() accordingly.
| Box( | ||
| modifier = Modifier | ||
| .debouncedClickable(onClick = onSearchClick) | ||
| .padding(horizontal = 20.dp, vertical = 8.dp), | ||
| ) { | ||
| Image( | ||
| imageVector = ImageVector.vectorResource(id = ic_plus_novel), | ||
| contentDescription = null, | ||
| modifier = Modifier.size(24.dp), | ||
| ) | ||
| } |
There was a problem hiding this comment.
액션 버튼에 접근성 라벨과 버튼 semantics를 추가해 주세요.
지금은 클릭 가능한 아이콘인데 contentDescription = null 이라 스크린리더에서 기능이 드러나지 않습니다. 상단바의 유일한 행동 버튼이므로 접근성상 바로 수정하는 게 좋습니다.
♿ 제안 수정안
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
@@
Box(
modifier = Modifier
.debouncedClickable(onClick = onSearchClick)
+ .semantics { role = Role.Button }
.padding(horizontal = 20.dp, vertical = 8.dp),
) {
Image(
imageVector = ImageVector.vectorResource(id = ic_plus_novel),
- contentDescription = null,
+ contentDescription = "서재에서 검색",
modifier = Modifier.size(24.dp),
)
}📝 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.
| Box( | |
| modifier = Modifier | |
| .debouncedClickable(onClick = onSearchClick) | |
| .padding(horizontal = 20.dp, vertical = 8.dp), | |
| ) { | |
| Image( | |
| imageVector = ImageVector.vectorResource(id = ic_plus_novel), | |
| contentDescription = null, | |
| modifier = Modifier.size(24.dp), | |
| ) | |
| } | |
| import androidx.compose.ui.Alignment | |
| import androidx.compose.ui.Modifier | |
| import androidx.compose.ui.semantics.Role | |
| import androidx.compose.ui.semantics.role | |
| import androidx.compose.ui.semantics.semantics | |
| import androidx.compose.ui.graphics.vector.ImageVector | |
| import androidx.compose.ui.res.vectorResource | |
| import androidx.compose.ui.unit.dp | |
| Box( | |
| modifier = Modifier | |
| .debouncedClickable(onClick = onSearchClick) | |
| .semantics { role = Role.Button } | |
| .padding(horizontal = 20.dp, vertical = 8.dp), | |
| ) { | |
| Image( | |
| imageVector = ImageVector.vectorResource(id = ic_plus_novel), | |
| contentDescription = "서재에서 검색", | |
| modifier = Modifier.size(24.dp), | |
| ) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@feature/library/src/main/java/com/into/websoso/feature/library/component/LibraryTopBar.kt`
around lines 36 - 46, The clickable icon in LibraryTopBar (Box/Image using
debouncedClickable and onSearchClick) currently has contentDescription = null
and lacks button semantics; update the Image (or the Box's Modifier) to provide
an accessible label and button semantics by replacing contentDescription = null
with a meaningful string (or stringResource) and adding a semantics modifier
that sets role = Role.Button and an onClick semantic that invokes onSearchClick
(or ensure semantics are merged so the existing debouncedClickable is exposed to
accessibility). This ensures the action is exposed to screen readers while
keeping the existing debouncedClickable behavior.
- final-newline: 10개 파일에 누락된 개행 추가 - blank-line-between-when-conditions: DetailExploreScreen when 조건 사이 빈 줄 추가 - function-signature: updateSelectedRatingRange 파라미터 멀티라인 포맷 - import-ordering: DetailExploreAppBar, DetailExploreKeywordTab import 순서 수정 - no-blank-line-in-list: DetailExploreInfoTab StatusSection 호출 내 불필요한 빈 줄 제거 - if-else-wrapping/multiline-if-else: RatingRangeSlider if-else 중괄호 및 개행 추가 - backing-property-naming: DetailExploreResultViewModel 미노출 backing property 이름 변경 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/main/java/com/into/websoso/domain/usecase/GetDetailExploreResultUseCase.kt (1)
29-33:⚠️ Potential issue | 🟠 Major | ⚡ Quick win상세 탐색 캐시 재사용 시
resultCount가 잘못 계산됩니다.Line 31이
cachedNormalExploreResult.size를 사용하고 있어, 상세 탐색 캐시(cachedDetailExploreResult)를 반환할 때 결과 개수가 틀어집니다.수정 제안
- resultCount = novelRepository.cachedNormalExploreResult.size.toLong(), + resultCount = novelRepository.cachedDetailExploreResult.size.toLong(),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/into/websoso/domain/usecase/GetDetailExploreResultUseCase.kt` around lines 29 - 33, The resultCount is calculated from the wrong cache when reusing detailed explore cache in GetDetailExploreResultUseCase: change the value used for resultCount from novelRepository.cachedNormalExploreResult.size to novelRepository.cachedDetailExploreResult.size when returning ExploreResultEntity while isSearchButtonClick && isCacheValid(...) so the returned resultCount matches the cachedDetailExploreResult and preserve other fields like isLoadable and novels (cachedDetailExploreIsLoadable and cachedDetailExploreResult).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@app/src/main/java/com/into/websoso/domain/usecase/GetDetailExploreResultUseCase.kt`:
- Around line 72-76: 현재 null인 필드 비교에서 genres?.equals(previousGenres) 및
keywordIds?.equals(previousKeywordIds)처럼 수신자가 null일 때 항상 false가 되어 캐시 재사용이
실패합니다; GetDetailExploreResultUseCase 안의 해당 조건 블록을 찾아 nullable 안전 동치 비교로 바꿔주세요
(예: genres == previousGenres 및 keywordIds == previousKeywordIds 또는 이전값을 왼쪽에 두고
안전한 비교(previousGenres == genres)처럼), 나머지 불리언/범위 비교(novelRatingStart/End,
isCompleted)는 그대로 유지하여 동일한 검색 조건일 때 캐시가 올바르게 재사용되도록 수정하세요.
---
Outside diff comments:
In
`@app/src/main/java/com/into/websoso/domain/usecase/GetDetailExploreResultUseCase.kt`:
- Around line 29-33: The resultCount is calculated from the wrong cache when
reusing detailed explore cache in GetDetailExploreResultUseCase: change the
value used for resultCount from novelRepository.cachedNormalExploreResult.size
to novelRepository.cachedDetailExploreResult.size when returning
ExploreResultEntity while isSearchButtonClick && isCacheValid(...) so the
returned resultCount matches the cachedDetailExploreResult and preserve other
fields like isLoadable and novels (cachedDetailExploreIsLoadable and
cachedDetailExploreResult).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: dc9f0ba7-37ef-4bef-99ad-59bdbdf8e60e
📒 Files selected for processing (6)
app/src/main/java/com/into/websoso/data/remote/api/NovelApi.ktapp/src/main/java/com/into/websoso/data/repository/NovelRepository.ktapp/src/main/java/com/into/websoso/domain/usecase/GetDetailExploreResultUseCase.ktapp/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreActivity.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultViewModel.ktapp/src/main/java/com/into/websoso/ui/detailExploreResult/model/DetailExploreFilteredModel.kt
🚧 Files skipped from review as they are similar to previous changes (2)
- app/src/main/java/com/into/websoso/ui/detailExplore/DetailExploreActivity.kt
- app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultViewModel.kt
| genres?.equals(previousGenres) == true && | ||
| isCompleted == previousIsCompleted && | ||
| novelRating == previousNovelRating && | ||
| novelRatingStart == previousNovelRatingStart && | ||
| novelRatingEnd == previousNovelRatingEnd && | ||
| keywordIds?.equals(previousKeywordIds) == true |
There was a problem hiding this comment.
null 필터 조건에서 캐시 유효성 검사가 항상 실패합니다.
Line 72, Line 76은 현재 값이 null일 때 무조건 false가 되어, 동일 검색 조건이어도 캐시를 재사용하지 못합니다.
수정 제안
- genres?.equals(previousGenres) == true &&
+ genres == previousGenres &&
isCompleted == previousIsCompleted &&
novelRatingStart == previousNovelRatingStart &&
novelRatingEnd == previousNovelRatingEnd &&
- keywordIds?.equals(previousKeywordIds) == true
+ keywordIds == previousKeywordIds🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@app/src/main/java/com/into/websoso/domain/usecase/GetDetailExploreResultUseCase.kt`
around lines 72 - 76, 현재 null인 필드 비교에서 genres?.equals(previousGenres) 및
keywordIds?.equals(previousKeywordIds)처럼 수신자가 null일 때 항상 false가 되어 캐시 재사용이
실패합니다; GetDetailExploreResultUseCase 안의 해당 조건 블록을 찾아 nullable 안전 동치 비교로 바꿔주세요
(예: genres == previousGenres 및 keywordIds == previousKeywordIds 또는 이전값을 왼쪽에 두고
안전한 비교(previousGenres == genres)처럼), 나머지 불리언/범위 비교(novelRatingStart/End,
isCompleted)는 그대로 유지하여 동일한 검색 조건일 때 캐시가 올바르게 재사용되도록 수정하세요.
📌𝘐𝘴𝘴𝘶𝘦𝘴
📎𝘞𝘰𝘳𝘬 𝘋𝘦𝘴𝘤𝘳𝘪𝘱𝘵𝘪𝘰𝘯
📷𝘚𝘤𝘳𝘦𝘦𝘯𝘴𝘩𝘰𝘵
Screen_recording_20260501_143559.webm
Screen_recording_20260501_143408.webm
💬𝘛𝘰 𝘙𝘦𝘷𝘪𝘦𝘸𝘦𝘳𝘴
아직 상세 탐색 평점이 서버가 범위로 api 가 바뀌지 않은 상태라 그 부분 빼고 확인 부탁드려용-> 연결 완료
Summary by CodeRabbit
새로운 기능
개선 사항
제거