[UI] 데이터 없는 화면, 사용자 찾기 화면 구현#75
Conversation
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... 📒 Files selected for processing (4)
Walkthrough여러 Compose UI 컴포넌트와 화면에 "데이터 없음" 상태를 처리하는 뷰와 메시지가 추가되었습니다. 기존 북마크/피드 저장 화면, 검색 및 피드 화면 등에서 데이터가 없을 때 보여줄 UI와 문자열 리소스가 대거 보강되었으며, 관련 ViewModel과 미리보기(Preview)도 추가 및 수정되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI
participant ViewModel
User->>UI: 화면 진입/검색/탭 전환
UI->>ViewModel: 데이터 요청 (피드/책/반응/검색 등)
ViewModel-->>UI: 데이터 목록 반환
alt 데이터 없음
UI->>User: "데이터 없음" 메시지 및 Empty UI 표시
else 데이터 존재
UI->>User: 데이터 리스트 렌더링
end
User->>UI: (필요시) 인터랙션 (ex. thipNum 클릭, 북마크, 검색어 삭제)
UI->>ViewModel: 상태 변경 요청 (옵션)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20분 Assessment against linked issues
Assessment against linked issues: Out-of-scope changes해당 이슈(#74)의 "데이터 없는 페이지 생성" 목적과 직접 관련 없는 변경사항은 발견되지 않았습니다. Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip You can disable sequence diagrams in the walkthrough.Disable the ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 19
🔭 Outside diff range comments (2)
app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedFeedViewModel.kt (1)
9-112: 하위 클래스에서 상태 플로우가 분리되어 토글이 반영되지 않는 결함(Shadowing)EmptySavedFeedViewModel이 별도의
_feeds를 정의하고feeds만 override해, 상위의 toggleBookmark/Like가 상위_feeds만 갱신합니다. 결과적으로 EmptySavedFeedViewModel의feeds에는 토글 변화가 반영되지 않습니다.상위에 단일 가변 플로우를 두고 이를 override 가능하게 열어주는 방식으로 정리하세요.
수정 예:
-open class SavedFeedViewModel: ViewModel() { - private val _feeds = MutableStateFlow( +open class SavedFeedViewModel : ViewModel() { + protected open val mutableFeeds: MutableStateFlow<List<FeedItem>> = MutableStateFlow( listOf( ... 기존 목데이터 ... ) ) - - open val feeds: StateFlow<List<FeedItem>> = _feeds + open val feeds: StateFlow<List<FeedItem>> = mutableFeeds fun toggleBookmark(id: Int) { - _feeds.value = _feeds.value.map { + mutableFeeds.value = mutableFeeds.value.map { if (it.id == id) it.copy(isSaved = !it.isSaved) else it } } fun toggleLike(id: Int) { - _feeds.value = _feeds.value.map { + mutableFeeds.value = mutableFeeds.value.map { if (it.id == id) it.copy(isLiked = !it.isLiked) else it } } } -class EmptySavedFeedViewModel : SavedFeedViewModel() { - - private val _feeds = MutableStateFlow<List<FeedItem>>(emptyList()) - - override val feeds: StateFlow<List<FeedItem>> = _feeds - -} +class EmptySavedFeedViewModel : SavedFeedViewModel() { + override val mutableFeeds: MutableStateFlow<List<FeedItem>> = + MutableStateFlow(emptyList()) +}이렇게 하면 상위 토글 로직이 언제나 동일한 플로우 인스턴스를 갱신하므로, 서브클래스에서도 일관되게 반영됩니다.
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt (1)
181-201: onContentClick TODO 처리 및 lastIndex 기준 리스트 불일치 개선
- onContentClick가 비어 있어 내비게이션이 동작하지 않습니다. 주석대로 댓글 화면으로 이동하도록 연결하세요.
- Divider 조건에서 feeds.lastIndex를 사용하고 있는데, 루프는 feedStateList를 순회하므로 기준 리스트가 다릅니다. 일관성 있게 feedStateList.lastIndex를 사용하는 것이 안전합니다.
MyFeedCard( feedItem = feed, onLikeClick = { val updated = feed.copy( isLiked = !feed.isLiked, likeCount = if (feed.isLiked) feed.likeCount - 1 else feed.likeCount + 1 ) feedStateList[index] = updated }, - onContentClick = {} //TODO FeedCommentScreen으로 + onContentClick = { + // TODO: 실제 라우트로 교체 + navController?.navigate("feedComment/${feed.id}") + } ) Spacer(modifier = Modifier.height(40.dp)) -if (index != feeds.lastIndex) { +if (index != feedStateList.lastIndex) { HorizontalDivider( color = colors.DarkGrey02, thickness = 10.dp ) }내비게이션 라우트 문자열은 프로젝트의 NavGraph 규칙에 맞게 조정이 필요합니다. 원하시면 해당 화면 연결까지 PR에 반영할 수 있도록 도와드릴게요.
🧹 Nitpick comments (23)
app/src/main/res/values/strings.xml (2)
303-306: 피드 빈 상태 문구 추가는 적절합니다문구 톤과 스타일은 기존 리소스와 자연스럽습니다. 필요 시 마침표/감탄사 사용 일관성만 한 번 더 점검 부탁드립니다.
333-336: 검색 관련 문자열 리소스 추가 적절새로 추가된 사용자 검색/빈 결과 문구는 명확하고 UI 구성요소와의 연결도 자연스럽습니다. SearchPeopleEmptyResult에서 이 리소스를 직접 사용하면 중복/하드코딩을 줄일 수 있습니다.
app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt (1)
102-118: 접근성 및 터치 타겟 개선 제안(선택)thipNum 영역이 클릭 가능해진 만큼 최소 터치 영역(예: padding)과 semantics(role 등)을 부여하면 접근성이 좋아집니다. 아이콘에도 설명이 필요하면 contentDescription을 고려하세요.
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt (3)
165-179: 빈 상태 레이아웃: 고정 dp 대신 부모 높이 기반 정렬 권장.top padding 244.dp는 기기 해상도/상태바/탭 높이에 따라 어긋날 수 있습니다. LazyColumn 아이템에서는 fillParentMaxSize를 활용해 중앙 정렬로 표현하는 편이 더 견고합니다.
- Box( - modifier = Modifier - .fillMaxWidth() - .padding(top = 244.dp), - contentAlignment = Alignment.TopCenter - ) { + Box( + modifier = Modifier + .fillParentMaxSize(), + contentAlignment = Alignment.Center + ) { Text( text = stringResource(R.string.create_feed), style = typography.smalltitle_sb600_s18_h24, - color = colors.White + color = colors.White ) }참고: fillParentMaxSize는 LazyColumn 아이템 내부에서 빈 상태를 스크린 중앙에 배치할 때 유용합니다.
280-289: Preview 중복 ThipTheme 제거Preview 내부에서 ThipTheme를 중첩 적용하고 있습니다. 불필요한 중첩으로 인한 부작용(예: 상태바 사이드 이펙트) 가능성이 있으니 하나로 통일하세요.
- ThipTheme { - FeedScreen( - nickname = "ThipUser01", - userRole = "문학 칭호", - selectedTabIndex = 1, - feeds = mockFeeds, - totalFeedCount = mockFeeds.size, - followerProfileImageUrls = mockFollowerImages - ) - } + FeedScreen( + nickname = "ThipUser01", + userRole = "문학 칭호", + selectedTabIndex = 1, + feeds = mockFeeds, + totalFeedCount = mockFeeds.size, + followerProfileImageUrls = mockFollowerImages + )
300-309: 두 번째 Preview도 ThipTheme 중첩 해제 권장위와 동일하게 중첩된 ThipTheme를 제거하세요.
- ThipTheme { - FeedScreen( - nickname = "ThipUser01", - userRole = "문학 칭호", - selectedTabIndex = 1, - feeds = mockFeeds, - totalFeedCount = mockFeeds.size, - followerProfileImageUrls = mockFollowerImages - ) - } + FeedScreen( + nickname = "ThipUser01", + userRole = "문학 칭호", + selectedTabIndex = 1, + feeds = mockFeeds, + totalFeedCount = mockFeeds.size, + followerProfileImageUrls = mockFollowerImages + )app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (1)
34-46: 아이템 액션에 콜백 사용 및 패딩 제안
- ViewModel 호출을 콜백으로 교체하세요.
- 가독성과 스크롤 여백을 위해 contentPadding 추가를 고려할 수 있습니다.
- LazyColumn { + LazyColumn( + contentPadding = androidx.compose.foundation.layout.PaddingValues(bottom = 16.dp) + ) { items(feedList, key = { it.id }) { feed -> val profileImagePainter = feed.userProfileImage?.let { painterResource(it) } SavedFeedCard( feedItem = feed, profileImage = profileImagePainter, - onBookmarkClick = { viewModel.toggleBookmark(feed.id) }, - onLikeClick = { viewModel.toggleLike(feed.id) } + onBookmarkClick = { onToggleBookmark(feed.id) }, + onLikeClick = { onToggleLike(feed.id) } ) } }app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt (2)
95-102: 이미지 로딩 품질 개선(플레이스홀더/에러 처리)네트워크 이미지에 대한 placeHolder/error를 지정하면 깜빡임과 실패 시 UX를 개선할 수 있습니다.
AsyncImage( model = profile.profileImageUrl, contentDescription = null, modifier = Modifier .size(36.dp) .clip(CircleShape) .background(Color.LightGray), placeholder = painterResource(R.drawable.ic_profile_placeholder), error = painterResource(R.drawable.ic_profile_placeholder) )ic_profile_placeholder가 없다면 추가 생성이 필요합니다.
114-119: 접근성 보완(역할/라벨)우측 셰브론 아이콘은 장식용이므로 contentDescription = null 유지가 맞습니다. 다만 전체 Row가 클릭 가능하므로 Row에 역할/라벨을 부여하면 스크린리더 접근성이 향상됩니다.
Row( modifier = Modifier .fillMaxWidth() .height(58.dp) .clickable { onClick() } .semantics { role = Role.Button; contentDescription = stringResource(R.string.my_subscription) }, verticalAlignment = Alignment.CenterVertically ) { ... }app/src/main/java/com/texthip/thip/ui/feed/component/PeopleRecentSearch.kt (1)
53-60: 중복 키워드 제거(선택 사항)같은 키워드가 중복 저장될 수 있다면 distinct()로 중복을 제거해 가독성을 높일 수 있습니다.
- recentSearches.take(9).forEach { keyword -> + recentSearches.distinct().take(9).forEach { keyword ->app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt (1)
40-47: Divider를 Spacer+background 대신 HorizontalDivider로 교체하여 일관성과 접근성을 높이세요.다른 화면(
FeedOthersScreen)에서도HorizontalDivider를 사용 중입니다. 동일한 컴포넌트를 사용하면 코드 가독성과 스타일 일관성이 좋아집니다.- Spacer( - modifier = Modifier - .padding(vertical = 12.dp, horizontal = 20.dp) - .fillMaxWidth() - .height(1.dp) - .background(colors.DarkGrey02) - ) + androidx.compose.material3.HorizontalDivider( + modifier = Modifier + .padding(vertical = 12.dp, horizontal = 20.dp), + thickness = 1.dp, + color = colors.DarkGrey02 + )app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt (3)
50-54: TopAppBar 뒤로가기 핸들러 구현 누락
onLeftClick = {}는 사용자 경험상 뒤로가기를 기대하게 만듭니다. NavController 등을 연결해 뒤로가기 동작을 구현해주세요. 필요하시면 내비게이션 코드 생성 도와드리겠습니다.
137-174: Preview 내 ThipTheme 중복 감싸기 제거
ThipTheme안에서 다시ThipTheme를 감싸 중복 적용되고 있습니다. 불필요한 중첩을 제거하세요.- ThipTheme { - FeedOthersScreen( - nickname = "ThipUser01", - userRole = "문학 칭호", - feeds = mockFeeds, - totalFeedCount = mockFeeds.size, - followerProfileImageUrls = mockFollowerImages - ) - } + FeedOthersScreen( + nickname = "ThipUser01", + userRole = "문학 칭호", + feeds = mockFeeds, + totalFeedCount = mockFeeds.size, + followerProfileImageUrls = mockFollowerImages + )
176-193: 두 번째 Preview도 ThipTheme 중복 제거- ThipTheme { - FeedOthersScreen( - nickname = "ThipUser01", - userRole = "문학 칭호", - feeds = mockFeeds, - totalFeedCount = mockFeeds.size, - followerProfileImageUrls = mockFollowerImages - ) - } + FeedOthersScreen( + nickname = "ThipUser01", + userRole = "문학 칭호", + feeds = mockFeeds, + totalFeedCount = mockFeeds.size, + followerProfileImageUrls = mockFollowerImages + )app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt (1)
134-137: 배경색 중복 적용 제거 검토
ThipTheme가 루트에 검은 배경을 깔고 있습니다. 화면에서도Modifier.background(colors.Black)를 추가로 적용해 중복될 수 있습니다. 테마 일관성을 위해 배경 지정은 하나로 유지하세요.app/src/main/java/com/texthip/thip/ui/feed/screen/SearchPeopleScreen.kt (4)
45-48: 최근 검색어 초기값 하드코딩 제거실서비스에서는 임시 키워드(“메롱…”) 대신 빈 목록으로 시작하는 것이 자연스럽습니다. 필요 시 샘플은 Preview에서만 사용하세요.
- var recentSearches by rememberSaveable { - mutableStateOf(listOf("메롱", "메메롱", "메메메롱", "메메메", "메메루메루메루")) - } + var recentSearches by rememberSaveable { mutableStateOf(emptyList<String>()) }
78-82: 첫 진입 시 키보드 포커스 이동 또는 FocusRequester 제거
focusRequester를 부착했지만 실제로requestFocus()를 호출하지 않습니다. 초기 포커스를 원하는 경우 아래처럼 호출하고, 아니면 관련 코드 제거를 권장합니다.LaunchedEffect(isSearched) { if (isSearched) { focusManager.clearFocus() } } + LaunchedEffect(Unit) { + focusRequester.requestFocus() + }
111-116: 최근 검색어 중복 저장 방지(대소문자·공백 무시) 로직 보강현재는 단순
contains로 대소문자/공백 차이의 중복을 허용합니다.- onSearch = { query -> - if (query.isNotBlank() && !recentSearches.contains(query)) { - recentSearches = (listOf(query) + recentSearches).take(10) - } + onSearch = { query -> + val q = query.trim() + val exists = recentSearches.any { it.equals(q, ignoreCase = true) } + if (q.isNotBlank() && !exists) { + recentSearches = (listOf(q) + recentSearches).take(10) + } isSearched = true }
128-133: 결과 카운트 문자열 리소스의 의미 명확화
group_searched_room_size는 “그룹/방” 문맥의 리소스로 보입니다. 사람 검색에는 별도의 리소스(예:search_people_result_count)를 두어 복잡한 재사용을 피하세요.리소스 추가와 교체를 제안드립니다. 필요 시 strings.xml 패치도 도와드리겠습니다.
app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt (4)
47-51: Composable 파라미터의 ViewModel 기본값 분리로 테스트/미리보기/DI 스코프 개선 제안현재 기본값에서
viewModel()을 직접 호출하는 패턴은 동작상 문제는 없지만, DI 스코프(특히 NavGraph별 스코프 또는 Hilt 사용 시)와 미리보기를 분리하기엔 덜 유연합니다. 다음처럼 오버로드로 분리하면 테스트/프리뷰/스코프 제어가 쉬워집니다.
- NavHost 내에서 화면을 사용할 때 ViewModel 스코프가 의도한 Owner(예: navBackStackEntry)에 묶이는지 확인 부탁드립니다. Hilt 사용 중이면
hiltViewModel()로 대체하는 것도 고려해 주세요.-@Composable -fun SavedScreen( - feedViewModel: SavedFeedViewModel = viewModel(), - bookViewModel: SavedBookViewModel = viewModel() -) { +@Composable +fun SavedScreen( + feedViewModel: SavedFeedViewModel, + bookViewModel: SavedBookViewModel +) { // ... 본문 동일 ... } + +// 기본 진입 오버로드: 실제 화면 사용 시에만 ViewModel 획득 +@Composable +fun SavedScreen() { + val feedVm: SavedFeedViewModel = viewModel() + val bookVm: SavedBookViewModel = viewModel() + SavedScreen(feedVm, bookVm) +}
70-72: 하드코딩된 너비(160dp/60dp) 제거로 가변 텍스트/현지화 대응력 향상탭 라벨 길이(현지화)에 따라 잘림/겹침 위험이 있습니다. TabRow는 기본적으로 탭을 균등 분배하므로 고정폭을 제거하는 편이 안전합니다.
- Box(modifier = Modifier - .width(160.dp) - .padding(start = 20.dp)) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) {- Tab( - modifier = Modifier.width(60.dp), + Tab( + modifier = Modifier, selected = selected, onClick = { selectedTabIndex = index },추가로 TabRow 자체에 가로 폭을 명시해 균등 분배를 확실히 하려면(선택):
TabRow( modifier = Modifier.fillMaxWidth(), selectedTabIndex = selectedTabIndex, // ... )Also applies to: 95-95
126-130: 미리보기도 테마로 감싸 일관된 배경/타이포 확인 권장다른 Preview(
SavedScreenWithoutFeedPrev)는ThipTheme로 감싸지만, 본 미리보기는 테마가 없어 실제 배경/색 대비 검증이 어렵습니다. 통일을 권장합니다.@Preview @Composable private fun SavedScreenPrev() { - SavedScreen( + ThipTheme { + SavedScreen( feedViewModel = SavedFeedViewModel(), bookViewModel = SavedBookViewModel() - ) + ) + } }
132-141: 빈 상태 프리뷰(LGTM) — 실제 다크 배경·타이포까지 검증 가능Empty VM으로 상태 시뮬레이션하고 테마를 적용해 시각적 확인이 용이합니다. 필요 시 북만 비어있는 경우/피드만 비어있는 경우 등 조합 프리뷰도 추가하면 QA가 더 수월합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
app/src/main/res/drawable/search_character_image.pngis excluded by!**/*.png
📒 Files selected for processing (18)
app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/feed/component/FeedSubscribelistBar.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/feed/component/PeopleRecentSearch.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/feed/component/SearchPeopleEmptyResult.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/feed/screen/SearchPeopleScreen.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveBook.kt(0 hunks)app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveFeed.kt(0 hunks)app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt(5 hunks)app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt(2 hunks)app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedFeedViewModel.kt(3 hunks)app/src/main/res/values/strings.xml(3 hunks)
💤 Files with no reviewable changes (2)
- app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveBook.kt
- app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveFeed.kt
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt:108-112
Timestamp: 2025-07-01T07:19:10.981Z
Learning: The user rbqks529 prefers to extract hardcoded UI strings to StringResource files (strings.xml) rather than keeping them inline in Compose components, which is a good practice for maintainability and localization in Android development.
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/myPage/groupPage/GroupPageScreen.kt:34-37
Timestamp: 2025-07-01T07:19:01.239Z
Learning: GroupPageScreen의 MyPageViewModel은 임시 ViewModel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다.
📚 Learning: 2025-07-01T07:19:10.981Z
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt:108-112
Timestamp: 2025-07-01T07:19:10.981Z
Learning: The user rbqks529 prefers to extract hardcoded UI strings to StringResource files (strings.xml) rather than keeping them inline in Compose components, which is a good practice for maintainability and localization in Android development.
Applied to files:
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.ktapp/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.ktapp/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.ktapp/src/main/res/values/strings.xml
📚 Learning: 2025-07-01T07:19:01.239Z
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/myPage/groupPage/GroupPageScreen.kt:34-37
Timestamp: 2025-07-01T07:19:01.239Z
Learning: GroupPageScreen의 MyPageViewModel은 임시 ViewModel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다.
Applied to files:
app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt
🧬 Code Graph Analysis (8)
app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (1)
app/src/main/java/com/texthip/thip/ui/mypage/component/SavedFeedCard.kt (1)
SavedFeedCard(33-134)
app/src/main/java/com/texthip/thip/ui/feed/component/SearchPeopleEmptyResult.kt (1)
app/src/main/java/com/texthip/thip/ui/theme/Theme.kt (1)
ThipTheme(41-69)
app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt (1)
app/src/main/java/com/texthip/thip/ui/common/cards/CardBookList.kt (1)
CardBookList(37-104)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt (1)
app/src/main/java/com/texthip/thip/ui/theme/Theme.kt (1)
ThipTheme(41-69)
app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt (1)
app/src/main/java/com/texthip/thip/ui/theme/Theme.kt (1)
ThipTheme(41-69)
app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt (4)
app/src/main/java/com/texthip/thip/ui/common/topappbar/DefaultTopAppBar.kt (1)
DefaultTopAppBar(22-65)app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt (1)
OptionChipButton(30-92)app/src/main/java/com/texthip/thip/ui/common/cards/CardAlarm.kt (1)
CardAlarm(39-148)app/src/main/java/com/texthip/thip/ui/theme/Theme.kt (1)
ThipTheme(41-69)
app/src/main/java/com/texthip/thip/ui/feed/screen/SearchPeopleScreen.kt (5)
app/src/main/java/com/texthip/thip/ui/common/topappbar/DefaultTopAppBar.kt (1)
DefaultTopAppBar(22-65)app/src/main/java/com/texthip/thip/ui/common/forms/SearchBookTextField.kt (1)
SearchBookTextField(38-112)app/src/main/java/com/texthip/thip/ui/feed/component/SearchPeopleEmptyResult.kt (1)
SearchPeopleEmptyResult(16-32)app/src/main/java/com/texthip/thip/ui/feed/component/PeopleRecentSearch.kt (1)
PeopleRecentSearch(27-63)app/src/main/java/com/texthip/thip/ui/theme/Theme.kt (1)
ThipTheme(41-69)
app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt (3)
app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (1)
FeedContent(26-47)app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt (1)
BookContent(27-49)app/src/main/java/com/texthip/thip/ui/theme/Theme.kt (1)
ThipTheme(41-69)
🔇 Additional comments (8)
app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt (1)
51-70: 빈 상태 UI 구성 적절문구를 문자열 리소스로 추출하고, 중앙 정렬로 안내 메시지를 제공한 점 좋습니다. 테마 타이포그래피/컬러 일관성도 양호합니다.
app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (1)
49-68: 빈 상태 UI 구성 적절문구/스타일/정렬 모두 일관되고 명확합니다. 다른 Empty 컴포넌트들과 톤 앤 매너가 잘 맞습니다.
app/src/main/java/com/texthip/thip/ui/feed/component/PeopleRecentSearch.kt (1)
27-63: 최근 검색 UI 구성 적절
- 문자열 리소스 사용 및 FlowRow로 2줄 제한, 9개 캡 처리 모두 적절합니다.
- Chip의 onClose로 개별 삭제 UX도 명확합니다.
app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt (1)
22-38: 중복 정의 없음 확인됨스크립트 실행 결과
SearchPeopleResult함수는LiveSearchPeopleResult.kt파일에서만 정의되어 있어, 동일 패키지 내 중복 선언으로 인한 빌드 오류는 발생하지 않습니다.app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt (1)
11-13: bookList 사용처 점검 완료 – 추가 수정 불필요
books프로퍼티를 참조하는 호출부가 모두bookList로 통합되어 있어, 더 이상의 호출부 수정은 필요하지 않습니다.
- app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt:55
- app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt:31 (주석 처리된 예시)
app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt (3)
3-3: 임포트 변경사항 확인됨 — 추가 코멘트 없음기능/리팩토링 흐름에 부합하는 임포트 추가로 보이며 별도 이슈는 없습니다.
Also applies to: 18-18, 31-31, 35-35, 37-41
113-115: 상태 수집을 상위(SavedScreen)로 끌어올린 구조, 재사용성/테스트성 향상에 적합
FeedContent/BookContent가 데이터와 ViewModel을 주입받도록 변경되어 컴포저블 재사용과 UI 테스트가 수월해졌습니다. 빈 상태 처리도 하위 컴포넌트에서 일관되게 수행됩니다. 굿.
54-55:collectAsStateWithLifecycle사용을 위해 필요한 의존성이 프로젝트에 포함되어 있지 않아 보입니다.수동으로 다음을 확인해주세요:
androidx.lifecycle:lifecycle-runtime-compose의존성이build.gradle(또는 버전 카탈로그) 파일에 추가되어 있는지의존성이 없을 경우 아래와 같이 추가해야 합니다:
implementation "androidx.lifecycle:lifecycle-runtime-compose:<latest-version>"
app/src/main/java/com/texthip/thip/ui/feed/component/FeedSubscribelistBar.kt
Show resolved
Hide resolved
| itemsIndexed(peopleList) { index, user -> | ||
| AuthorHeader( | ||
| profileImage = user.profileImageUrl, | ||
| nickname = user.nickname, | ||
| badgeText = user.role, | ||
| profileImageSize = 36.dp, | ||
| showButton = false, | ||
| showThipNum = true, | ||
| thipNum = user.subscriberCount, | ||
| onThipNumClick = { onThipNumClick(user) } | ||
| ) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
LazyColumn 아이템에 안정적 key를 지정해 재구성 비용과 스크롤 깜빡임을 줄여주세요.
현재 itemsIndexed(peopleList)에 key가 없어 Diff 계산 시 불필요한 재구성이 발생할 수 있습니다. 고유 식별자가 있다면 그 값을 key로 사용하세요. (닉네임이 유일하지 않을 수 있으므로 가능하면 id 사용 권장)
다음과 같이 적용을 제안드립니다(예: 임시로 nickname 사용):
- itemsIndexed(peopleList) { index, user ->
+ itemsIndexed(peopleList, key = { _, user -> user.nickname }) { index, user ->닉네임이 유일하지 않다면 MySubscriptionData에 id를 추가한 뒤 해당 id를 key로 사용해주세요.
📝 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.
| itemsIndexed(peopleList) { index, user -> | |
| AuthorHeader( | |
| profileImage = user.profileImageUrl, | |
| nickname = user.nickname, | |
| badgeText = user.role, | |
| profileImageSize = 36.dp, | |
| showButton = false, | |
| showThipNum = true, | |
| thipNum = user.subscriberCount, | |
| onThipNumClick = { onThipNumClick(user) } | |
| ) | |
| itemsIndexed(peopleList, key = { _, user -> user.nickname }) { index, user -> | |
| AuthorHeader( | |
| profileImage = user.profileImageUrl, | |
| nickname = user.nickname, | |
| badgeText = user.role, | |
| profileImageSize = 36.dp, | |
| showButton = false, | |
| showThipNum = true, | |
| thipNum = user.subscriberCount, | |
| onThipNumClick = { onThipNumClick(user) } | |
| ) |
🤖 Prompt for AI Agents
In
app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt
around lines 28 to 38, the LazyColumn's itemsIndexed call lacks a stable key,
causing unnecessary recompositions and scroll flickering. Fix this by adding a
key parameter to itemsIndexed using a unique identifier for each user,
preferably an id if available; if not, temporarily use the nickname as the key.
If the data model does not have an id, add one to ensure stable keys.
| if (subscriptions.isEmpty()) { | ||
| EmptyMySubscriptionBar() | ||
| } else { | ||
| Row( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(58.dp) | ||
| .clickable { onClick() }, |
There was a problem hiding this comment.
빈 구독 바 클릭 액션 누락(기능적 이슈)
subscriptions가 비어 있을 때 EmptyMySubscriptionBar가 자체 clickable { }을 갖지만 onClick을 호출하지 않습니다. 사용자가 빈 상태를 눌러 검색/구독으로 진입할 수 있도록 onClick을 전달하세요.
- if (subscriptions.isEmpty()) {
- EmptyMySubscriptionBar()
+ if (subscriptions.isEmpty()) {
+ EmptyMySubscriptionBar(onClick = onClick)
} else {- @Composable
- private fun EmptyMySubscriptionBar() {
+ @Composable
+ private fun EmptyMySubscriptionBar(onClick: () -> Unit) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(42.dp)
.clip(RoundedCornerShape(8.dp))
.background(colors.DarkGrey02)
- .clickable { }
+ .clickable { onClick() }
) {
Text(
modifier = Modifier
.align(Alignment.CenterStart)
.padding(start = 12.dp),
text = stringResource(R.string.find_thip_mate),
color = colors.White,
style = typography.view_m500_s12_h20
)
Icon(
painter = painterResource(id = R.drawable.search_character_image),
contentDescription = null,
tint = Color.Unspecified,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(end = 12.dp)
.width(32.dp)
.height(42.dp)
)
}
}Also applies to: 124-154
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt
around lines 79 to 86 and also lines 124 to 154, the EmptyMySubscriptionBar
component is missing the onClick callback invocation on its clickable modifier.
Modify EmptyMySubscriptionBar to accept the onClick lambda and ensure it is
called when the empty subscription bar is clicked, enabling navigation to
search/subscribe functionality.
| modifier: Modifier= Modifier, | ||
| mainText: String | ||
| ) { | ||
| Column( | ||
| modifier = Modifier.fillMaxSize(), | ||
| verticalArrangement = Arrangement.Center, |
There was a problem hiding this comment.
🛠️ Refactor suggestion
전달받은 modifier가 사용되지 않습니다
외부에서 넘긴 modifier를 반영해야 조합성이 살아납니다.
적용 diff 예:
- Column(
- modifier = Modifier.fillMaxSize(),
+ Column(
+ modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {📝 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.
| modifier: Modifier= Modifier, | |
| mainText: String | |
| ) { | |
| Column( | |
| modifier = Modifier.fillMaxSize(), | |
| verticalArrangement = Arrangement.Center, | |
| modifier: Modifier= Modifier, | |
| mainText: String | |
| ) { | |
| Column( | |
| modifier = modifier.fillMaxSize(), | |
| verticalArrangement = Arrangement.Center, | |
| horizontalAlignment = Alignment.CenterHorizontally | |
| ) { |
🤖 Prompt for AI Agents
In
app/src/main/java/com/texthip/thip/ui/feed/component/SearchPeopleEmptyResult.kt
around lines 18 to 23, the passed-in modifier parameter is not used inside the
Column composable, which breaks composability. Replace the hardcoded
Modifier.fillMaxSize() with modifier.fillMaxSize() to apply the external
modifier properly while still filling the max size.
| Row(modifier = Modifier.padding(start = 20.dp, top = 20.dp, bottom = 20.dp)) { | ||
| OptionChipButton( | ||
| text = stringResource(R.string.likes), | ||
| isFilled = true, | ||
| onClick = { isLikesSelected = !isLikesSelected } | ||
| ) | ||
| Spacer(modifier = Modifier.width(12.dp)) | ||
| OptionChipButton( | ||
| text = stringResource(R.string.comments), | ||
| isFilled = true, | ||
| onClick = { isCommentsSelected = !isCommentsSelected } | ||
| ) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Chip의 선택 상태를 외부 상태로 제어하도록 isSelected를 지정하세요.
현재 OptionChipButton은 내부 상태도 토글하기 때문에 외부 isLikesSelected와 불일치 위험이 있습니다. 제어형 컴포넌트로 사용하세요.
OptionChipButton(
text = stringResource(R.string.likes),
isFilled = true,
+ isSelected = isLikesSelected,
onClick = { isLikesSelected = !isLikesSelected }
)
Spacer(modifier = Modifier.width(12.dp))
OptionChipButton(
text = stringResource(R.string.comments),
isFilled = true,
+ isSelected = isCommentsSelected,
onClick = { isCommentsSelected = !isCommentsSelected }
)🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt
around lines 146 to 157, the OptionChipButton components toggle their own
internal state, which can cause inconsistency with the external isLikesSelected
and isCommentsSelected states. To fix this, remove internal state toggling
inside OptionChipButton and instead pass the external isLikesSelected and
isCommentsSelected as the isSelected parameter, controlling the selection state
externally. Also, update the onClick handlers to only toggle the external state
variables without changing internal state.
| text = stringResource(R.string.no_saved_reation), | ||
| style = typography.smalltitle_sb600_s18_h24, | ||
| color = colors.White | ||
| ) | ||
| Text( | ||
| text = stringResource(R.string.save_first_reaction), | ||
| style = typography.feedcopy_r400_s14_h20, | ||
| color = colors.Grey, | ||
| modifier = Modifier.padding(top = 8.dp) | ||
| ) | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
문자열 리소스 키 오타 의심: no_saved_reation → no_saved_reaction
리소스 키가 오타로 보입니다. 키와 실제 strings.xml 값을 정정해 주세요. 빌드/번역 관리 시 혼란을 줄입니다.
다음 스크립트로 키 사용처를 확인하고 일괄 수정하세요:
🏁 Script executed:
#!/bin/bash
# 'no_saved_reation' 키 검색
rg -n "no_saved_reation" -S
# strings.xml 내 정의 위치 확인
fd strings.xml | xargs -I{} rg -n "no_saved_reation" {}Length of output: 405
리소스 키 오타 수정 필요: no_saved_reation → no_saved_reaction
strings.xml과 코드에서 해당 키를 일관되게 수정해 주세요. 그렇지 않으면 빌드나 번역 관리 시 혼란이 발생할 수 있습니다.
- app/src/main/res/values/strings.xml (133행)
- app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt (166행)
수정 예시:
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -133,7 +133,7 @@
- <string name="no_saved_reation">아직 저장한 반응이 없어요</string>
+ <string name="no_saved_reaction">아직 저장한 반응이 없어요</string>--- a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt
+++ b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt
@@ -166,7 +166,7 @@
- text = stringResource(R.string.no_saved_reation),
+ text = stringResource(R.string.no_saved_reaction),📝 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.
| text = stringResource(R.string.no_saved_reation), | |
| style = typography.smalltitle_sb600_s18_h24, | |
| color = colors.White | |
| ) | |
| Text( | |
| text = stringResource(R.string.save_first_reaction), | |
| style = typography.feedcopy_r400_s14_h20, | |
| color = colors.Grey, | |
| modifier = Modifier.padding(top = 8.dp) | |
| ) | |
| } | |
| text = stringResource(R.string.no_saved_reaction), | |
| style = typography.smalltitle_sb600_s18_h24, | |
| color = colors.White | |
| ) | |
| Text( | |
| text = stringResource(R.string.save_first_reaction), | |
| style = typography.feedcopy_r400_s14_h20, | |
| color = colors.Grey, | |
| modifier = Modifier.padding(top = 8.dp) | |
| ) |
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt
at line 166 and in app/src/main/res/values/strings.xml at line 133, the resource
key "no_saved_reation" is misspelled. Rename this key to "no_saved_reaction"
consistently in both the strings.xml file and the Kotlin code to prevent build
errors and translation issues.
app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt (3)
11-12: 공개 StateFlow 일원화는 잘 반영되었습니다. 다만books는 굳이open일 필요가 없습니다.상태의 단일 소스를 보장하려면 서브클래스가 별도 Flow를 노출하지 못하게
books는final유지가 더 안전합니다._books를protected로 둔 현재 구조라면 상태 수정은 서브클래스에서 충분히 가능합니다.적용 예:
- open val books: StateFlow<List<BookItem>> = _books + val books: StateFlow<List<BookItem>> = _books
14-19: init에서 open 메서드 호출은 지양 권장. Empty ViewModel을 위해 override no-op이 필요한 구조는 설계 신호입니다.현재 구조는 부모 init에서
loadMockBooks()(open)를 호출하고, EmptySavedBookViewModel이 이를 no-op으로 덮어쓰는 방식입니다. 이는
- 상속 초기화 순서에 취약(초기화 전 다형성 호출),
- detekt(EmptyFunctionBlock) 경고 유발의 근본 원인,
- 서브클래스가 상태 흐름을 분기시킬 여지를 만듭니다.
두 가지 대안 제안:
- 옵션 A(권장, 변경 영향 최소): “사전 채움 여부”를 생성자 인자로 받습니다. 미리보기에서는
prepopulate = false로 호출해 빈 상태를 만들고, 더 이상 open 메서드 override가 필요 없습니다.- 옵션 B(대안): 기본 목업 데이터를 상수/팩토리로 분리하고, 호출 측(Preview/DI)에서 명시적으로
loadMockBooks()를 호출하도록 변경하여 부모 init에서 open 호출을 제거합니다.옵션 A 예시:
open class SavedBookViewModel( prepopulate: Boolean = true ) : ViewModel() { protected val _books = MutableStateFlow<List<BookItem>>(emptyList()) val books: StateFlow<List<BookItem>> = _books init { if (prepopulate) _books.value = DEFAULT_BOOKS } companion object { private val DEFAULT_BOOKS: List<BookItem> = listOf( // 기존 목업 아이템들 ) } } class EmptySavedBookViewModel : SavedBookViewModel(prepopulate = false)옵션 B 예시(호출 측으로 위임):
open class SavedBookViewModel : ViewModel() { protected val _books = MutableStateFlow<List<BookItem>>(emptyList()) val books: StateFlow<List<BookItem>> = _books // init { loadMockBooks() } 제거 open fun loadMockBooks() { _books.value = DEFAULT_BOOKS } }또한, 현재 목업 리스트는 동일 아이템 블록이 반복됩니다. 간결성을 위해 생성 유틸을 쓰는 편이 유지보수에 유리합니다.
private fun mockBooks(count: Int = 8): List<BookItem> = List(count) { idx -> BookItem( id = idx + 1, title = "이기적 유전자", author = "리처드 도킨스", publisher = "을유문화사", imageUrl = null, isSaved = true ) }
87-89: StateFlow 갱신은update {}사용을 권장합니다.읽기→쓰기 패턴보다
update가 간결하고 잠재적 경합에도 더 안전합니다.적용 예:
+import kotlinx.coroutines.flow.update @@ - _books.value = _books.value.map { - if (it.id == id) it.copy(isSaved = !it.isSaved) else it - } + _books.update { list -> + list.map { if (it.id == id) it.copy(isSaved = !it.isSaved) else it } + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/feed/screen/SearchPeopleScreen.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt(5 hunks)app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt(2 hunks)app/src/main/res/values/strings.xml(3 hunks)
✅ Files skipped from review due to trivial changes (1)
- app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt
🚧 Files skipped from review as they are similar to previous changes (5)
- app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt
- app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt
- app/src/main/java/com/texthip/thip/ui/feed/screen/SearchPeopleScreen.kt
- app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt
- app/src/main/res/values/strings.xml
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt:108-112
Timestamp: 2025-07-01T07:19:10.981Z
Learning: The user rbqks529 prefers to extract hardcoded UI strings to StringResource files (strings.xml) rather than keeping them inline in Compose components, which is a good practice for maintainability and localization in Android development.
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/myPage/groupPage/GroupPageScreen.kt:34-37
Timestamp: 2025-07-01T07:19:01.239Z
Learning: GroupPageScreen의 MyPageViewModel은 임시 ViewModel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다.
🪛 detekt (1.23.8)
app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt
[warning] 94-94: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
🔇 Additional comments (1)
app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt (1)
5-5: 별도 조치 불필요해당 import 변경은 리뷰 포인트 없음으로 스킵합니다.
| class EmptySavedBookViewModel : SavedBookViewModel() { | ||
| override fun loadMockBooks() {} | ||
|
|
||
| } No newline at end of file |
There was a problem hiding this comment.
🛠️ Refactor suggestion
detekt(EmptyFunctionBlock) 경고 해결: 최소 @Suppress 또는 주석 추가. 근본적으로는 부모 init 설계 개선이 바람직합니다.
현재 override는 의도적 no-op이므로 제거할 수 없습니다. 경고 억제를 위해 주석 혹은 @Suppress를 추가하세요. 상단 코멘트의 옵션 A/B를 채택하면 이 override 자체가 불필요해집니다.
빠른 수정:
-class EmptySavedBookViewModel : SavedBookViewModel() {
- override fun loadMockBooks() {}
+class EmptySavedBookViewModel : SavedBookViewModel() {
+ @Suppress("EmptyFunctionBlock")
+ override fun loadMockBooks() { /* no-op for empty preview */ }
}📝 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.
| class EmptySavedBookViewModel : SavedBookViewModel() { | |
| override fun loadMockBooks() {} | |
| } | |
| class EmptySavedBookViewModel : SavedBookViewModel() { | |
| @Suppress("EmptyFunctionBlock") | |
| override fun loadMockBooks() { /* no-op for empty preview */ } | |
| } |
🧰 Tools
🪛 detekt (1.23.8)
[warning] 94-94: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedBookViewModel.kt
around lines 93 to 96, the override of loadMockBooks is an intentional no-op but
triggers a detekt EmptyFunctionBlock warning. To fix this quickly, add either a
@Suppress annotation or a comment explaining the intentional empty override to
suppress the warning. Alternatively, consider refactoring the parent class
initialization to avoid needing this override.
➕ 이슈 링크
🔎 작업 내용
데이터 없는 화면
새로 추가된 screen
📸 스크린샷
데이터 없는 화면






새로 추가된 screen
bandicam.2025-08-09.14-01-44-672.mp4
😢 해결하지 못한 과제
📢 리뷰어들에게
캡쳐, 화면녹화를 듀얼모니터에서 해서 그런가 올리고 보니 비율이 이상하게 캡쳐된 것들이 보이네용.. 양해 부탁드려욧.. 실제로는 좌우 padding 값 이상 없습니닷!
Summary by CodeRabbit
신규 기능
기능 개선
버그 수정
문서 및 스타일
테스트 및 프리뷰