Skip to content

[UI] 기록장 화면에 필요한 컴포넌트#38

Merged
Nico1eKim merged 14 commits intoTHIP-TextHip:developfrom
Nico1eKim:ui/#33-group_note
Jul 4, 2025
Merged

[UI] 기록장 화면에 필요한 컴포넌트#38
Nico1eKim merged 14 commits intoTHIP-TextHip:developfrom
Nico1eKim:ui/#33-group_note

Conversation

@Nico1eKim
Copy link
Member

@Nico1eKim Nico1eKim commented Jul 4, 2025

➕ 이슈 링크


🔎 작업 내용

  • 바텀시트 컴포넌트 만들었습니다
  • 페이지만 입력할 수 있는 textfield 컴포넌트 만들었습니다
  • 아이콘만 들어가는 버튼 컴포넌트 만들었습니다
  • 페이지 필터할 수 있는 버튼 컴포넌트 만들었습니다
  • 탭바 컴포넌트로 분리했습니다
  • 필터링에 쓰이는 버튼 컴포넌트 만들었습니다
  • 기존 option chip button 확장성있게 수정했습니다
  • 필터 header 컴포넌트 만들었습니다
  • action bar button 컴포넌트 만들었습니다
  • 내용만 들어가는 댓글 컴포넌트 만들었습니다

📸 스크린샷

바텀시트 컴포넌트

2025-07-04.2.37.46.mov

아이콘만 들어가는 컴포넌트: SendButton

image

기록 필터 버튼 컴포넌트

2025-07-04.2.41.23.mov

탭바 컴포넌트로 분리

2025-07-04.2.42.44.mov

댓글 하단부 컴포넌트: ActionBarButton

Uploading 화면 기록 2025-07-04 오후 2.44.15.mov…


📢 리뷰어들에게

  • 바텀시트 컴포넌트의 경우 바텀시트가 쓰이는 screen의 최상단에
Box(
        if (isBottomSheetVisible) {
            Modifier
                .fillMaxSize()
                .blur(5.dp)
        } else {
            Modifier.fillMaxSize()
        }
    )

와 같이 감싸줘야 블러 효과가 적용됩니다. 적용법 헷갈리시면 GroupRoomScreen 참고 부탁합니다!

  • 탭바의 경우 width가 고정되어있었는데, 그렇게하면 글씨가 길어지는 경우 custom이 자유롭지 않아서 기존 TabRow에서 ScrollableTabRow로 리팩했습니다!
  • action bar button 컴포넌트의 경우 좋아요, 댓글은 모든 컴포넌트에 공통적인거같아서 따로 필드를 분리하지 않았고 핀, 저장의 경우는 넣고 뺄 수 있도록 했습니다!

Summary by CodeRabbit

  • 신규 기능

    • 그룹룸 화면에 모달 하단 시트 메뉴(방 나가기, 신고, 삭제 등) 추가 및 블러 효과 적용.
    • 다양한 UI 컴포넌트(메뉴 바텀시트, 액션바 버튼, 필터 칩 버튼, 폼 버튼, 전송 버튼, 페이지 입력 필드, 헤더 탭, 필터 헤더, 텍스트 댓글 카드) 추가.
    • 그룹 노트 아이템(댓글/투표) 데이터 구조 추가.
  • 버그 수정

    • 하트 아이콘 벡터 리소스 크기 및 경로 개선.
  • 스타일

    • 필터 버튼 및 옵션 칩 버튼의 레이아웃과 활성/비활성 스타일 개선.
  • 문서화

    • 그룹룸 관련 신규 문자열(방 나가기, 신고, 삭제, 페이지 등) 리소스 추가.

@coderabbitai
Copy link

coderabbitai bot commented Jul 4, 2025

Caution

Review failed

The pull request is closed.

