Skip to content

[REFACTOR] 3번째 QA 진행#119

Merged
rbqks529 merged 16 commits intoTHIP-TextHip:developfrom
Nico1eKim:refactor/#101-qa3
Aug 20, 2025
Merged

[REFACTOR] 3번째 QA 진행#119
rbqks529 merged 16 commits intoTHIP-TextHip:developfrom
Nico1eKim:refactor/#101-qa3

Conversation

@Nico1eKim
Copy link
Member

@Nico1eKim Nico1eKim commented Aug 20, 2025

➕ 이슈 링크


🔎 작업 내용

  • 커밋기록 확인해주세여 ..
  • 가장 큰 수정사항은 프로필 눌렀을 때 내가 주인이면 내 프로필로 이동하도록 화면 생성하고 api 연결했습니다

📸 스크린샷


😢 해결하지 못한 과제

  • [] TASK


📢 리뷰어들에게

  • 참고해야 할 사항들을 적어주세요

Summary by CodeRabbit

  • New Features

    • 내 피드 화면 추가 및 Feed 경로(My) 도입
    • 구독자 목록에서 내 프로필/타인 프로필 분기 이동
    • 저장함: 책/피드 항목 클릭으로 상세/댓글 이동
    • 도서 카드·피드 카드에 행/콘텐츠 클릭 지원
    • 장르 칩 선택 최대 5개 제한
  • UI/UX

    • 이미지 뷰어 배경 반투명 처리
    • 댓글 화면 메뉴·삭제 다이얼로그·토스트 플로우 개선
    • 팔로우 토스트 애니메이션 추가
    • 키보드 대응 패딩·스크롤 개선(노트/투표 생성, 검색 바텀시트)
    • 하단 내비 좌우 여백 축소, 빈 피드 안내 위치 조정
    • 목록 구분선/간격 조정
  • Localization

    • ‘게시글 신고를 완료했어요.’ 문구 추가

@coderabbitai
Copy link

coderabbitai bot commented Aug 20, 2025

Walkthrough

여러 UI/네비게이션/모델 변경이 포함됨. 주요 내용은: 퍼센티지 타입(Double→Int) 변경 전파, 팔로워 모델에 isMyself 추가, 댓글 액션 모드(enum) 및 관련 파라미터 제거, 피드 마이 화면 추가와 네비게이션 분기(내 프로필/타인) 도입, 클릭 핸들러(onClick) 확장, 레이아웃/토스트/오버레이 조정, 테마 색상/문자열 추가.

Changes

Cohort / File(s) Summary
데이터 모델 변경
app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt, app/src/main/java/com/texthip/thip/data/model/users/response/OthersFollowersResponse.kt
userPercentage 타입 Double→Int로 변경. FollowerList에 isMyself:Boolean 필드 추가(SerializedName 포함).
댓글 액션 모드 제거 및 API 단순화
app/src/main/java/com/texthip/thip/ui/common/CommentActionMode.kt, .../group/note/component/CommentItem.kt, .../group/note/component/ReplyItem.kt, .../group/note/component/CommentSection.kt, .../group/note/component/CommentBottomSheet.kt
CommentActionMode enum 삭제. CommentItem/ReplyItem/CommentSection에서 actionMode, 선택/팝업 관련 파라미터 제거 및 내부 로직 삭제. BottomSheet 호출부에서 actionMode 전달 제거.
칩/버튼 동작 조정
.../ui/common/buttons/OptionChipButton.kt, .../ui/common/buttons/SubGenreChipRow.kt
비활성화 시 텍스트/보더 색상 고정(DarkGrey/ DarkGrey02). 서브장르 최대 5개 선택 제한 및 비선택 칩 비활성화 로직 추가.
카드/마이페이지 클릭 핸들러 확장
.../ui/common/cards/CardBookList.kt, .../ui/mypage/component/BookContent.kt, .../ui/mypage/component/FeedContent.kt, .../ui/mypage/screen/MypageSaveScreen.kt, .../ui/navigator/navigations/MyPageNavigation.kt
CardBookList에 onClick 추가. BookContent/FeedContent/MypageSaveScreen에 onBookClick/onFeedClick 콜백 추가 및 전파. MyPageNavigation에서 해당 콜백으로 도서상세/피드댓글로 네비게이션.
피드 화면/오버레이/토스트/신규 화면
.../ui/feed/screen/FeedCommentScreen.kt, .../ui/feed/screen/FeedMyScreen.kt, .../ui/feed/screen/FeedOthersScreen.kt, .../ui/feed/screen/FeedScreen.kt
FeedCommentScreen에 메뉴/삭제 다이얼로그/토스트 상태 모델 정리 및 오버레이 계산 추가. FeedMyScreen 추가(내 피드 표시). Others 화면 토스트에 AnimatedVisibility 적용. FeedScreen 레이아웃 여백 조정.
네비게이션 확장(내 피드 경로)
.../ui/navigator/navigations/FeedNavigation.kt, .../ui/navigator/routes/FeedRoutes.kt, .../ui/navigator/navigations/GroupNavigation.kt
FeedViewModel 연동해 myUserId 파생. 사용자 클릭 시 내 프로필은 FeedRoutes.My로, 그 외는 Others로 분기. 새 Route FeedRoutes.My 추가 및 FeedMyScreen 연결. 구독 리스트 클릭도 isMyself 기반 분기.
이미지/테마/문자열
.../ui/feed/component/ImageViewerModal.kt, .../ui/theme/Color.kt, app/src/main/res/values/strings.xml
ImageViewerModal에 반투명(Black80) 배경 적용. 테마에 Black80 색 추가 및 default 세팅 확장. feed 신고 완료 문자열 추가.
그룹-룸/도서 검색 UI 조정
.../ui/group/room/component/GroupRoomBody.kt, .../ui/group/room/screen/GroupRoomScreen.kt, .../ui/group/makeroom/component/GroupBookListWithScrollbar.kt, .../ui/group/makeroom/component/GroupBookSearchBottomSheet.kt
GroupRoomBody의 userPercentage 파라미터 Int로 변경 및 사용처/프리뷰 반영. 스크롤바 리스트 높이 고정 제거 및 구분선/간격 단순화. 도서 검색 시 80% 높이/IME 패딩 적용.
그룹-노트 작성/투표 화면 스크롤/IME 대응
.../ui/group/note/screen/GroupNoteCreateScreen.kt, .../ui/group/note/screen/GroupVoteCreateScreen.kt
advancedImePadding와 verticalScroll 적용해 키보드/긴 콘텐츠 대응.
하단 네비게이션 바
.../ui/navigator/BottomNavigationBar.kt
좌우 패딩 32→20dp로 변경, Preview 추가.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant FeedNav as FeedNavigation
  participant VM as FeedViewModel
  participant Routes as FeedRoutes
  participant Screen as FeedScreen/FeedMyScreen
  User->>FeedNav: 사용자 프로필 클릭(userId, isMyself?)
  FeedNav->>VM: uiState 수집(myFeedInfo.creatorId = myUserId)
  alt isMyself == true or userId == myUserId
    FeedNav->>Routes: navigate(FeedRoutes.My)
    Routes-->>Screen: FeedMyScreen(viewModel)
  else
    FeedNav->>Routes: navigate(FeedRoutes.Others(userId))
    Routes-->>Screen: OthersProfile/Feed
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant FCS as FeedCommentScreen
  participant VM as FeedDetailViewModel
  Note over FCS: 상태: isPostMenuVisible, isCommentMenuVisible,<br/>showDeleteDialog, showToast, toastMessage
  User->>FCS: 앱바 액션(메뉴)
  FCS->>FCS: isPostMenuVisible = true
  User->>FCS: 댓글 롱프레스(commentId, isWriter)
  FCS->>FCS: selectedCommentForMenu 설정<br/>isCommentMenuVisible = true
  alt 댓글 작성자
    User->>FCS: 삭제 선택
    FCS->>VM: DeleteComment(commentId)
    FCS->>FCS: isCommentMenuVisible = false
  else 타인
    User->>FCS: 신고 선택
    FCS->>FCS: toastMessage 설정, showToast = true
    Note over FCS: LaunchedEffect로 3초 후 showToast=false
  end
  User->>FCS: 게시글 삭제(메뉴)
  FCS->>FCS: showDeleteDialog = true
  User->>FCS: 확인
  FCS->>VM: deleteFeed(feedId)
  FCS->>FCS: showDeleteDialog = false
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Assessment against linked issues