"""

Walkthrough

여러 Jetpack Compose UI 컴포넌트(버튼, 칩, 바텀시트, 폼 등)와 그룹 노트 관련 데이터 모델, 문자열 리소스, 벡터 드로어블이 추가 및 개선되었습니다. 또한 .idea/deploymentTargetSelector.xml IDE 설정 파일이 삭제되었습니다. 일부 기존 컴포넌트는 인터페이스와 스타일이 확장 또는 변경되었습니다.

Changes

파일/경로 그룹 변경 요약
.idea/deploymentTargetSelector.xml IDE 배포 타겟 선택 설정 파일 삭제
app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt 바텀시트 메뉴 및 아이템 데이터 클래스 추가, 애니메이션 및 제스처 지원
app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt 액션바 버튼 UI 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/common/buttons/FilterButton.kt 레이아웃 수정: 컬럼이 항상 최대 너비, 우측 정렬 적용
app/src/main/java/com/texthip/thip/ui/common/buttons/FilterChipButton.kt 필터 칩 버튼 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/common/buttons/FormButton.kt 페이지 입력 폼 버튼 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt enabled, textStyle 파라미터 추가, 비활성화 스타일 지원, 인터페이스 변경
app/src/main/java/com/texthip/thip/ui/common/buttons/SendButton.kt 전송 버튼 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/common/forms/PageTextField.kt 페이지 입력 텍스트필드 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt 헤더 탭 메뉴바 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/group/note/component/FilterHeaderSection.kt 필터 헤더 섹션 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt 텍스트 코멘트 카드 컴포넌트 및 프리뷰 추가
app/src/main/java/com/texthip/thip/ui/group/note/mock/CommentData.kt 그룹 노트 아이템/레코드/투표 데이터 모델 계층 추가
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt 바텀시트 메뉴 및 블러 효과 추가, 상태 관리 및 UI 레이어링 변경
app/src/main/res/drawable/ic_heart.xml 하트 벡터 드로어블 뷰포트 및 경로 데이터 수정
app/src/main/res/values/strings.xml 그룹룸 관련 및 UI용 문자열 9개 추가

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant GroupRoomScreen
    participant MenuBottomSheet

    User->>GroupRoomScreen: 우측 상단 메뉴 아이콘 클릭
    GroupRoomScreen->>MenuBottomSheet: 바텀시트 표시 (isBottomSheetVisible = true)
    User->>MenuBottomSheet: 메뉴 아이템 클릭 or 바깥 영역 클릭/드래그
    MenuBottomSheet->>GroupRoomScreen: onDismiss 호출 (isBottomSheetVisible = false)
Loading
sequenceDiagram
    participant User
    participant FilterHeaderSection
    participant FormButton

    User->>FilterHeaderSection: "페이지별 보기" 칩 클릭
    FilterHeaderSection->>FormButton: 페이지 입력 폼 표시
    User->>FormButton: 페이지 입력/초기화/완료 버튼 클릭
    FormButton->>FilterHeaderSection: 입력값 변경 or 완료 콜백 호출
Loading

Possibly related PRs

  • THIP-TextHip/THIP-Android#31: .idea/deploymentTargetSelector.xml 파일을 .gitignore에 추가 및 수정하여 본 PR과 동일 파일 관리 관련
  • THIP-TextHip/THIP-Android#21: .idea/deploymentTargetSelector.xml 파일을 추가 및 확장, 본 PR과 반대 방향(추가 vs 삭제)으로 동일 파일 변경

Suggested reviewers

  • rbqks529

Poem

🐰
새로운 버튼, 칩, 바텀시트,
UI가 반짝, 기능이 빛~
하트도 살짝 작아지고
그룹룸 메뉴가 아래로 휙!
토끼는 깡총, 코드를 찬양해
Compose 세상에 또 한 번 만세!

"""


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b4b0111 and 6f8cfb7.

📒 Files selected for processing (1)
  • app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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: 6

🧹 Nitpick comments (9)
app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt (3)

61-64: 텍스트 오버플로 방지 미흡

탭 라벨이 길어질 경우 잘려서 보이지 않을 수 있습니다. maxLines = 1overflow = TextOverflow.Ellipsis를 지정해 UI 깨짐을 예방하세요.


29-29: 하드코딩된 색상 대신 테마 색상 사용 권장

indicatorColor 기본값을 Color.White로 두면 다크모드나 테마 변경 시 부조화를 일으킬 수 있습니다. ThipTheme.colors.White(또는 새로 정의한 색상)로 교체해 일관성을 유지하세요.


74-80: 프리뷰 상태 변수 선언 방식

var selectedIndex = rememberSaveable { mutableIntStateOf(0) }MutableIntState를 변수로 들고 있어 가독성이 떨어집니다. Kotlin 위임 프로퍼티를 사용하면 더 깔끔합니다.

-var selectedIndex = rememberSaveable { mutableIntStateOf(0) }
+var selectedIndex by rememberSaveable { mutableIntStateOf(0) }
app/src/main/java/com/texthip/thip/ui/group/note/mock/CommentData.kt (1)

4-5: TODO 주석을 해결하고 적절한 날짜 타입을 사용하세요.

postDate가 현재 Int 타입으로 되어 있고 TODO 주석이 있습니다. 날짜 처리를 위해 String 보다는 LocalDateTime이나 Long (타임스탬프) 사용을 고려해보세요.

-//    abstract val postDate: String
-abstract val postDate: Int // TODO: String으로 바꾸기
+abstract val postDate: Long // 타임스탬프 사용 권장

또는 더 명확한 날짜 처리를 위해:

+import java.time.LocalDateTime
-abstract val postDate: Int // TODO: String으로 바꾸기
+abstract val postDate: LocalDateTime

이 TODO 항목을 해결하는 데 도움이 필요하시면 새로운 이슈로 만들어 드릴까요?

app/src/main/java/com/texthip/thip/ui/common/buttons/FilterChipButton.kt (1)

74-74: 하드코딩된 문자열을 StringResource로 추출하세요.

프리뷰에서 사용된 "페이지별 보기" 텍스트가 하드코딩되어 있습니다. 유지보수성과 현지화를 위해 strings.xml 파일로 추출하는 것이 좋습니다.

-        text = "페이지별 보기",
+        text = stringResource(R.string.page_view_filter),
app/src/main/java/com/texthip/thip/ui/common/forms/PageTextField.kt (1)

37-46: 페이지 번호 입력 검증 추가를 고려해보세요.

현재 구현은 숫자 키보드를 사용하지만, 음수나 0, 빈 문자열 등에 대한 검증이 없습니다. 유효한 페이지 번호 범위를 제한하는 것을 고려해보세요.

BasicTextField(
    value = text,
-   onValueChange = onTextChange,
+   onValueChange = { newValue ->
+       if (newValue.isEmpty() || (newValue.toIntOrNull()?.let { it > 0 } == true)) {
+           onTextChange(newValue)
+       }
+   },
    textStyle = typography.copy_r400_s14.copy(color = colors.White),
    keyboardOptions = KeyboardOptions.Default.copy(
        keyboardType = KeyboardType.Number
    ),
    cursorBrush = SolidColor(colors.NeonGreen),
)
app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt (2)

104-123: 드래그 제스처 처리 개선

현재 드래그 제스처 구현에서 dragAmount / 2로 감속 효과를 주고 있으나, 사용자 경험 개선을 위해 더 정교한 제스처 처리가 필요합니다.

                .pointerInput(Unit) {
                    detectVerticalDragGestures(
                        onVerticalDrag = { _, dragAmount ->
-                            if (dragAmount > 0) {
-                                offsetY += dragAmount / 2  // 아래로 드래그할 때만 적용
-                            }
+                            if (dragAmount > 0) {
+                                offsetY = (offsetY + dragAmount).coerceAtMost(200f)
+                            }
                        },
                        onDragEnd = {
                            if (offsetY > 100f && !isDismissing) {
                                isDismissing = true
                                scope.launch {
                                    animatableOffset.animateTo(300f, tween(300))
                                    onDismiss()
                                }
                            } else {
+                                scope.launch {
+                                    offsetY = 0f
+                                }
-                                offsetY = 0f
                            }
                        }
                    )
                }

55-55: 매직 넘버를 상수로 추출

하드코딩된 숫자들을 의미 있는 상수로 추출하여 가독성과 유지보수성을 개선하세요.

+private const val INITIAL_OFFSET = 300f
+private const val ANIMATION_DURATION = 300
+private const val DRAG_THRESHOLD = 100f

-    val animatableOffset = remember { Animatable(300f) } // 시작 위치 아래
+    val animatableOffset = remember { Animatable(INITIAL_OFFSET) }
app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt (1)