Objective Addressed Explanation
QA 수정사항 반영 전반(#101) 범위가 광범위하며 개별 QA 항목 매핑 정보가 없음.
Task1(#101) 구체적 작업 내용이 제공되지 않음.
Task2(#101) 구체적 작업 내용이 제공되지 않음.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
신규 Route 추가 FeedRoutes.My 및 FeedMyScreen 도입 (.../ui/navigator/routes/FeedRoutes.kt, .../ui/feed/screen/FeedMyScreen.kt, .../ui/navigator/navigations/FeedNavigation.kt) QA 수정 범주로 보기엔 기능 추가 성격으로 보이며, 명시된 이슈 목표에 해당 기능 확장 요구가 특정되지 않음.
댓글 액션 모드(enum) 및 관련 파라미터 전면 제거 (.../ui/common/CommentActionMode.kt 삭제, CommentItem/ReplyItem/CommentSection 시그니처 변경) 기능 축소/API 변경은 QA 수정이라기보다 구조 변경에 해당. 이슈에 해당 제거 요구가 명시되지 않음.
테마 색상 Black80 추가 및 ImageViewerModal 배경 변경 (.../ui/theme/Color.kt, .../ui/feed/component/ImageViewerModal.kt) UI 테마 확장은 QA 수정일 수 있으나, 구체 요구사항 불명확. 이슈와 직접 연결성 확인 불가.

Possibly related PRs

Suggested reviewers

  • JJUYAAA
  • rbqks529

Poem

토끼는 탭을 톡, 나의 길로 점프해
칩은 다섯, 딱— 멈추고 반짝해
퍼센트는 동글동글, 이젠 정수야 헤헷
검은 밤(Black80) 속에 사진이 살짝 돋네
댓글 바람에 메뉴가 사르르— 휘이잉
저장함 툭 치면 책과 피드가 달그락 🥕

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt (1)

88-93: 토스트 애니메이션 타이밍 문제: '정지 시간'이 거의 없어 UX가 저하됩니다

현재 진입/종료 애니메이션이 각각 2000ms이고, 표시 타이머도 2000ms라서, 토스트가 완전히 자리 잡자마자 곧바로 사라지는 흐름입니다. 사용자는 정지된 상태의 토스트를 거의 보지 못합니다.

아래 중 하나로 정렬해 주세요.

  • 최소 변경(기존 2초 애니메이션 유지): 표시 지연을 4000ms로 늘려 정지 시간을 2초 확보
  • 권장(애니메이션 단축 + 가독성 향상): 진입/퇴장 애니메이션을 200~300ms로 줄이고, 표시 시간을 별도로 2000ms 확보

최소 변경안(라인 88-93만 수정):

 LaunchedEffect(uiState.showToast) {
     if (uiState.showToast) {
-        delay(2000)
+        // enter(2s) + hold(2s) = 4s 후 hide
+        delay(4000)
         onHideToast()
     }
 }

권장 변경안(애니메이션 단축 + 표시 시간 분리):

 AnimatedVisibility(
     visible = uiState.showToast,
     enter = slideInVertically(
         initialOffsetY = { -it },
-        animationSpec = tween(durationMillis = 2000)
+        animationSpec = tween(durationMillis = 300)
     ),
     exit = slideOutVertically(
         targetOffsetY = { -it },
-        animationSpec = tween(durationMillis = 2000)
+        animationSpec = tween(durationMillis = 200)
     ),

그리고 표시 타이머는 진입 시간(300ms)을 고려해 총 2300ms 정도로:

 LaunchedEffect(uiState.showToast) {
     if (uiState.showToast) {
-        delay(2000)
+        // enter(300ms) + hold(2000ms)
+        delay(2300)
         onHideToast()
     }
 }

Also applies to: 189-198

app/src/main/java/com/texthip/thip/ui/group/note/component/CommentItem.kt (1)

52-52: 불필요한 단독 표현식 제거 필요(data)

Line 52의 단독 data 표현식은 의미가 없고 정적 분석(ktlint/detekt)에서 경고/실패를 유발할 수 있습니다. 제거하세요.

-                data
                 ProfileBarFeed(
app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt (1)

240-247: SearchPeople 경로에서 ‘내 프로필’ 분기 미적용 — 요구사항 누락으로 보입니다

현재 navigateToUserProfile(userId) 확장을 그대로 사용하여 항상 Others로 갈 가능성이 큽니다. 본 PR의 목표(내/타인 분기)에 맞춰 로직을 맞춰주세요.

아래처럼 Feed 탭의 ViewModel에서 myUserId를 가져와 분기하는 것으로 통일할 수 있습니다:

   composable<FeedRoutes.SearchPeople> {
-        SearchPeopleScreen(
-            onNavigateBack = navigateBack,
-            onUserClick = { userId ->
-                navController.navigateToUserProfile(userId)
-            }
-        )
+        val feedViewModel: FeedViewModel = hiltViewModel(navController.getBackStackEntry(MainTabRoutes.Feed))
+        val uiState by feedViewModel.uiState.collectAsState()
+        val myUserId = uiState.myFeedInfo?.creatorId
+
+        SearchPeopleScreen(
+            onNavigateBack = navigateBack,
+            onUserClick = { userId ->
+                if (myUserId != null && myUserId == userId) {
+                    navController.navigate(FeedRoutes.My)
+                } else {
+                    navController.navigate(FeedRoutes.Others(userId))
+                }
+            }
+        )
   }
🧹 Nitpick comments (35)
app/src/main/java/com/texthip/thip/ui/navigator/BottomNavigationBar.kt (2)

101-101: 패딩 32→20dp 변경: 디자인·터치 영역 확인 및 dimen 추출 권장

좌우 패딩 축소로 가장자리 아이템의 시각적/터치 밀집도가 높아질 수 있습니다. 디자인 스펙과 최소 터치 영역(권장 48dp) 충족 여부를 한번 확인해 주세요. 또한 매직 넘버 대신 dimen 리소스로 추출해 두면 향후 조정이 용이합니다.

적용 제안(diff):

-                .padding(horizontal = 20.dp),
+                .padding(horizontal = dimensionResource(id = R.dimen.bottom_nav_horizontal_padding)),

추가 필요사항:

  • import 추가
    • import androidx.compose.ui.res.dimensionResource
  • 리소스 정의(res/values/dimens.xml 예시)
<resources>
    <dimen name="bottom_nav_horizontal_padding">20dp</dimen>
</resources>

139-146: Preview 추가 굿. 가독성 향상을 위한 소폭 개선 제안

Preview 캔버스에서 컴포넌트 경계 인지가 쉬우도록 showBackground와 name을 지정해 두면 편합니다. 선택 사항이지만 실사용 테마가 있다면(예: ThipTheme 컴포저블) 프리뷰를 테마로 감싸면 색/타이포 일관성이 더 잘 보입니다.

적용 제안(diff):

-@Preview
+@Preview(name = "BottomNavigationBar", showBackground = true)
 @Composable
 private fun BottomNavigationBarPreview() {
     val navController = rememberNavController()
-    BottomNavigationBar(
-        navController = navController
-    )
+    BottomNavigationBar(navController = navController)
 }

참고: 테마 컴포저블이 존재한다면 아래처럼 감싸는 것도 고려해 주세요(예시).

// ThipTheme { BottomNavigationBar(navController) }
app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupNoteCreateScreen.kt (1)

96-100: padding과 verticalScroll 적용 순서 조정 제안

현재 순서(…verticalScroll().padding())에서는 padding이 스크롤 영역 밖에 적용됩니다. 폼 끝단까지 자연스럽게 스크롤되도록 패딩이 스크롤에 포함되게 하는 것이 일반적으로 더 자연스러워, 아래처럼 순서를 바꾸는 것을 권장합니다.

-                modifier = Modifier
-                    .weight(1f)
-                    .verticalScroll(rememberScrollState())
-                    .padding(vertical = 32.dp, horizontal = 20.dp),
+                modifier = Modifier
+                    .weight(1f)
+                    .padding(vertical = 32.dp, horizontal = 20.dp)
+                    .verticalScroll(rememberScrollState()),
app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupVoteCreateScreen.kt (1)

96-100: 스크롤/패딩 순서 통일 제안 (사용자 경험 개선)

Note 화면과 동일하게 padding을 스크롤에 포함시키는 순서가 더 자연스럽습니다. 아래와 같이 적용을 권장합니다.

-                modifier = Modifier
-                    .weight(1f)
-                    .verticalScroll(rememberScrollState())
-                    .padding(vertical = 32.dp, horizontal = 20.dp),
+                modifier = Modifier
+                    .weight(1f)
+                    .padding(vertical = 32.dp, horizontal = 20.dp)
+                    .verticalScroll(rememberScrollState()),
app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookSearchBottomSheet.kt (1)

31-31: BottomSheet의 높이 제한(0.8f) + advancedImePadding 조합 검증 권장

0.8f 높이 제한에 IME 패딩이 더해지면, 소형 단말/대형 IME 환경에서 실제 가용 공간이 과도하게 줄 수 있습니다. 특히 검색 결과가 길어 스크롤이 필요한 경우와 로딩 스피너가 표시되는 경우 레이아웃 안정성을 점검해 주세요.

권장 수동 테스트 시나리오:

  • 단말 A(작은 해상도)와 단말 B(큰 해상도)에서 키보드 열고/닫기 시 리스트 영역이 충분히 스크롤 가능하고 TextField가 가려지지 않는지 확인
  • 제스처 내비/3버튼 내비 모두에서 하단 네비게이션 바와 겹침 없는지 확인
  • 검색어 입력 중 로딩 스피너(라인 101-110)가 중앙 정렬로 정상 노출되는지 확인

대안(선택):

  • IME 패딩을 전체 Column이 아닌 리스트 영역(예: GroupBookListWithScrollbar를 감싼 컨테이너)에만 적용하여 헤더/탭 영역 레이아웃 이동 최소화
  • 0.8f를 Dimen로 추출해 화면군(폰/태블릿)에 따라 튜닝 가능하게 구성

Also applies to: 69-71

app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt (1)

45-49: percentage 값 범위(0..100) 보장 클램핑 권장

서버/계산 오류로 0~100 범위를 벗어나는 값이 들어올 경우 CardNote 내부 진행률 표시가 깨질 수 있습니다. 방어적으로 클램핑하면 안전합니다.

다음 변경을 제안합니다:

         CardNote(
             currentPage = currentPage,
-            percentage = userPercentage,
+            percentage = userPercentage.coerceIn(0, 100),
         ) {
             onNavigateToNote()
         }
app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookListWithScrollbar.kt (4)

30-39: 스크롤 뷰포트 제약이 없어 실제로 스크롤되지 않을 수 있습니다

Box의 고정 높이(또는 상위 제약)가 사라지면 Column의 verticalScroll이 부모 제약 내에서만 의미가 있어, 상위가 wrapContent일 경우 리스트 전체가 확장되어 사실상 스크롤이 동작하지 않을 수 있습니다. 기존 320.dp 고정 높이를 제거한 의도(유연한 높이)는 좋지만, 부모 쪽에서 명시적으로 높이/weight를 주입할 수 있는 여지를 열어두는 편이 안전합니다.

권장: modifier 파라미터를 추가해 부모에서 높이/weight 제약을 전달할 수 있게 해주세요.

@Composable
fun GroupBookListWithScrollbar(
    books: List<BookData>,
    onBookClick: (BookData) -> Unit,
    modifier: Modifier = Modifier, // 추가
) {
    val scrollState = rememberScrollState()
    Box(
        modifier
            .fillMaxWidth()
    ) {
        Column(
            Modifier
                .fillMaxWidth()
                .verticalScroll(scrollState)
                .drawVerticalScrollbar(scrollState)
        ) { /* ... */ }
    }
}

만약 컴포넌트 내부에서 기본 상한을 주고 싶다면 heightIn(max = …) 사용을 고려해 주세요(예: .heightIn(max = 320.dp)). 단, 가능한 한 상위에서 제약을 전달하는 쪽이 재사용성과 일관성 면에서 더 낫습니다.
QA 체크 포인트: 실제 화면에서 리스트가 “스크롤되어야 하는” 영역에서 정상적으로 스크롤/스크롤바가 동작하는지 확인 바랍니다.


46-46: 마지막 아이템 하단에 불필요한 12.dp 여백이 생깁니다 + 항목 간 간격이 12+1+12=25.dp로 증가했습니다

현재 구조상 모든 항목 뒤에 12.dp가 무조건 들어가고, 마지막이 아닌 항목에는 Divider 전후로 총 24.dp(+1.dp 라인) 간격이 생깁니다. 의도된 디자인 변경인지 확인이 필요합니다. 일반적인 리스트 간격(예: 8~12.dp) 대비 과도하게 벌어질 수 있습니다.

최소 수정(항목 간 간격을 줄이고 마지막 하단 공백 제거):

-                Spacer(modifier = Modifier.height(12.dp))
+                // 항목 간 과도한 여백 및 마지막 하단 공백 방지: 제거

대안 1(시각적 여백을 Divider 위쪽에만 두고 12.dp 유지):

-                Spacer(modifier = Modifier.height(12.dp))
                 if (index < books.size - 1) {
+                    Spacer(modifier = Modifier.height(12.dp)) // Divider 위 여백
                     // Divider(또는 1.dp 라인)
-                    Spacer(modifier = Modifier.height(12.dp))
                 }

대안 2(컴포즈의 Arrangement.spacedBy로 간격을 일관 관리하고, Divider만 사이에 두기): Column에 verticalArrangement = Arrangement.spacedBy(12.dp)를 주고, Divider는 항목 사이에서만 렌더링하도록 루프를 조정하는 방법도 있습니다.


48-53: Separator는 Spacer+background 대신 Divider 사용 권장, 6.dp 매직 넘버 상수화 제안

Material 컴포넌트인 Divider를 사용하면 두께/컬러/투명도 등 접근성과 일관성이 좋아집니다. 또한 end = 6.dp는 스크롤바와의 간섭을 피하려는 의도로 보이는데, 디자인 토큰(예: ThipTheme.dimensions.xxx)으로 상수화하면 유지보수에 유리합니다.

적용 예시(해당 라인 범위 내 변경):

-                    Spacer(
-                        modifier = Modifier
-                            .fillMaxWidth()
-                            .padding(end = 6.dp)
-                            .height(1.dp)
-                            .background(color = colors.Grey02)
-                    )
+                    Divider(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(end = 6.dp), // TODO: 디자인 토큰으로 대체 권장
+                        thickness = 1.dp,
+                        color = colors.Grey02,
+                    )

추가: Divider import 필요

import androidx.compose.material3.Divider

참고: 스크롤바와 겹침 방지 여백(6.dp)이 실제 디바이스/다크모드에서도 시각적으로 자연스러운지 확인 부탁드립니다.


40-57: 데이터가 많아질 가능성이 있으면 LazyColumn 전환 고려

Column + verticalScroll은 모든 항목을 한 번에 컴포지션/측정하므로, 리스트가 길어질 경우 성능/메모리 비용이 커집니다. LazyColumn(itemsIndexed)로 전환하면 가시 영역만 렌더링되어 효율적입니다. 다만 drawVerticalScrollbar가 LazyListState를 지원하도록 확장되어야 합니다.

스켈레톤 예시:

val listState = rememberLazyListState()
LazyColumn(
    modifier = Modifier.fillMaxWidth(),
    state = listState,
    // contentPadding = PaddingValues(bottom = 12.dp) 등
) {
    itemsIndexed(books) { index, book ->
        CardBookSearch(
            title = book.title,
            imageUrl = book.imageUrl,
            onClick = { onBookClick(book) }
        )
        if (index < books.lastIndex) {
            // 위 코멘트의 Divider 방식을 적용
        }
    }
}
// drawVerticalScrollbar(listState)를 지원하도록 확장 필요
app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt (2)

45-49: 비활성(Disabled) 텍스트 컬러 변경은 의도 명확. 다만 isFilled=true 배경과의 대비(contrast) 점검 필요

현재 !enabled && isFilled일 때 배경이 DarkGrey02, 텍스트가 DarkGrey로 설정됩니다. 두 값의 명도 차가 작으면 가독성/접근성(WCAG 대비 4.5:1 권장) 이슈가 생길 수 있습니다. 디자인 토큰 기준으로 대비를 한 번 확인해 주세요. 필요 시 비활성 텍스트 컬러를 한 단계 더 밝히거나(alpha 적용 포함) 배경 대비가 충분한 색상으로 조정하는 것을 권장합니다.

접근성 보강을 위해 시각적 비활성화뿐 아니라 스크린 리더에도 “비활성”으로 노출되도록 semantics를 추가하는 것도 권장드립니다(아래는 변경 라인 외 지원 코드 예시).

// import 추가
import androidx.compose.ui.semantics.disabled
import androidx.compose.ui.semantics.semantics

// Box(modifier = ...) 체인에 추가
.semantics { if (!enabled) disabled() }

57-61: 비활성 보더 컬러 추가는 👍. 상호작용(리플/접근성) 일관성 개선 제안

현재 clickable은 항상 활성화되어 있어 비활성일 때도 리플이 표시되고(onDisabledClick 호출), 접근성 트리에서는 “클릭 가능”으로 노출될 수 있습니다. 의도가 “선택 제한 초과 시 안내 토스트 등”이라면 onDisabledClick 유지도 합리적이지만, 리플은 꺼주고 접근성에는 disabled semantics를 부여하는 게 일관성 있습니다.

아래와 같이 개선을 검토해 보세요(변경 라인 외 지원 코드 예시).

// import
import androidx.compose.foundation.interaction.MutableInteractionSource

Box(
  modifier = modifier
    // ...
    .semantics { if (!enabled) disabled() } // 시각/접근성 동기화
    .clickable(
      // 비활성 시 리플 제거
      indication = if (enabled) null else null,
      interactionSource = remember { MutableInteractionSource() }
    ) {
      if (enabled) {
        if (isSelected == null) isClicked = !isClicked
        onClick()
      } else {
        onDisabledClick()
      }
    }
    // ...
)

참고: 비활성 시 완전히 상호작용을 막고 싶다면 clickable(enabled = enabled)로 바꾸고 else 분기를 제거하면 됩니다(그 경우 onDisabledClick은 더 이상 호출되지 않습니다).

app/src/main/java/com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt (2)

27-32: 선택 제한 로직 명확. 매직 넘버(5) 상수/파라미터화 제안

현재 제한값 5가 하드코딩되어 있어 향후 기획 변경 시 파급 범위가 커질 수 있습니다. 지역 상수 혹은 함수 파라미터로 노출하는 것을 권장합니다.

적용 예(해당 범위 내 최소 수정):

-        val isLimitReached = selectedGenres.size >= 5
+        val maxSelection = 5
+        val isLimitReached = selectedGenres.size >= maxSelection

또는 함수 시그니처에 기본값 파라미터로 받는 방법:

@Composable
fun SubGenreChipGrid(
  subGenres: List<String>,
  selectedGenres: List<String>,
  onGenreToggle: (String) -> Unit,
  horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
  maxSelection: Int = 5, // new
) {
  val isLimitReached = selectedGenres.size >= maxSelection
  // ...
}

33-39: OptionChipButton 파라미터 연결 좋습니다. 비활성 클릭 시 사용자 피드백 훅 제공 고려

isSelected/ enabled 전달로 UI 상태가 잘 반영됩니다. 선택 제한에 걸렸을 때 사용자에게 즉시 안내(예: 토스트)하고 싶다면 onDisabledClick을 활용할 수 있도록 훅을 노출하는 것을 권장합니다.

예시(지원 코드):

@Composable
fun SubGenreChipGrid(
  subGenres: List<String>,
  selectedGenres: List<String>,
  onGenreToggle: (String) -> Unit,
  horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
  maxSelection: Int = 5,
  onMaxSelectionAttempt: (() -> Unit)? = null, // new
) {
  val isLimitReached = selectedGenres.size >= maxSelection

  subGenres.forEach { genre ->
    val isSelected = selectedGenres.contains(genre)
    val isEnabled = isSelected || !isLimitReached

    OptionChipButton(
      text = genre,
      isSelected = isSelected,
      isFilled = false,
      enabled = isEnabled,
      onClick = { onGenreToggle(genre) },
      onDisabledClick = { onMaxSelectionAttempt?.invoke() }, // new
    )
  }
}

원하시면 위 변경을 반영한 커밋 패치를 만들어 드리겠습니다.

app/src/main/res/values/strings.xml (1)

374-374: 신규 토스트 메시지 추가 좋습니다. 문장부호 톤만 기존과 맞추면 더 일관적입니다.

같은 섹션의 posting_complete_feed!를 사용합니다. 동일 톤 유지 차원에서 감탄부호 사용을 제안드립니다.

-    <string name="report_complete_feed">게시글 신고를 완료했어요.</string>
+    <string name="report_complete_feed">게시글 신고를 완료했어요!</string>
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt (1)

320-320: 빈 상태 상단 여백 하드코딩 대신 dimens로 추출 권장

고정 110.dp는 기기 해상도/비율에 따라 어색할 수 있습니다. 리소스로 추출하면 화면별 조정이 쉬워집니다.

-                                        .padding(top = 110.dp),
+                                        .padding(top = dimensionResource(id = R.dimen.feed_empty_top_padding)),

추가로 필요한 리소스 정의 예시(별도 파일):

<!-- res/values/dimens.xml -->
<resources>
    <dimen name="feed_empty_top_padding">110dp</dimen>
</resources>
app/src/main/java/com/texthip/thip/ui/group/note/component/FilterHeaderSection.kt (2)

55-57: 불필요한 조건 분기 제거로 간결화

이미 보이는지 여부와 상관없이 true 대입은 멱등적입니다. 단순 대입으로 정리하면 읽기 쉬워집니다.

-                    if (!isPageInputVisible) {
-                        isPageInputVisible = true
-                    }
+                    isPageInputVisible = true

71-80: 상태 분기를 enabled 속성으로 위임해 의도를 명확히 표현

isPageInputVisible일 때 클릭 무시 로직을 onClick/onDisabledClick에서 분기하기보다, 버튼 자체를 비활성 처리하는 편이 접근성/시맨틱 측면에서 더 자연스럽습니다. enabled = totalEnabled && !isPageInputVisible로 위임하면 스크린리더에도 명확히 전달됩니다.

-                enabled = totalEnabled,
+                enabled = totalEnabled && !isPageInputVisible,
                 textStyle = typography.menu_r400_s14_h24,
-                onClick = {
-                    if (!isPageInputVisible) {
-                        onTotalToggle()
-                    }
-                },
-                onDisabledClick = {
-                    if (!isPageInputVisible) {
-                        onDisabledClick()
-                    }
-                },
+                onClick = onTotalToggle,
+                onDisabledClick = onDisabledClick,

추가 고려:

  • isPageInputVisible 상태에서 해당 옵션을 비활성화했음을 사용자에게 알릴 필요가 있다면, onDisabledClick에서 안내 토스트를 노출하는 패턴도 유효합니다.
app/src/main/java/com/texthip/thip/ui/common/cards/CardBookList.kt (1)

50-52: Row 전역 클릭 처리 시 두 가지 자잘한 개선 제안

  • Transparent 배경 지정은 기본값과 동일하여 불필요합니다.
  • 접근성 향상을 위해 role 지정 또는 contentDescription/semantics 보강을 고려하세요.
-            .background(Color.Transparent)
-            .clickable { onClick() },
+            .clickable(role = null) { onClick() },

추가로, UI 테스트/접근성에 도움이 되도록 필요 시 semantics { } 또는 testTag 부여를 검토해 주세요.

app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt (1)

122-127: 불필요한 TODO 주석 정리 권장

해당 버튼에 이미 onToggleFollow가 연결되어 있어 “TODO: 띱하기/취소하기 로직 연결” 주석은 현재 상태와 불일치합니다. 혼선을 줄이기 위해 제거 또는 최신 설명으로 갱신해 주세요.

-                            // TODO: 띱하기/취소하기 로직 연결
                             onButtonClick = onToggleFollow,
app/src/main/java/com/texthip/thip/data/model/users/response/OthersFollowersResponse.kt (1)

22-23: isMyself 필드에 기본값을 부여해 하위호환성을 확보하세요

서버가 구버전이거나 필드가 누락될 경우, Kotlinx Serialization/Gson 모두에서 역직렬화 실패가 발생할 수 있습니다. 기본값을 추가해 방어적으로 처리하는 것을 권장합니다.

-  @SerializedName("isMyself") val isMyself: Boolean
+  @SerializedName("isMyself") val isMyself: Boolean = false

또한 본 파일은 @Serializable(kotlinx)와 @SerializedName(Gson) 어노테이션을 혼용하고 있습니다. 프로젝트 전반의 직렬화 전략(하나로 통일)을 재점검하는 것이 유지보수에 유리합니다.

app/src/main/java/com/texthip/thip/ui/feed/component/ImageViewerModal.kt (1)

46-47: 배경 오버레이 추가는 UX 향상에 유효합니다. 접근성(Back 버튼/스크린리더) 보완을 권장합니다.

  • Back 버튼으로도 닫히도록 BackHandler를 추가하면 접근성이 좋아집니다.
  • "닫기" 아이콘의 contentDescription을 stringResource로 통일(i18n)하면 번역 누락을 줄일 수 있습니다.

아래 코드를 컴포저블 상단(rememberPagerState 아래 등)에 추가하는 것을 제안드립니다:

import androidx.activity.compose.BackHandler

BackHandler(enabled = true) { onDismiss() }
app/src/main/java/com/texthip/thip/ui/navigator/navigations/MyPageNavigation.kt (1)

46-53: feedId 타입 통일 확인 완료
모든 레이어에서 feedIdLong으로 일치합니다. 별도 수정은 필요 없으며, 원하실 경우 람다 파라미터에 타입을 명시하시면(예: { feedId: Long -> … }) 컴파일 타임 검사가 더 빠르게 적용됩니다.

  • MypageSaveScreen(onFeedClick: Long)
  • FeedContent(onFeedClick: Long)
  • NavHostController.navigateToFeedComment(feedId: Long)
  • FeedRoutes.Comment(feedId: Long)
app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt (1)

28-31: onBookClick 추가는 타당합니다. 재사용성/역호환을 위해 기본값 제공을 제안합니다.

기본값을 두면 호출부 수정 누락으로 인한 컴파일 오류를 줄일 수 있습니다.

-    onBookClick: (isbn: String) -> Unit
+    onBookClick: (isbn: String) -> Unit = {}
app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (1)

48-50: 컨텐츠 클릭 → 댓글 진입 트리거 연결 좋습니다. 댓글 버튼도 동일 동작으로 통일을 고려해 보세요.

UX 일관성을 위해 액션바의 댓글 버튼(onCommentClick)도 동일한 핸들러로 연결을 제안합니다.

                 SavedFeedCard(
                     feedItem = feed,
                     onBookmarkClick = { viewModel.toggleBookmark(feed.id) },
                     onLikeClick = { viewModel.toggleLike(feed.id) },
-                    onContentClick = { onFeedClick(feed.id) }
+                    onContentClick = { onFeedClick(feed.id) },
+                    onCommentClick = { onFeedClick(feed.id) }
                 )
app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt (2)

285-293: FeedViewModel을 Group 백스택에 스코핑하고 탭 전환(onTabSelected)로 내 정보 로딩하는 방식은 결합도가 높습니다

Group 흐름에서 FeedViewModel을 생성(navController.getBackStackEntry(MainTabRoutes.Group))해 myFeedInfo를 로딩하는 것은 Feed 탭과 서로 다른 인스턴스/상태를 가지게 되어 중복 로딩·상태 불일치가 발생할 수 있습니다. 또한 Group 흐름 진입 시 Feed 탭의 선택 인덱스를 강제로 바꾸는 부작용도 생깁니다.

  • 추천: 전역 사용자 세션/프로필(예: Auth/UserSession Repository)에서 myUserId를 직접 제공받아 의존성을 낮추거나, UI와 무관한 가벼운 ViewModel/UseCase로 현재 사용자 ID만 획득하세요.
  • 최소한으로는, 해당 인스턴스가 실제로 myFeedInfo만 안전하게 로딩하는지와 Feed 탭의 상태에 영향이 없는지 확인이 필요합니다.

로컬에서 Group → RoomMates/Note 진입 시 Feed 탭 상태(선택 인덱스, 로딩 플래그)가 의도치 않게 변하지 않는지 한 번 더 확인 부탁드립니다.


301-306: 내/타인 분기 로직이 중복됩니다 — 공용 헬퍼로 추출해 DRY 유지 권장

두 곳 모두 동일한 분기 if (myUserId != null && myUserId == userId) … 로직을 사용하고 있습니다. 공용 함수(예: NavHostController 확장)로 추출하면 유지보수가 쉬워지고, 추후 분기 요건 변경 시 한 곳에서 수정 가능합니다.

적용 예시(선택):

-                if (myUserId != null && myUserId == userId) {
-                    navController.navigate(FeedRoutes.My)
-                } else {
-                    navController.navigate(FeedRoutes.Others(userId))
-                }
+                navController.navigateToProfile(myUserId, userId)

추가: 파일 내부(또는 extensions)에 다음 유틸을 정의하세요.

// 예: NavigationExtensions.kt
fun NavHostController.navigateToProfile(myUserId: Long?, targetUserId: Long) {
    if (myUserId != null && myUserId == targetUserId) {
        navigate(FeedRoutes.My)
    } else {
        navigate(FeedRoutes.Others(targetUserId))
    }
}

Also applies to: 371-376

app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt (2)

35-47: 초기 진입 시 myUserId가 null이면 자기 프로필 클릭에도 Others로 갈 수 있습니다

현재 myUserId는 uiState.myFeedInfo?.creatorId에서 파생되는데, Feed 탭이 ‘모두’ 탭(0)일 때는 myFeedInfo 로딩이 보장되지 않아 null일 수 있습니다. 이 경우 실제로 본인 프로필을 눌러도 Others로 분기될 수 있습니다.

  • 단기: myUserId가 null이고 클릭된 userId가 서버에서 ‘isMyself’로 함께 내려오는 경우(있다면) 이를 활용해 보정.
  • 장기: myUserId는 탭 상태와 무관한 전역 소스(세션/프로필)에서 제공받아 분기에 사용.

88-102: MySubscription에서도 동일한 my/others 분기 신뢰성 이슈가 있습니다

myUserId 미로딩 시 자기 자신을 Others로 라우팅할 수 있습니다. 위 코멘트와 동일한 개선을 권장합니다.

app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt (1)

162-169: 하드코딩된 토스트 문자열 + 불사용 변수(context)

  • context를 정의했지만 사용하지 않습니다.
  • 토스트 문구는 하드코딩 대신 stringResource/리소스로 관리하세요(현지화·일관성).

다음과 같이 정리할 수 있습니다(문자열 리소스가 있다면):

toastMessage = stringResource(R.string.report_feed_done)
// 또는
toastMessage = context.getString(R.string.report_feed_done)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedMyScreen.kt (2)

164-170: 내 피드에서 OthersFeedCard 사용은 UX 미스매치 가능성

기존 FeedScreen에서는 내 피드에 대해 MyFeedCard를 사용하며 “좋아요/저장 개념 없음”이라고 주석이 있습니다. 여기서는 OthersFeedCard를 사용해 액션이 노출되고, toFeedList에서 isLiked/isSaved를 항상 false로 넣어 상태 일치성도 떨어집니다.

  • 선택 1(권장): MyFeedCard 사용으로 컴포넌트 정책 일관화
  • 선택 2: OthersFeedCard가 액션 노출 여부를 제어할 수 있도록 파라미터(예: isSaveVisible, isLikeVisible)를 추가하고 내 피드에서는 비활성화

74-90: toFeedList()를 Composable 내부에 정의하면 재구성마다 람다 생성 비용이 발생합니다

매핑 함수는 UI와 독립적이므로 top-level 확장/Mapper로 분리하는 것을 권장합니다.

app/src/main/java/com/texthip/thip/ui/feed/screen/OthersSubscriptionListScreen.kt (3)

79-79: OthersSubscriptionContent 시그니처 갱신 OK. 동일한 typealias 적용으로 일관성 확보를 제안합니다.

아래와 같이 공용 typealias를 적용하면 상위와 하위 컴포저블 간 시그니처가 한 곳에서 관리됩니다.

-    onProfileClick: (userId: Long, isMyself: Boolean) -> Unit
+    onProfileClick: OnProfileClick

위 변경에는 다음 import가 필요합니다:

import com.texthip.thip.ui.common.types.OnProfileClick

167-169: Preview: 가짜 데이터에서 isMyself 값을 다양화하여 분기 시각화를 돕는 것을 제안합니다.

모든 항목이 true면 분기 검증에 한계가 있습니다. 짝/홀로 번갈아가며 값을 주면 UI 점검에 더 유리합니다.

-            isMyself = true
+            isMyself = it % 2 == 0

46-46: 콜백 타입 재사용을 위한 typealias 도입 제안

현재 OthersSubscriptionListScreen에만 쓰이고 있는 2-parameter 콜백 시그니처를 공용으로 관리하면, 추후 유사 패턴이 생길 때 중복 정의를 줄이고 오탈자 위험을 낮출 수 있습니다.

제안 사항:

  1. 공용 typealias 정의

    • 파일: app/src/main/java/com/texthip/thip/ui/common/types/Handlers.kt
    package com.texthip.thip.ui.common.types
    
    /** 사용자 프로필 클릭 콜백(userId, isMyself) */
    typealias OnProfileClick = (userId: Long, isMyself: Boolean) -> Unit
  2. OthersSubscriptionListScreen에 적용

    import com.texthip.thip.utils.color.hexToColor
    + import com.texthip.thip.ui.common.types.OnProfileClick
    
     @Composable
     fun OthersSubscriptionListScreen(
         onNavigateBack: () -> Unit,
    -    onProfileClick: (userId: Long, isMyself: Boolean) -> Unit = { _, _ -> },
    +    onProfileClick: OnProfileClick = { _, _ -> },
         viewModel: OthersSubscriptionViewModel = hiltViewModel()
     ) { … }
  3. 현재 코드베이스 내 콜백 현황
    • 2-parameter (Long, Boolean) → OthersSubscriptionListScreen.kt, FeedNavigation.kt(229행)
    • 1-parameter (Long) → CommentSection.kt, CommentBottomSheet.kt 등에 여전히 사용 중
    — 필요 시 별도 typealias((Long) -> Unit) 도입 검토

  4. 기본값(= { _, _ -> })은 실수로 콜백을 빼먹었을 때 문제 발견이 늦어질 수 있으니, 팀 합의가 된다면 제거 고려(선택 사항).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7051f00 and 1998cee.

📒 Files selected for processing (33)
  • app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/data/model/users/response/OthersFollowersResponse.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/CommentActionMode.kt (0 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt (2 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/cards/CardBookList.kt (2 hunks)
  • app/src/main/java/com/texthip/thip/ui/feed/component/ImageViewerModal.kt (3 hunks)
  • app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt (7 hunks)
  • app/src/main/java/com/texthip/thip/ui/feed/screen/FeedMyScreen.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt (3 hunks)
  • app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/feed/screen/OthersSubscriptionListScreen.kt (5 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookListWithScrollbar.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookSearchBottomSheet.kt (3 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/component/CommentBottomSheet.kt (0 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/component/CommentItem.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/component/CommentSection.kt (2 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/component/FilterHeaderSection.kt (2 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupNoteCreateScreen.kt (4 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupVoteCreateScreen.kt (4 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt (3 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt (2 hunks)
  • app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt (2 hunks)
  • app/src/main/java/com/texthip/thip/ui/navigator/BottomNavigationBar.kt (3 hunks)
  • app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt (7 hunks)
  • app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt (5 hunks)
  • app/src/main/java/com/texthip/thip/ui/navigator/navigations/MyPageNavigation.kt (2 hunks)
  • app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/theme/Color.kt (3 hunks)
  • app/src/main/res/values/strings.xml (1 hunks)
💤 Files with no reviewable changes (2)
  • app/src/main/java/com/texthip/thip/ui/common/CommentActionMode.kt
  • app/src/main/java/com/texthip/thip/ui/group/note/component/CommentBottomSheet.kt
🧰 Additional context used
🧬 Code Graph Analysis (8)
app/src/main/java/com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt (1)
app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt (1)
  • OptionChipButton (30-93)
app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt (1)
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomMatesScreen.kt (1)
  • GroupRoomMatesScreen (29-66)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt (1)
app/src/main/java/com/texthip/thip/ui/common/modal/ToastWithDate.kt (1)
  • ToastWithDate (24-61)
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 (38-141)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedMyScreen.kt (6)
app/src/main/java/com/texthip/thip/ui/common/topappbar/DefaultTopAppBar.kt (1)
  • DefaultTopAppBar (24-75)
app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt (1)
  • AuthorHeader (34-121)
app/src/main/java/com/texthip/thip/utils/color/HexToColor.kt (1)
  • hexToColor (6-13)
app/src/main/java/com/texthip/thip/ui/feed/component/FeedSubscribelistBar.kt (1)
  • FeedSubscribeBarlist (35-101)
app/src/main/java/com/texthip/thip/ui/feed/component/OthersFeedCard.kt (1)
  • OthersFeedCard (35-123)
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/FeedCommentScreen.kt (3)
app/src/main/java/com/texthip/thip/ui/common/modal/ToastWithDate.kt (1)
  • ToastWithDate (24-61)
app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt (1)
  • MenuBottomSheet (22-59)
app/src/main/java/com/texthip/thip/ui/common/modal/DialogPopup.kt (1)
  • DialogPopup (22-71)
app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt (2)
app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (1)
  • FeedContent (25-63)
app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt (1)
  • BookContent (26-68)
app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt (3)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt (1)
  • FeedScreen (66-471)
app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt (1)
  • MySubscriptionScreen (52-91)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedMyScreen.kt (1)
  • FeedMyScreen (40-61)
🔇 Additional comments (33)
app/src/main/java/com/texthip/thip/ui/navigator/BottomNavigationBar.kt (1)

27-31: 프리뷰용 import 추가 적절

Preview/rememberNavController 도입으로 Studio 내 빠른 UI 확인이 가능해졌습니다. 별다른 부작용 없어 보입니다.

app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupNoteCreateScreen.kt (2)

9-10: 스크롤 상태 도입 적절합니다

긴 폼 입력 시 키보드/작은 화면 대응에 유효한 변경입니다. 불필요한 재구성을 유발하지 않는 패턴으로 사용되고 있어 좋습니다.


84-87: 루트 컨테이너 IME 대응 추가 👍

Box에 advancedImePadding()을 적용하여 키보드에 가려지지 않도록 한 방향이 적절합니다. 상위 계층에서 중복된 ime/systemBars 패딩을 또 적용하지 않는지만 확인해 주세요(이중 인셋 적용 시 여백이 과해질 수 있습니다).

중복 인셋 확인 체크:

  • 이 화면을 감싸는 상위 Scaffold/Container에 imePadding 또는 systemBarsPadding이 추가로 있는지 점검
  • 키보드 열고/닫을 때 하단 요소가 이격만 생기고 레이아웃 점프(jump)가 없는지 육안 확인
app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupVoteCreateScreen.kt (1)

81-85: IME 대응 패딩 적용 적합

루트 Box에 advancedImePadding() 적용은 키보드 표시 시 입력 영역 가림을 방지하는데 효과적입니다. GroupNoteCreateScreen과 동일한 패턴으로 일관성이 있는 점도 좋습니다.

app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookSearchBottomSheet.kt (1)

6-6: fillMaxHeight로의 전환 적절

BottomSheet 내부에서 높이를 퍼센트로 제한하는 방식은 다양한 단말 높이에 대응하기 용이합니다. 아래 컨테이너 변경과도 일관됩니다.

app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt (1)

23-23: userPercentage Int 변경: 코드베이스 검증 완료 & 백엔드 스키마 확인 요청

– 모든 .kt 파일에서 userPercentage: Double 선언 및 roundToInt(…) 호출 미발견
– 모든 .json 모킹 샘플에 소수점 퍼센티지 미발견

모델을 Int로 유지해도 코드상 추가 변경은 불필요하나, 반드시 백엔드가 0..100 정수만 반환하도록 스키마/응답을 확인해 주세요.
만약 아직 소수점 값이 남아있다면, 아래와 같이 관대한 역직렬화를 적용하세요.

  1. RoomsPlayingResponse.kt 에 커스텀 직렬화기 지정
-    val userPercentage: Int,
+    @kotlinx.serialization.Serializable(with = PercentIntSerializer::class)
+    val userPercentage: Int,
  1. 새 파일 app/src/main/java/com/texthip/thip/data/serialization/PercentIntSerializer.kt 추가
package com.texthip.thip.data.serialization

import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.doubleOrNull
import kotlinx.serialization.json.intOrNull
import kotlin.math.roundToInt

object PercentIntSerializer : KSerializer<Int> {
    override val descriptor: SerialDescriptor =
        PrimitiveSerialDescriptor("PercentInt", PrimitiveKind.INT)

    override fun deserialize(decoder: Decoder): Int {
        val jsonDecoder = decoder as? JsonDecoder ?: return decoder.decodeInt()
        val element = jsonDecoder.decodeJsonElement() as? JsonPrimitive
            ?: throw SerializationException("Cannot decode percent from $element")
        jsonDecoder.decodeJsonElement().let {
            it.intOrNull?.let { return it }
            it.doubleOrNull?.let { return it.roundToInt() }
        }
        throw SerializationException("Percent must be number, but was $element")
    }

    override fun serialize(encoder: Encoder, value: Int) {
        encoder.encodeInt(value)
    }
}
app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt (1)

27-27: 타입 전파 및 사용처 업데이트 깔끔합니다

  • Composable 파라미터/호출/프리뷰 모두 Int로 일관성 있게 변경되어 UI 층의 형변환 오버헤드가 제거되었습니다.

Also applies to: 47-47, 74-74

app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (1)

304-304: 프리뷰 Double→Int 반영 정상입니다

샘플 데이터 타입이 모델 변경과 일치합니다.

app/src/main/java/com/texthip/thip/ui/theme/Color.kt (2)

43-43: 새 반투명 블랙(Black80) 추가 LGTM

모달/오버레이 배경에 적합한 알파값이며 팔레트 구성과 네이밍도 일관적입니다.


86-87: ThipColors 생성자 변경 검토 완료 – 영향 범위 없음

rg 검색 결과 ThipColors(...) 직접 호출은 defaultThipColors에서만 이루어지고, ThipColors.copy() 호출도 없어 추가 수정이 필요하지 않습니다.
안정적으로 빌드에 영향이 없음을 확인했습니다.

app/src/main/java/com/texthip/thip/ui/common/cards/CardBookList.kt (2)

4-4: clickable import 추가 적절

Row에 클릭 핸들러를 부여하기 위한 필수 import입니다.


44-46: onClick 파라미터 도입 LGTM — 기본값으로 역호환성 유지됨

기존 호출부에 영향 없이 아이템 전체 탭 동작을 쉽게 주입할 수 있습니다.

app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt (1)

64-69: 팔로우/언팔로우 토스트 메시지 구성 적절합니다

닉네임 null-safety와 리소스 사용이 일관적입니다. 여기서는 LGTM입니다.

app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt (1)

38-39: 프로필 클릭 콜백 분리 좋습니다

actionMode 제거 후 onProfileClick만 남겨 상위 네비게이션 분기에 맞게 단순화된 API가 명확합니다. 하위 ProfileBarFeed로 안전하게 전달됩니다.

app/src/main/java/com/texthip/thip/ui/group/note/component/CommentItem.kt (1)

36-60: 프로필 클릭 콜백 전달 LGTM

onProfileClick이 ProfileBarFeed의 onClick으로 일관되게 전달되어 네비게이션/소유자 분기에 활용하기 좋습니다.

app/src/main/java/com/texthip/thip/ui/group/note/component/CommentSection.kt (2)

35-51: actionMode 제거에 따른 섹션 단순화 LGTM

CommentItem/ReplyItem 호출부가 간결해졌고, 이벤트(onEvent) 라우팅도 명확합니다.

Also applies to: 58-73


53-56: creatorId 타입 일치 확인 완료

CommentList.creatorId는 Long?이며 let 블록 내 id는 non-null Long이고, ReplyList.creatorId는 Long으로 onProfileClick(id)에 타입 불일치가 없습니다. 별도 toLong() 변환이 필요하지 않습니다.

app/src/main/java/com/texthip/thip/ui/feed/component/ImageViewerModal.kt (2)

70-71: 스타일(개행) 변경만 존재 — 동작 영향 없음

별도 조치 불필요합니다.


108-112: 문자열 리소스 다중 인자 호출로 가독성 개선 — 좋습니다.

표현식 분리로 리뷰/수정 용이성이 올라갑니다.

app/src/main/java/com/texthip/thip/ui/navigator/navigations/MyPageNavigation.kt (2)

12-12: 책 상세 내비게이션 import 추가 적절합니다.


15-15: 피드 댓글 내비게이션 import 추가 적절합니다.

app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt (1)

53-55: 아이템 클릭/북마크 토글 연결 방식 LGTM

  • onBookmarkClick에서 VM 액션 분리, onClick으로 ISBN 전달 모두 적절합니다.
app/src/main/java/com/texthip/thip/ui/mypage/component/FeedContent.kt (2)

35-41: 리스트 구성 및 key 지정 방식 적절합니다.

  • contentPadding/first item spacing/Stable key(feed.id) 모두 적절합니다.

27-30: feedId 타입 일관성 확인 완료

MypageSaveScreen(onFeedClick: (feedId: Long)), FeedContent(onFeedClick: (feedId: Long)) 및 navigateToFeedComment(feedId: Long) 모두 Long으로 일치하므로 추가 변경이 필요 없습니다.

app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageSaveScreen.kt (2)

46-51: 신규 콜백(onBookClick, onFeedClick) 추가 및 기본값 처리 LGTM

기본 no-op 제공으로 기존 호출부 영향 없이 확장되었습니다. 하위 컴포저블로의 전달도 자연스럽습니다.


120-136: 하위 콘텐츠로 콜백 전파가 일관적이고 명확합니다

  • FeedContent: onFeedClick(feed.id)
  • BookContent: onClick → onBookClick(book.isbn)

탭 전환과 데이터 로딩(LaunchedEffect(selectedTabIndex))도 적절합니다.

app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt (3)

173-185: FeedRoutes.My 화면 진입 로직 LGTM

Feed 탭의 백스택에 스코프된 FeedViewModel을 재사용하고, FeedMyScreen 내에서 탭 인덱스 전환을 트리거하는 흐름이 자연스럽습니다.


201-226: Feed 댓글 화면으로의 내/타인 분기 연동이 적절합니다

FeedCommentScreen으로부터의 프로필 네비게이션 콜백이 일관되게 FeedRoutes.My/Others로 분기됩니다.


231-237: 구독자 목록(onProfileClick) 분기 로직이 명확합니다

isMyself 플래그를 활용해 My/Others를 정확히 분기하고 있습니다.

app/src/main/java/com/texthip/thip/ui/feed/screen/FeedMyScreen.kt (1)

49-51: 탭 전환 트리거 로직은 적절합니다

LaunchedEffect(Unit)으로 최초 1회 My 탭 전환을 보장해 화면 진입 경험이 명확합니다.

app/src/main/java/com/texthip/thip/ui/feed/screen/OthersSubscriptionListScreen.kt (3)

71-72: 하위 컴포저블로의 콜백 전달 배선이 명확합니다.

단순 전달 패턴이어서 재조합에 따른 부작용이 없어 보입니다.


125-125: 아이템 클릭 시 isMyself 플래그를 함께 전달하는 방식이 요구사항에 부합합니다.

  • 키(key)에 userId를 사용하고 있어 리스트 안정성도 확보되었습니다.

182-183: Preview 콜백 시그니처 반영이 정확합니다.

미리보기에서 no-op으로 두는 선택도 합리적입니다. 필요하면 println/log로 클릭 동작을 가볍게 확인할 수 있습니다.

Comment on lines +201 to 208
modifier = if (isOverlayVisible) {
Modifier
.fillMaxSize()
.blur(5.dp)
.background(colors.Black800)
} else {
Modifier.fillMaxSize()
}
// 바깥 터치 시 키보드 숨기기
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

오버레이(메뉴/다이얼로그/이미지뷰어) 표시 시 배경 터치가 차단되지 않습니다

현재는 blur만 적용되어 있고 입력을 소거하지 않아 배경의 터치가 통과할 수 있습니다. 오버레이가 띄워진 동안 포인터 이벤트를 소비하도록 수정하세요.

-        Box(
-            modifier = if (isOverlayVisible) {
-                Modifier
-                    .fillMaxSize()
-                    .blur(5.dp)
-            } else {
-                Modifier.fillMaxSize()
-            }
+        Box(
+            modifier = if (isOverlayVisible) {
+                Modifier
+                    .fillMaxSize()
+                    .blur(5.dp)
+                    .pointerInput(Unit) {
+                        awaitPointerEventScope {
+                            while (true) { awaitPointerEvent() } // 모든 터치 소비
+                        }
+                    }
+            } else {
+                Modifier.fillMaxSize()
+            }
📝 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
modifier = if (isOverlayVisible) {
Modifier
.fillMaxSize()
.blur(5.dp)
.background(colors.Black800)
} else {
Modifier.fillMaxSize()
}
// 바깥 터치 시 키보드 숨기기
Box(
modifier = if (isOverlayVisible) {
Modifier
.fillMaxSize()
.blur(5.dp)
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) { awaitPointerEvent() } // 모든 터치 소비
}
}
} else {
Modifier.fillMaxSize()
}
) {
// 바깥 터치 시 키보드 숨기기
}
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt around
lines 201 to 208, the overlay only applies a blur so pointer events still pass
through to the background; update the modifier so that when isOverlayVisible is
true it also consumes pointer events. Add a conditional pointer-consumption
layer (e.g., a pointerInput or clickable layer that continuously awaits and
consumes pointer events while the overlay is visible) on the same composable
that applies the blur, ensuring taps are swallowed and do not reach underlying
views; keep the non-overlay branch as Modifier.fillMaxSize().

Comment on lines +381 to 387
selectedCommentForMenu = CommentActionTarget(comment.commentId!!, comment.isWriter)
isCommentMenuVisible = true
},
onReplyLongPress = { reply ->
selectedCommentId = reply.commentId
},
onDismissPopup = {
selectedCommentId = null
selectedCommentForMenu = CommentActionTarget(reply.commentId, reply.isWriter)
isCommentMenuVisible = true
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

NPE 위험: commentId가 null일 수 있는 타입에 대해 !! 사용

key에서 comment.commentId ?: comment.hashCode()로 널 가능성을 인정하고 있으나, 롱프레스 처리에서는 !!로 단언하고 있어 크래시 위험이 있습니다.

안전하게 처리하는 것으로 교체를 권장합니다:

-                                    onCommentLongPress = { comment ->
-                                        selectedCommentForMenu = CommentActionTarget(comment.commentId!!, comment.isWriter)
-                                        isCommentMenuVisible = true
-                                    },
+                                    onCommentLongPress = { comment ->
+                                        val id = comment.commentId
+                                        if (id != null) {
+                                            selectedCommentForMenu = CommentActionTarget(id, comment.isWriter)
+                                            isCommentMenuVisible = true
+                                        }
+                                    },
                                     onReplyLongPress = { reply ->
-                                        selectedCommentForMenu = CommentActionTarget(reply.commentId, reply.isWriter)
-                                        isCommentMenuVisible = true
+                                        val id = reply.commentId
+                                        if (id != null) {
+                                            selectedCommentForMenu = CommentActionTarget(id, reply.isWriter)
+                                            isCommentMenuVisible = true
+                                        }
                                     },
📝 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
selectedCommentForMenu = CommentActionTarget(comment.commentId!!, comment.isWriter)
isCommentMenuVisible = true
},
onReplyLongPress = { reply ->
selectedCommentId = reply.commentId
},
onDismissPopup = {
selectedCommentId = null
selectedCommentForMenu = CommentActionTarget(reply.commentId, reply.isWriter)
isCommentMenuVisible = true
},
onCommentLongPress = { comment ->
val id = comment.commentId
if (id != null) {
selectedCommentForMenu = CommentActionTarget(id, comment.isWriter)
isCommentMenuVisible = true
}
},
onReplyLongPress = { reply ->
val id = reply.commentId
if (id != null) {
selectedCommentForMenu = CommentActionTarget(id, reply.isWriter)
isCommentMenuVisible = true
}
},
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt around
lines 381-387, remove the unsafe non-null assertion on comment.commentId (the
"!!") and instead compute a safe id consistent with the key logic (e.g., val id
= comment.commentId ?: comment.hashCode() or convert hashCode to Long if the
constructor expects Long), then pass that id into CommentActionTarget along with
comment.isWriter; this avoids NPEs by using the same null-safe fallback used
elsewhere.

Comment on lines +517 to 523
if (showDeleteDialog) {
Box(
Modifier
.fillMaxSize()
.clickable { showDialog = false }) {
.clickable(enabled = false, onClick = {})
) {
Box(Modifier.align(Alignment.Center)) {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

클릭 차단을 위해 clickable(enabled = false)는 효과가 없습니다

enabled=false는 포인터 입력을 추가하지 않아 배경 터치가 통과합니다. 빈 onClick으로 터치를 소비하세요.

-            Box(
-                Modifier
-                    .fillMaxSize()
-                    .clickable(enabled = false, onClick = {})
-            ) {
+            Box(
+                Modifier
+                    .fillMaxSize()
+                    .clickable(
+                        indication = null,
+                        interactionSource = remember { androidx.compose.foundation.interaction.MutableInteractionSource() }
+                    ) { /* consume clicks */ }
+            ) {
📝 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
if (showDeleteDialog) {
Box(
Modifier
.fillMaxSize()
.clickable { showDialog = false }) {
.clickable(enabled = false, onClick = {})
) {
Box(Modifier.align(Alignment.Center)) {
if (showDeleteDialog) {
Box(
Modifier
.fillMaxSize()
.clickable(
indication = null,
interactionSource = remember { androidx.compose.foundation.interaction.MutableInteractionSource() }
) { /* consume clicks */ }
) {
Box(Modifier.align(Alignment.Center)) {
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt around
lines 517 to 523, the current Modifier.clickable(enabled = false, onClick = {})
does not block pointer events because enabled=false prevents adding pointer
handling; replace it with a clickable modifier that provides an empty onClick
handler (i.e., a consuming no-op onClick) so the background touch is consumed
and clicks do not pass through, ensuring the dialog overlay intercepts touches.

Comment on lines +34 to +35
@Serializable
data object My : FeedRoutes()
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

새 FeedRoutes.My 추가 자체는 적절합니다. 다만 네이밍/일관성 점검이 있으면 더 좋겠습니다.

  • 네이밍: 기존 패턴(MySubscription, OthersSubscription, Others)을 고려하면 My는 다소 모호합니다. MyFeed 등 구체적 네이밍을 고려해 보세요.
  • 타입 일관성(참고): 동일 파일 내 Write.feedId가 Int?이고, Comment.feedId는 Long입니다. 도메인 단위로 feedId 타입(Long 권장)을 일관화하면 파이프라인 전반(네비, VM, API)에서 캐스팅 잡음이 줄어듭니다.
  • 내비게이션 등록 확인: composable<FeedRoutes.My>가 실제 그래프에 등록되었는지, 관련 딥링크/업네비 동작(Back stack)도 함께 확인 부탁드립니다.

다음 스크립트로 사용/등록 여부와 타입 불일치를 빠르게 훑을 수 있습니다:


🏁 Script executed:

#!/bin/bash
# FeedRoutes.My 사용/그래프 등록 확인
rg -nP -C3 '\bcomposable<\s*FeedRoutes\.My\s*>' --type=kt
rg -nP -C2 '\bFeedRoutes\.My\b' --type=kt

# Write.feedId 타입 확인(참고)
rg -nP -n 'data\s+class\s+Write\(' app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt

Length of output: 288


🏁 Script executed:

#!/bin/bash
# FeedRoutes.My 네비게이션 등록 여부 확인
rg -nP -C3 'composable<\s*FeedRoutes\.My\s*>' -g '*.kt'
rg -nP '\bFeedRoutes\.My\b' -g '*.kt'

# FeedRoutes.kt 내 feedId 타입 확인
rg -n 'feedId' app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt

Length of output: 2064


FeedRoutes.My 추가 – 네이밍·타입·네비게이션 검토

  • 네이밍
    • 현재 MyMySubscription, OthersSubscription, Others 패턴 대비 다소 모호합니다.
    MyFeed 등 보다 구체적인 이름을 검토해주세요.

  • 피드 ID 타입 일관성 (app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt)
    Write.feedId: Int? vs Comment.feedId: Long
    • 도메인(네비, ViewModel, API) 전반에서 Long으로 통일해 불필요한 캐스팅과 잠재적 데이터 손실을 방지하세요.

  • 네비게이션 등록 확인
    app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt에 이미
    composable<FeedRoutes.My>로 등록되어 있으며,
    navController.navigate(FeedRoutes.My) 호출도 다수 존재합니다.
    • 딥링크 및 Back stack 동작이 의도대로 작동하는지 추가 검증을 부탁드립니다.

🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt around
lines 34-35, the new route named `My` is ambiguous and the feedId types are
inconsistent; rename `My` to a more descriptive name like `MyFeed` (or
`MySubscriptionFeed`) to match the `MySubscription`/`OthersSubscription`
pattern, and change all feedId usages to Long (e.g., make Write.feedId: Long?
instead of Int?) across routes, ViewModels, navigation arguments, and API models
to ensure type consistency and avoid casts/data loss; after renaming and type
changes, update all navigation registrations
(app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt)
and every navController.navigate(...) call to use the new route, and run manual
tests for deep links and Back stack behavior to confirm navigation works as
intended.

@rbqks529 rbqks529 merged commit a823936 into THIP-TextHip:develop Aug 20, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] QA 수정사항 반영 [(THIP2025-301)]

2 participants