35-35: 문자열 연결 개선

문자열 연결 방식을 개선하여 가독성을 높이세요.

-            bottomText = data.page.toString() + stringResource(R.string.page),
+            bottomText = stringResource(R.string.page_format, data.page),

그리고 strings.xml에 다음을 추가하세요:

<string name="page_format">%d페이지</string>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between df00e1f and b4b0111.

📒 Files selected for processing (16)
  • .idea/deploymentTargetSelector.xml (0 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/FilterButton.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/FilterChipButton.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/FormButton.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt (4 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/buttons/SendButton.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/forms/PageTextField.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/component/FilterHeaderSection.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/note/mock/CommentData.kt (1 hunks)
  • app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (2 hunks)
  • app/src/main/res/drawable/ic_heart.xml (1 hunks)
  • app/src/main/res/values/strings.xml (1 hunks)
💤 Files with no reviewable changes (1)
  • .idea/deploymentTargetSelector.xml
🧰 Additional context used
🧠 Learnings (5)
📓 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.
app/src/main/res/values/strings.xml (1)
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.
app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt (1)
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.
app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt (1)
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.
app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt (1)
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.
🧬 Code Graph Analysis (3)
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (2)
app/src/main/java/com/texthip/thip/ui/common/topappbar/GradationTopAppBar.kt (1)
  • GradationTopAppBar (24-72)
app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt (1)
  • MenuBottomSheet (49-156)
app/src/main/java/com/texthip/thip/ui/common/buttons/FormButton.kt (2)
app/src/main/java/com/texthip/thip/ui/common/forms/PageTextField.kt (1)
  • PageTextField (24-47)
app/src/main/java/com/texthip/thip/ui/common/buttons/SendButton.kt (1)
  • SendButton (21-46)
app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt (2)
app/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.kt (1)
  • ProfileBar (34-116)
app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt (1)
  • ActionBarButton (24-99)
🔇 Additional comments (22)
app/src/main/res/values/strings.xml (1)

160-168: 새로운 문자열 리소스 추가가 적절합니다.

그룹 룸 기능을 위한 새로운 문자열 리소스들이 잘 추가되었습니다. 명명 규칙이 기존 패턴과 일치하고, 한국어 현지화가 적절하게 되어 있습니다. 이는 하드코딩된 문자열을 StringResource로 추출하는 좋은 관례를 따르고 있습니다.

app/src/main/java/com/texthip/thip/ui/common/buttons/SendButton.kt (1)

21-46: SendButton 컴포넌트 구현이 잘 되어 있습니다.

Compose 패턴을 잘 따르고 있고, 조건부 스타일링과 클릭 처리가 적절하게 구현되어 있습니다. 활성/비활성 상태에 따른 시각적 피드백도 명확합니다.

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

3-51: 데이터 모델 설계가 잘 되어 있습니다.

sealed class 계층구조를 통해 다양한 타입의 그룹 노트 아이템을 효과적으로 표현하고 있습니다. 공통 속성들이 잘 추상화되어 있고, 각 구체적인 타입들의 고유 속성들도 적절히 정의되어 있습니다.

app/src/main/java/com/texthip/thip/ui/common/buttons/FilterButton.kt (1)

45-48: 레이아웃 구조 개선이 적절합니다.

필터 버튼을 Column으로 감싸고 정렬 제어를 부모 컨테이너로 이동시킨 것은 좋은 레이아웃 개선입니다. 이렇게 하면 레이아웃 제어가 더 명확해지고 유지보수가 용이해집니다.

app/src/main/res/drawable/ic_heart.xml (1)

2-7: 아이콘 크기 표준화가 적절합니다.

하트 아이콘의 크기를 25dp에서 24dp로 변경하고 뷰포트를 맞춰 조정한 것은 Material Design 가이드라인을 따르는 좋은 개선입니다. 24dp는 표준적인 아이콘 크기이며, 패스 데이터도 새로운 뷰포트에 맞게 적절히 업데이트되었습니다.

app/src/main/java/com/texthip/thip/ui/common/buttons/FilterChipButton.kt (1)

27-67: 잘 구현된 재사용 가능한 컴포넌트입니다.

FilterChipButton 컴포넌트가 깔끔하게 구현되었습니다. 상태 기반 스타일링, 조건부 아이콘 표시, 외부 상태 관리 등이 잘 적용되었습니다.

app/src/main/java/com/texthip/thip/ui/common/forms/PageTextField.kt (1)

24-47: 깔끔하게 구현된 페이지 입력 컴포넌트입니다.

PageTextField 컴포넌트가 목적에 맞게 잘 구현되었습니다. 적절한 크기, 스타일링, 그리고 숫자 키보드 설정이 잘 적용되었습니다.

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

43-53: 바텀시트 블러 효과 구현이 잘 되었습니다.

바텀시트가 보일 때 배경에 블러 효과를 적용하는 방식이 PR 목표에 따라 올바르게 구현되었습니다. 조건부 Modifier 사용이 깔끔합니다.


120-143: 바텀시트 통합이 올바르게 구현되었습니다.

MenuBottomSheet 컴포넌트와의 통합이 깔끔하게 이루어졌습니다. 상태 관리, 문자열 리소스 사용, 그리고 dismiss 처리가 모두 적절합니다.

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

35-35: 전송 버튼 활성화 로직이 올바릅니다.

페이지 입력 필드 중 하나라도 비어있지 않으면 전송 버튼이 활성화되는 로직이 적절합니다.


26-86: 잘 구성된 폼 버튼 컴포넌트입니다.

FormButton 컴포넌트가 PageTextField와 SendButton을 잘 조합하여 구현되었습니다. 레이아웃, 상태 관리, 그리고 리셋 기능이 모두 적절하게 구현되었습니다.

app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt (1)

24-99: 유연하고 재사용 가능한 액션바 컴포넌트입니다.

ActionBarButton이 좋아요, 댓글, 핀, 저장 기능을 잘 통합하였습니다. 조건부 가시성 처리, 상태 기반 아이콘 변경, 그리고 외부 상태 관리가 모두 적절하게 구현되었습니다.

app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt (2)

43-47: 데이터 클래스 구조가 적절합니다

MenuBottomSheetItem 데이터 클래스의 구조가 메뉴 항목을 표현하기에 적절하고, 기본값 설정도 합리적입니다.


158-181: 프리뷰 컴포넌트 적절

프리뷰에서 실제 문자열 리소스를 사용하여 다양한 메뉴 항목을 보여주는 것이 좋습니다.

app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt (3)

36-37: 새로운 파라미터 추가 적절

enabledtextStyle 파라미터 추가로 컴포넌트의 확장성이 향상되었습니다. 기본값 설정도 합리적입니다.


43-59: 비활성화 상태 처리 로직 개선

비활성화 상태에 대한 색상 처리 로직이 적절하게 구현되었습니다. 사용자가 버튼의 상태를 명확히 인지할 수 있습니다.


72-77: 레이아웃 일관성 개선

고정 높이 설정과 패딩 조정으로 버튼의 시각적 일관성이 향상되었습니다.

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

26-26: 좋아요 상태 관리 검토

현재 isLiked 상태가 로컬에서만 관리되고 있습니다. 실제 앱에서는 서버 동기화가 필요할 수 있습니다.

이 컴포넌트가 실제로 사용될 때 좋아요 상태 변경이 서버에 반영되는지 확인해주세요. 필요하다면 상위 컴포넌트에서 상태 관리를 하거나 콜백을 통해 처리해야 할 수 있습니다.


60-78: 프리뷰 데이터 적절

프리뷰에서 실제 사용 시나리오를 잘 보여주는 샘플 데이터를 사용하고 있습니다.

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

35-36: 상태 관리 로직 적절

rememberSaveable을 사용하여 상태 보존을 적절히 처리하고, 페이지 필터 상태를 정확히 계산하고 있습니다.


59-67: OptionChipButton 사용 적절

새로 추가된 enabled 파라미터와 textStyle 파라미터를 적절히 활용하여 전체 보기 옵션을 구현했습니다.


84-100: 프리뷰 구현 우수

프리뷰에서 실제 사용 시나리오를 잘 시뮬레이션하고 있으며, 상태 관리도 적절히 구현되어 있습니다.

Comment on lines +51 to +56
Tab(
modifier = Modifier
.padding(horizontal = 5.dp)
.height(40.dp),
selected = selected,
onClick = { onTabSelected(index) },
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

터치 타깃 최소 높이 미준수

탭 높이를 40.dp로 고정하면 머티리얼 가이드라인의 최소 터치 영역(48 dp)을 만족하지 못해 접근성이 떨어집니다. 최소 48 dp 이상으로 늘리거나 minHeight를 사용해 유연하게 조정하는 것을 권장합니다.

🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt
around lines 51 to 56, the Tab component's height is fixed at 40.dp, which is
below the Material Design minimum touch target height of 48.dp, reducing
accessibility. To fix this, replace the fixed height with a minHeight modifier
set to at least 48.dp, allowing the tab to be at least 48.dp tall while
remaining flexible.

Comment on lines +36 to +43
indicator = { tabPositions ->
val tabPosition = tabPositions[selectedTabIndex]
Box(
modifier = Modifier
.tabIndicatorOffset(tabPosition)
.padding(horizontal = 20.dp)
.height(2.dp)
.background(indicatorColor, shape = RoundedCornerShape(1.5.dp))
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

빈 탭 목록일 때 런타임 크래시 가능성

tabPositions[selectedTabIndex] 호출은 titles가 비어 있거나 selectedTabIndex가 범위를 벗어나면 IndexOutOfBoundsException을 유발합니다.
방어 로직을 추가해 안전하게 처리해주세요.

-            val tabPosition = tabPositions[selectedTabIndex]
+            if (tabPositions.isNotEmpty() && selectedTabIndex in tabPositions.indices) {
+                val tabPosition = tabPositions[selectedTabIndex]
+                Box(
+                    modifier = Modifier
+                        .tabIndicatorOffset(tabPosition)
+                        .padding(horizontal = 20.dp)
+                        .height(2.dp)
+                        .background(indicatorColor, shape = RoundedCornerShape(1.5.dp))
+                )
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
indicator = { tabPositions ->
val tabPosition = tabPositions[selectedTabIndex]
Box(
modifier = Modifier
.tabIndicatorOffset(tabPosition)
.padding(horizontal = 20.dp)
.height(2.dp)
.background(indicatorColor, shape = RoundedCornerShape(1.5.dp))
indicator = { tabPositions ->
if (tabPositions.isNotEmpty() && selectedTabIndex in tabPositions.indices) {
val tabPosition = tabPositions[selectedTabIndex]
Box(
modifier = Modifier
.tabIndicatorOffset(tabPosition)
.padding(horizontal = 20.dp)
.height(2.dp)
.background(indicatorColor, shape = RoundedCornerShape(1.5.dp))
)
}
}
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt
around lines 36 to 43, the code accesses tabPositions[selectedTabIndex] without
checking if tabPositions is empty or if selectedTabIndex is within bounds, which
can cause an IndexOutOfBoundsException. Add a guard condition to verify that
tabPositions is not empty and selectedTabIndex is within the valid range before
accessing tabPositions[selectedTabIndex]. If the check fails, handle the case
safely, for example by not displaying the indicator or using a default position.

) {
Icon(
painter = painterResource(id = icon),
contentDescription = "Send Icon",
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

하드코딩된 콘텐츠 설명을 문자열 리소스로 추출하세요.

접근성을 위한 contentDescription이 하드코딩되어 있습니다. 현지화 및 일관성을 위해 strings.xml에 추가하는 것이 좋습니다.

-contentDescription = "Send Icon",
+contentDescription = stringResource(R.string.send_icon_description),

그리고 strings.xml에 추가:

<string name="send_icon_description">전송 아이콘</string>
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/common/buttons/SendButton.kt at line
42, the contentDescription is hardcoded as "Send Icon". To improve accessibility
and support localization, replace this hardcoded string with a reference to a
string resource. Add the string "send_icon_description" with the value "전송 아이콘"
to strings.xml, then update the contentDescription to use this resource.

Comment on lines 68 to 85
Box(
modifier = Modifier
.fillMaxSize()
.blur(5.dp)
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
if (!isDismissing) {
isDismissing = true
scope.launch {
animatableOffset.animateTo(300f, tween(300))
onDismiss()
}
}
}
.zIndex(1f) // 다른 컴포넌트 위에 뜨도록
)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

블러 효과 적용 방식 개선 필요

PR 목표에 따르면 블러 효과는 바텀시트를 사용하는 화면에서 콘텐츠를 Box로 감싸서 적용해야 합니다. 현재 구현에서는 바텀시트 자체에 블러를 적용하고 있어 의도와 다릅니다.

-    Box(
-        modifier = Modifier
-            .fillMaxSize()
-            .blur(5.dp)
-            .clickable(
-                indication = null,
-                interactionSource = remember { MutableInteractionSource() }
-            ) {
-                if (!isDismissing) {
-                    isDismissing = true
-                    scope.launch {
-                        animatableOffset.animateTo(300f, tween(300))
-                        onDismiss()
-                    }
-                }
-            }
-            .zIndex(1f) // 다른 컴포넌트 위에 뜨도록
-    )
+    Box(
+        modifier = Modifier
+            .fillMaxSize()
+            .background(Color.Black.copy(alpha = 0.3f))
+            .clickable(
+                indication = null,
+                interactionSource = remember { MutableInteractionSource() }
+            ) {
+                if (!isDismissing) {
+                    isDismissing = true
+                    scope.launch {
+                        animatableOffset.animateTo(300f, tween(300))
+                        onDismiss()
+                    }
+                }
+            }
+            .zIndex(1f)
+    )
📝 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
Box(
modifier = Modifier
.fillMaxSize()
.blur(5.dp)
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
if (!isDismissing) {
isDismissing = true
scope.launch {
animatableOffset.animateTo(300f, tween(300))
onDismiss()
}
}
}
.zIndex(1f) // 다른 컴포넌트 위에 뜨도록
)
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.3f))
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
if (!isDismissing) {
isDismissing = true
scope.launch {
animatableOffset.animateTo(300f, tween(300))
onDismiss()
}
}
}
.zIndex(1f)
)
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/common/bottomsheet/MenuBottomSheet.kt
between lines 68 and 85, the blur effect is incorrectly applied directly to the
bottom sheet component. To fix this, remove the blur modifier from the bottom
sheet and instead wrap the entire screen content that uses the bottom sheet
inside a Box composable with the blur modifier applied. This ensures the blur
effect is applied to the background content, not the bottom sheet itself,
matching the intended design.

Comment on lines +32 to +39
// profileImage = data.profileImageUrl,
profileImage = painterResource(R.drawable.character_literature),
topText = data.nickName,
bottomText = data.page.toString() + stringResource(R.string.page),
bottomTextColor = colors.Purple,
showSubscriberInfo = false,
// hoursAgo = data.postDate
hoursAgo = data.postDate
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

주석 처리된 코드 정리 필요

주석 처리된 코드들이 남아있어 완성도가 떨어져 보입니다. 프로필 이미지 로딩 로직을 완성하거나 주석을 제거하여 코드를 정리하세요.

        ProfileBar(
-//            profileImage = data.profileImageUrl,
-            profileImage = painterResource(R.drawable.character_literature),
+            profileImage = data.profileImageUrl?.let { rememberAsyncImagePainter(it) } 
+                ?: painterResource(R.drawable.character_literature),
            topText = data.nickName,
            bottomText = data.page.toString() + stringResource(R.string.page),
            bottomTextColor = colors.Purple,
            showSubscriberInfo = false,
-//            hoursAgo = data.postDate
            hoursAgo = data.postDate
        )
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt
around lines 32 to 39, there are commented-out lines related to profile image
loading and post date display. To improve code clarity and completeness, either
implement the profile image loading using data.profileImageUrl as originally
intended or remove the commented-out code entirely if not used. Clean up these
comments to ensure the code is tidy and maintainable.

Comment on lines +54 to +56
onCloseClick = {
isPageInputVisible = 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

FilterChipButton의 onCloseClick 로직 검토

onCloseClick에서 isPageInputVisible = true로 설정하는 것이 의도와 다를 수 있습니다. 닫기 버튼을 클릭했을 때는 입력 필드를 숨기고 필터를 초기화해야 할 것 같습니다.

                onCloseClick = {
-                    isPageInputVisible = true
+                    isPageInputVisible = false
+                    onFirstPageChange("")
+                    onLastPageChange("")
                }
🤖 Prompt for AI Agents
In
app/src/main/java/com/texthip/thip/ui/group/note/component/FilterHeaderSection.kt
around lines 54 to 56, the onCloseClick handler currently sets
isPageInputVisible to true, which likely contradicts the intended behavior.
Change the logic so that clicking the close button hides the input field by
setting isPageInputVisible to false and also reset or clear the filter state as
appropriate to properly initialize the filter.

@Nico1eKim Nico1eKim merged commit a2fbbe8 into THIP-TextHip:develop Jul 4, 2025
1 check was pending
Copy link
Collaborator

@rbqks529 rbqks529 left a comment

Choose a reason for hiding this comment

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

코드 확인 완료했습니다!

import com.texthip.thip.ui.theme.ThipTheme.typography
import kotlinx.coroutines.launch

data class MenuBottomSheetItem(
Copy link
Collaborator

Choose a reason for hiding this comment

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

data class는 분리 안하신 이유가 있을까용

Copy link
Member Author

Choose a reason for hiding this comment

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

아 이거 보기&수정하기 편하려고 같은 화면에 놓고 개발 하다가 옮겨야됐었는데 까먹었네요 .. ㅋㅎㅋㅎㅋㅎㅋ 옮기겠습니닷

import com.texthip.thip.R
import com.texthip.thip.ui.theme.ThipTheme.colors
import com.texthip.thip.ui.theme.ThipTheme.typography

Copy link
Collaborator

Choose a reason for hiding this comment

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

slot api 느낌의 코드 같은데 이렇게 분리 하신 이유가 있을까요?

Copy link
Collaborator

Choose a reason for hiding this comment

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

안스 켜서 확인해보니 많이 쓰이는 화면이네요 확인했습니다...

Copy link
Collaborator

Choose a reason for hiding this comment

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

이거 덕분에 편하게 개발했읍니다.,.

.padding(horizontal = 4.dp),
contentAlignment = Alignment.CenterStart,
) {
BasicTextField(
Copy link
Collaborator

Choose a reason for hiding this comment

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

이거 실행 시켜보니까 영어도 입력되는데 preview에서만 그런건가요? 그리고 혹시 모르니까 maxline = 1 도 있으면 좋을거 같아영

Copy link
Member Author

Choose a reason for hiding this comment

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

아 숫자만 입력하도록 필터링 걸게욧 ! maxline도 적용하겠습니닷

Copy link
Member

@JJUYAAA JJUYAAA left a comment

Choose a reason for hiding this comment

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

수고하셨었었었숩니다아!!

if (offsetY > 100f && !isDismissing) {
isDismissing = true
scope.launch {
animatableOffset.animateTo(300f, tween(300))
Copy link
Member

Choose a reason for hiding this comment

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

이런 튜닝값? 들도 위에 상수로 추출하는게 좋을 것 같아요! 나중에 UX적으로 숫자 수정할 일이 많을 것 같네용

Comment on lines +80 to +86
if (isPinVisible) {
Icon(
modifier = Modifier.clickable { onPinClick() },
painter = painterResource(R.drawable.ic_pin),
contentDescription = null,
tint = Color.White
)
Copy link
Member

Choose a reason for hiding this comment

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

요것은 원래 눌렀을때 색상변화가 없나유?

Copy link
Member Author

Choose a reason for hiding this comment

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

넹 디자이너님이 없다고 해쪄용

Comment on lines +50 to +53
PageTextField(
text = firstPage,
onTextChange = onFirstPageChange
)
Copy link
Member

Choose a reason for hiding this comment

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

자릿수 제한은 꼭 필요할 것 같아용 ~

Copy link
Member Author

Choose a reason for hiding this comment

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

이거 입력은 되는데 페이지 범위 넘어가면 토스트 메시지가 뜨는데 그래도 자릿수 제한이 필요할까욧 ? 지금은 maxline 적용해놓은 상태입니닷 !

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.

3 participants