Skip to content

refactor: 리컴포지션 최적화를 위한 람다 기반 Modifier 적용#230

Merged
easyhooon merged 8 commits intodevelopfrom
BOOK-473-refactor/#229
Dec 18, 2025
Merged

refactor: 리컴포지션 최적화를 위한 람다 기반 Modifier 적용#230
easyhooon merged 8 commits intodevelopfrom
BOOK-473-refactor/#229

Conversation

@easyhooon
Copy link
Copy Markdown
Contributor

@easyhooon easyhooon commented Dec 3, 2025

🔗 관련 이슈

📙 작업 설명

  • Modifier.background -> drawBehind { drawRect() } 으로 변경
    • 단순 컬러 매핑 방식의 background 사용 부분만 drawBehind { drawRect() } 로 변경 완료 (ex. .background(White))
    • 애니메이션이 적용된 background modifier만 drawBehind { drawRect() } 로 변경
    • 추가 설명 or 리뷰 포인트에 후술
  • Modifier.offset ->.offset { IntOffset() } 으로 변경
    • 모든 부분 문제 없는 관계로 변경 완료
  • Modifier.alpha(a).rotate(r).scale(s) -> .graphicsLayers { alpha = a rotationZ = r scaleX = s scaleY = s } 으로 변경
    • 현재 scale만 사용하고 있어 scale 사용 부분 graphicsLayers { scaleX = s scaleY = s} 로 변경 완료

🧪 테스트 내역 (선택)

  • 주요 기능 정상 동작 확인
  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

📸 스크린샷 또는 시연 영상 (선택)

💬 추가 설명 or 리뷰 포인트 (선택)

background Modifier 사용 전체를 drawBehind { drawRect() } 로 변경해보려고 했으나 문제점이 있었습니다.

1. Theme.colors 를 사용하는 부분

image drawRect() 내에서 themes 내에 포함된 color 사용 불가능 -> 해당 컬러를 변수로 선언하면 사용가능하지만, if else같은 분기처리 없는 color를 변수로 선언하는것은 코드량이 늘어나고, 무의미한 코드라 생각해서 이들은 .background() 패턴을 유지

2. background 내에 color 뿐만 아니라 shape로 설정하는 부분

-> 이부분은 shape를 Modifier.clip으로 빼내어 해결(변경 이후 UI가 같은지는 한번씩 확인 필요)

3. cornerShape가 clip, border에 중복으로 정의되어 있는 부분

-> 변수로 빼내어 한번만 생성되도록 함

reference)

Summary by CodeRabbit

릴리스 노트

  • Refactor
    • UI 렌더링 내부 정리: 모양(클립)과 배경 적용 순서 정리, 배경 파라미터 명시, 위치 오프셋 처리 방식 개선 등으로 코드 가독성과 일관성 향상.
    • 일부 컴포넌트에서 시각적 처리(툴팁/프레임/토글 트랙 등) 구현 방식이 변경되었음.

이 업데이트는 내부 구현 정리에 중점을 두었으며, 사용자에게 보이는 기능이나 디자인에는 변경이 없습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 3, 2025

Walkthrough

Compose Modifier 체인을 리팩토링하여 배경 색상 호출을 named parameter로 통일하고, shape 적용을 배경과 분리해서 clip(shape).background(color) 패턴으로 변경하며 일부 위치 오프셋을 IntOffset/roundToPx()로 계산하도록 조정했습니다. 공개 시그니처 변경은 없습니다.

Changes

코호트 / 파일(s) 변경 요약
Named 파라미터 배경 색상
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt, feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/HomeHeader.kt, feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/LibraryHeader.kt, feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt, feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt, feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt, feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/component/MainBottomBar.kt, feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt
.background(White) 등 기존 호출을 .background(color = ...) 형태로 명시화
clip + background 패턴 적용 (shape 분리)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/checkbox/CircleCheckBox.kt, core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/checkbox/SquareCheckBox.kt, core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/textfield/ReedRecordTextField.kt, core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/textfield/ReedSearchTextField.kt, core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/InfinityLazyColumn.kt, core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedDialog.kt, feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/component/QuoteItem.kt, feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/component/ReviewItem.kt, feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/BookCard.kt, feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/FilterChip.kt, feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/ImpressionGuideBox.kt, feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/SentenceBox.kt, feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/notification/NotificationUi.kt, feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/osslicenses/OssLicensesUi.kt, feature/edit/src/main/kotlin/com/ninecraft/booket/feature/edit/emotion/EmotionEditUi.kt
.background(color, shape = ...) 대신 .clip(shape).background(color)로 변경(clip import 추가) — 렌더링 순서 변경
로컬 색상 변수 사전 계산
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/RecordProgressBar.kt, core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedTopAppBar.kt, feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/BookUpdateBottomSheet.kt, feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/component/BookRegisterBottomSheet.kt
인라인 조건부 색상 계산을 val bgColor = ... 등으로 추출해 Modifier 호출 간소화
drawBehind 및 IntOffset 적용 / 오프셋 계산 리팩토링
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt, feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/OcrUi.kt, feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt, feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/ReedSwitch.kt
고정 오프셋을 IntOffset(...roundToPx())로 변환하고 일부 .background().drawBehind { drawRect(...) } 또는 graphicsLayer로 대체(clip/graphicsLayer import 변경 포함)
상호작용/접근성 리팩토링 및 기타 정리
feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/component/BookRegisterBottomSheet.kt, feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/BookUpdateBottomSheet.kt
selectable에 role = nullinteractionSource 추가; 일부 컴포넌트에서 배경 처리 및 텍스트 색 계산을 로컬 변수로 변경

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • 추가 검토 포인트:
    • clip 먼저 적용하는 변경이 border, hit-testing, 클릭 영역에 미치는 영향 (QuoteItem, ReviewItem, BookCard, 체크박스·칩 관련 파일)
    • IntOffset/roundToPx() 변환이 픽셀 정렬 및 레이아웃 위치를 이전과 동일하게 유지하는지 (CustomTooltipBox, OcrUi, ReedSwitch)
    • graphicsLayer로의 변환이 성능/렌더링 결과(특히 좌우/상하 반전)와 일치하는지 (CameraFrame)
    • drawBehind에서 색상/모양이 이전 background 호출과 동일하게 렌더되는지 (ReedSwitch)
    • 여러 파일에 반복적으로 적용된 패턴이므로 한두 파일에서 올바른 결과가 확인되면 다른 파일은 빠르게 검증 가능

Poem

🐇 나는 코드 밭을 훌쩍 뛰어다닌다
클립으로 모양을 만들고 색을 뒤따르게 하네
roundToPx로 발자국을 고정하고
modifier 춤을 깔끔히 정리했지
당근만큼 달콤한 리팩토링 축하해! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 람다 기반 Modifier 적용을 통한 리컴포지션 최적화라는 주요 변경사항을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed 변경사항이 #229 이슈의 목표를 대부분 충족합니다: offset과 graphicsLayers 변환은 완료되었고, background 변환도 부분 적용되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항은 람다 기반 Modifier 적용이라는 정의된 범위 내에 있으며, 연관된 background 호출 방식 변경도 리팩토링 목표와 일관됩니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BOOK-473-refactor/#229

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 1

Caution

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

⚠️ Outside diff range comments (2)
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (1)

9-24: Add missing androidx.compose.foundation.background import to fix compilation error

The file uses Modifier.background() at lines 132 and 222, but the required import androidx.compose.foundation.background is missing from the import section. This will cause a compilation error.

Add the import after line 24:

 import androidx.compose.foundation.verticalScroll
+import androidx.compose.foundation.background
 import androidx.compose.material3.Text
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/ReedSwitch.kt (1)

34-34: 구식 lint suppression 주석 제거 권장

코드가 이제 람다 기반 offset을 사용하고 있으므로, @SuppressLint("UseOfNonLambdaOffsetOverload") 주석은 더 이상 필요하지 않습니다. 이 주석을 제거하는 것이 좋습니다.

-@SuppressLint("UseOfNonLambdaOffsetOverload")
 @Composable
 internal fun ReedSwitch(
🧹 Nitpick comments (1)
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt (1)

20-21: SettingsUi 루트 배경 drawBehind 적용 및 중복 색상 처리

ReedScaffold의 modifier에서 background(White)drawBehind { drawRect(color = White) }로 바꾼 것은 리컴포지션 최적화 방향과 잘 맞고, 동작도 그대로 유지될 것으로 보입니다. 다만 containerColor = White도 이미 배경을 그리므로, 장기적으로는 둘 중 하나만 남겨서 중복을 줄이는 것도 고려해 볼 수 있습니다(이 PR에서 꼭 정리할 필요까지는 없어 보입니다).

Also applies to: 71-75

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67fd699 and dbbb6c4.

📒 Files selected for processing (14)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (2 hunks)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/HomeBanner.kt (2 hunks)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/HomeHeader.kt (2 hunks)
  • feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/LibraryHeader.kt (2 hunks)
  • feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt (2 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt (2 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/OcrUi.kt (4 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt (4 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (2 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt (2 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt (2 hunks)
  • feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/component/MainBottomBar.kt (2 hunks)
  • feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt (2 hunks)
  • feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/ReedSwitch.kt (3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-28T18:08:47.298Z
Learnt from: seoyoon513
Repo: YAPP-Github/Reed-Android PR: 72
File: feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt:21-82
Timestamp: 2025-07-28T18:08:47.298Z
Learning: Jetpack Compose에서 scale() 변환은 시각적 변환만 적용하며 레이아웃 좌표계는 변경하지 않는다. 따라서 scale(scaleX = -1f, scaleY = -1f)로 반전된 아이콘에서 padding()은 원래 레이아웃 기준으로 동작하므로, 시각적으로 올바른 위치를 위해서는 변환 전 좌표계 기준으로 padding을 설정해야 한다.

Applied to files:

  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt
📚 Learning: 2025-07-20T12:34:23.786Z
Learnt from: easyhooon
Repo: YAPP-Github/Reed-Android PR: 61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 `booket.android.feature` convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

Applied to files:

  • feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/LibraryHeader.kt
📚 Learning: 2025-08-28T12:25:54.058Z
Learnt from: easyhooon
Repo: YAPP-Github/Reed-Android PR: 174
File: feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt:128-133
Timestamp: 2025-08-28T12:25:54.058Z
Learning: In BookSearchPresenter.kt, when a guest user tries to register a book and is redirected to login, the bottom sheet (isBookRegisterBottomSheetVisible) and selection state (selectedBookIsbn, selectedBookStatus) are intentionally kept open/preserved so that when the user returns from login, they can continue from where they left off without losing context.

Applied to files:

  • feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Compose Stability Check
  • GitHub Check: ci-build
🔇 Additional comments (14)
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/HomeBanner.kt (1)

18-19: HomeBanner 배경을 drawBehind로 변경한 부분 확인

background(HomeBg)drawBehind { drawRect(HomeBg) }로 교체한 변경은 레이아웃·색상 동작을 그대로 유지하면서 람다 기반 Modifier로 전환하려는 PR 목적과 잘 맞습니다. 이 부분은 별다른 이슈 없이 그대로 가져가도 될 것 같습니다.

Also applies to: 48-53

feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (1)

28-31: HomeUi 루트 Column 배경 drawBehind 적용 확인

홈 화면 루트 Column에서 background(HomeBg)drawBehind { drawRect(color = HomeBg) }로 바꾼 부분은 색상·레이아웃 동작을 유지하면서 람다 기반 Modifier로 전환하려는 목적에 잘 부합합니다. Modifier 체인도 fillMaxSize() 이후에 배경을 그리고 그 위에 padding(innerPadding)을 적용하는 기존 구조를 그대로 유지하고 있어, 이 변경 자체로 인한 부작용은 없을 것으로 보입니다.

Also applies to: 100-105

feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/component/MainBottomBar.kt (1)

23-24: MainBottomBar 컨테이너 배경 drawBehind 변경 검토

하단 바 컨테이너의 배경을 background(White)에서 drawBehind { drawRect(color = White) }로 교체한 부분은 기존 둥근 모서리·테두리 구조(dropShadow → clip → border)와 계층을 그대로 유지하고 있어 시각적 결과나 레이아웃에는 변화가 없을 것으로 보입니다. 람다 기반 Modifier 전환이라는 PR 목적에도 부합하는 깔끔한 변경입니다.

Also applies to: 43-69

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt (1)

18-19: 툴팁 꼬리 offset의 IntOffset 람다 기반 변경

offset(x = (-10).dp, ...) 형태에서 offset { IntOffset(x = (-10).dp.roundToPx(), y = 0) }로 바꾼 부분은 Density 스코프 안에서 roundToPx()를 호출하는 올바른 람다 기반 패턴으로 보입니다. 음수 x 오프셋도 기존과 동일한 픽셀 값으로 계산되므로, 시각적인 위치 변화 없이 리컴포지션 최적화 목적을 달성하는 안전한 변경이라고 판단됩니다.

Also applies to: 48-56

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt (1)

28-29: QuoteStep 루트 Column 배경 drawBehind 변경

루트 Column에서 White 배경을 drawBehind { drawRect(color = White) }로 그리도록 변경한 것은 리컴포지션 최적화 방향과 잘 맞고, fillMaxSize() 이후·imePadding() 이전에 배경을 처리하고 있어 이전과 동일하게 전체 화면을 흰색으로 채울 수 있습니다. 이 변경으로 인한 기능·레이아웃 상의 문제점은 없어 보입니다.

Also applies to: 75-80

feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/LibraryHeader.kt (1)

14-15: LibraryHeader Row 배경 drawBehind 변경

헤더 Row에서 사용하던 White 배경을 drawBehind { drawRect(color = White) }로 교체한 변경은 레이아웃·색상 동작을 그대로 유지하면서 람다 기반 Modifier로 전환하려는 PR 목표에 잘 부합합니다. 다른 로직 변경 없이 렌더링 경로만 바뀐 것이어서, 이 부분은 그대로 머지해도 무방해 보입니다.

Also applies to: 30-35

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt (1)

14-15: CameraFrame 모서리 마커의 scale → graphicsLayer 전환 검토

세 군데 모서리 마커 아이콘에서 Modifier.scale 대신 graphicsLayer { scaleX / scaleY }를 사용하도록 바뀐 부분은, align → graphicsLayer → padding 순서를 그대로 유지하고 있어 레이아웃 좌표계나 패딩 기준이 변하지 않고 시각적인 결과도 기존과 동일하게 유지될 것으로 보입니다. Based on learnings, Jetpack Compose에서 scale/graphicsLayer는 레이아웃에는 영향을 주지 않고 시각적 변환만 적용하므로, 이 수정 방향은 타당하고 안전한 변경이라고 판단됩니다.

Also applies to: 50-85

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (1)

23-23: 변경 사항 확인 완료

람다 기반 drawBehind를 사용한 배경 렌더링 최적화가 올바르게 적용되었습니다. drawBehind는 드로잉 단계에서만 실행되므로 리컴포지션 최적화에 도움이 됩니다.

Also applies to: 54-54

feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/HomeHeader.kt (1)

14-14: 변경 사항 확인 완료

람다 기반 drawBehind를 사용한 배경 렌더링 최적화가 올바르게 적용되었습니다.

Also applies to: 33-33

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt (1)

36-36: 변경 사항 확인 완료

람다 기반 drawBehind를 사용한 배경 렌더링 최적화가 올바르게 적용되었습니다.

Also applies to: 90-90

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/OcrUi.kt (2)

43-43: 변경 사항 확인 완료

람다 기반 drawBehind를 사용한 배경 렌더링 최적화가 올바르게 적용되었습니다.

Also applies to: 195-195, 221-221


50-50: 변경 사항 확인 완료

람다 기반 offset을 사용한 위치 계산 최적화가 올바르게 적용되었습니다. IntOffset을 사용하여 오프셋 계산을 레이아웃 단계로 지연시켜 리컴포지션을 줄입니다.

Also applies to: 206-211

feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/ReedSwitch.kt (1)

62-67: 변경 사항 확인 완료

람다 기반 offset을 사용한 위치 계산 최적화가 올바르게 적용되었습니다.

feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt (1)

17-17: 변경 사항 확인 완료

람다 기반 drawBehind를 사용한 배경 렌더링 최적화가 올바르게 적용되었습니다.

Also applies to: 58-58

Copy link
Copy Markdown

@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: 0

🧹 Nitpick comments (1)
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (1)

218-224: LGTM! 페이저 인디케이터 최적화 완료

페이지 변경 시 리컴포지션을 최적화하기 위해 drawBehind를 적용한 것은 좋은 변경입니다. 기능적으로 동일하게 동작합니다.

선택적 개선 제안: 의미적 명확성을 위해 drawCircle 사용 고려

현재 drawRect로 사각형을 그린 후 CircleShape으로 클리핑하고 있습니다. 더 명확한 의도 표현을 위해 drawCircle을 사용할 수 있습니다:

                                    Box(
                                        modifier = Modifier
                                            .size(12.dp)
                                            .padding(3.dp)
                                            .clip(CircleShape)
-                                            .drawBehind { drawRect(color) },
+                                            .drawBehind { 
+                                                drawCircle(
+                                                    color = color,
+                                                    radius = size.minDimension / 2f
+                                                )
+                                            },
                                    )

이는 필수 사항은 아니며, 기존 변경사항도 충분히 올바르게 동작합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbbb6c4 and 7eb465a.

📒 Files selected for processing (1)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Compose Stability Check
  • GitHub Check: ci-build
🔇 Additional comments (2)
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (2)

31-31: LGTM! 필요한 import 추가

drawBehind 사용을 위해 필요한 import가 정상적으로 추가되었습니다.


104-104: LGTM! 리컴포지션 최적화 적용 완료

단순 색상 배경을 drawBehind로 교체하여 layout 단계를 건너뛸 수 있게 최적화되었습니다. PR 목표에 부합하는 올바른 변경사항입니다.

shape가 속성의 경우 Modifier.clip으로 빼낼 수 있음

적용 후 이전과 UI가 같은지 확인 필요
@easyhooon easyhooon marked this pull request as draft December 3, 2025 07:47
@easyhooon
Copy link
Copy Markdown
Contributor Author

흠.. drawBehind { drawRect() } 는 아무리 생각해도 .background Modifier에 비해 직관성이 떨어지는거 같네요.
사실 해당 람다 modifier들이 효력을 발휘하는게 애니메이션 등으로 인해 색상, 위치, 크기가 변경될때 composition 부터 재시작하지않고 바로 Layout 또는 drawing 단계부터 시작할 수 있도록 하는것이라 애니메이션이 없는 단순 고정값이나, If else 구문의 경우 의미가 없을 것 같긴합니다.(if else 의 경우 어차피 리컴포지션이 1번은 일어나야함)

따라서 애니메이션이 적용되지 않는 케이스의 경우 background -> drawBehind { drawRect() } 는 다시 background로 롤백하고,
offset이나 scale의 경우는 람다 modifier 적용 후에도 직관성이 나쁘지않다고 생각하므로 적용하도록 하겠습니다.

@easyhooon easyhooon marked this pull request as ready for review December 9, 2025 07:56
Copy link
Copy Markdown

@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: 0

🧹 Nitpick comments (9)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/RecordProgressBar.kt (1)

27-34: 변수 추출의 리컴포지션 최적화 효과가 제한적입니다.

bgColor를 로컬 변수로 추출한 것은 코드가 정상적으로 동작하지만, 이 변경이 실제로 리컴포지션 최적화에 도움이 되는지 재고가 필요합니다:

  • 이 변경은 람다 기반 Modifier(drawBehind, offset { }, graphicsLayers { })를 적용한 것이 아니라 단순히 조건식을 변수로 추출한 것입니다
  • currentStep이 변경되면 repeat 블록 전체가 리컴포지션되므로, 색상 계산을 변수로 추출해도 composition 단계를 건너뛸 수 없습니다
  • PR 설명의 코멘트에서 작성자께서 직접 언급하신 것처럼, "애니메이션이 적용되지 않는 단순 고정값이나 if/else 분기는 람다 Modifier 적용의 이점이 적음"에 해당하는 케이스입니다

성능상 측정 가능한 이점이 없다면, 기존의 인라인 조건식이 더 간결하고 직관적일 수 있습니다:

Box(
    modifier = Modifier
        .weight(1f)
        .height(6.dp)
        .clip(RoundedCornerShape(ReedTheme.radius.full))
        .background(
            if (index <= currentStep.ordinal) {
                ReedTheme.colors.bgPrimary
            } else {
                ReedTheme.colors.bgDisabled
            }
        ),
)

참고: .clip() 분리는 shape와 background를 명확히 구분하여 적절해 보입니다.

feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/component/BookRegisterBottomSheet.kt (1)

131-138: 색상 변수 추출이 리컴포지션 최적화에 기여하지 않음

bgColortextColor를 변수로 추출한 것은 코드 가독성 측면에서는 약간 개선이지만, PR의 핵심 목표인 리컴포지션 최적화에는 도움이 되지 않습니다.

이유:

  • selected 파라미터가 변경되면 BookStatusItem composable 전체가 리컴포지션됩니다
  • 리컴포지션 시점에 bgColortextColor가 매번 재계산됩니다
  • .background(bgColor)는 여전히 값 기반 modifier라서 composition 단계에서 평가됩니다
  • 람다 기반 modifier (offset { }, graphicsLayers { })와 달리, composition 단계를 건너뛰는 효과가 없습니다

PR 작성자의 코멘트에 따르면:

애니메이션이 없는 케이스에서는 background → drawBehind { drawRect() } 변경을 롤백하고 원래의 background 사용 권장

이 결정은 타당하나, 변수 추출만으로는 최적화 효과가 없으므로 다음을 고려해보세요:

  1. 단순성을 위해 inline 조건문으로 되돌리기:
.background(if (selected) ReedTheme.colors.bgTertiary else ReedTheme.colors.bgSecondary)
  1. 또는 변수 추출을 유지하되, 이것이 가독성 개선이지 성능 최적화가 아님을 인지

Also applies to: 151-151

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt (1)

63-66: scaleX = 1f 생략 가능 (선택적 리팩토링)

scaleX = 1f는 기본값이므로 명시하지 않아도 됩니다. 다만 다른 아이콘들과의 일관성을 위해 명시적으로 작성하신 것으로 보이며, 이는 가독성 측면에서 장점이 있을 수 있습니다.

간결함을 선호하신다면 아래와 같이 수정 가능합니다:

 .graphicsLayer {
-    scaleX = 1f
     scaleY = -1f
 }
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/SentenceBox.kt (1)

35-41: SentenceBox에서 RoundedCornerShape 재사용으로 중복 줄이기 제안

clip(RoundedCornerShape(ReedTheme.radius.sm))border(..., shape = RoundedCornerShape(ReedTheme.radius.sm))에서 같은 shape를 두 번 생성하고 있어서, 로컬 변수로 뽑아두면 가독성과 재사용성이 조금 더 좋아질 것 같습니다.

-    Box(
-        modifier = modifier
-            .fillMaxWidth()
-            .clip(RoundedCornerShape(ReedTheme.radius.sm))
-            .background(bgColor)
-            .border(
-                width = 1.dp,
-                color = borderColor,
-                shape = RoundedCornerShape(ReedTheme.radius.sm),
-            )
+    val shape = RoundedCornerShape(ReedTheme.radius.sm)
+
+    Box(
+        modifier = modifier
+            .fillMaxWidth()
+            .clip(shape)
+            .background(bgColor)
+            .border(
+                width = 1.dp,
+                color = borderColor,
+                shape = shape,
+            )
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/component/ReviewItem.kt (1)

33-41: ReviewItem 카드에서도 shape 상수로 통일하면 가독성 향상

RoundedCornerShape(ReedTheme.radius.md)를 clip과 border 양쪽에서 동일하게 쓰고 있어서, 로컬 shape로 빼두면 의도가 더 명확해질 것 같습니다.

-    Box(
-        modifier = modifier
-            .fillMaxWidth()
-            .clip(RoundedCornerShape(ReedTheme.radius.md))
-            .background(color = ReedTheme.colors.baseSecondary)
+    val shape = RoundedCornerShape(ReedTheme.radius.md)
+
+    Box(
+        modifier = modifier
+            .fillMaxWidth()
+            .clip(shape)
+            .background(color = ReedTheme.colors.baseSecondary)
             .padding(
                 horizontal = ReedTheme.spacing.spacing4,
                 vertical = ReedTheme.spacing.spacing4,
             ),
-            .border(
-                border = if (isError) errorBorderStroke else borderStroke,
-                shape = cornerShape,
-            )
+            .border(
+                border = if (isError) errorBorderStroke else borderStroke,
+                shape = shape,
+            )

(위 border 쪽 diff는 예시용이며, 실제 라인 위치에 맞게 조정하면 됩니다.)

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (1)

130-145: EmotionItem clip + background 패턴 및 shape 재사용 제안

clip(RoundedCornerShape(ReedTheme.radius.md))background(color = ReedTheme.colors.bgTertiary)border(shape = RoundedCornerShape(...)) 순서로 카드가 잘 정리돼서, Emotion 이미지/내용까지 모서리가 라운드 처리되는 형태입니다. 현재 디자인이 이런 모서리 클리핑을 기대하는 구조라면 동작은 자연스러워 보입니다.

다만 여기서도 동일한 shape를 두 번 만들고 있으니, 아래처럼 로컬 상수로 빼두면 재사용과 의도 전달에 도움이 될 것 같습니다.

-    Box(
-        modifier = modifier
-            .height(214.dp)
-            .clip(RoundedCornerShape(ReedTheme.radius.md))
-            .background(color = ReedTheme.colors.bgTertiary)
+    val cardShape = RoundedCornerShape(ReedTheme.radius.md)
+
+    Box(
+        modifier = modifier
+            .height(214.dp)
+            .clip(cardShape)
+            .background(color = ReedTheme.colors.bgTertiary)
             .then(
                 if (isSelected) Modifier.border(
                     width = ReedTheme.border.border15,
                     color = ReedTheme.colors.borderBrand,
-                    shape = RoundedCornerShape(ReedTheme.radius.md),
+                    shape = cardShape,
                 )
                 else Modifier,
             )

실기기에서 Emotion 이미지의 모서리 표현이 기존 디자인과 동일한지만 한 번 눈으로 확인해 주시면 좋겠습니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/ImpressionGuideBox.kt (1)

36-45: ImpressionGuideBox에서도 RoundedCornerShape 상수 추출 제안

여기도 RoundedCornerShape(ReedTheme.radius.sm)clipborder에서 중복 생성하고 있어서, 공통 shape 변수로 빼두면 코드가 좀 더 읽기 쉬울 것 같습니다.

-    Box(
-        modifier = modifier
-            .fillMaxWidth()
-            .clip(RoundedCornerShape(ReedTheme.radius.sm))
-            .background(bgColor)
-            .border(
-                width = 1.dp,
-                color = borderColor,
-                shape = RoundedCornerShape(ReedTheme.radius.sm),
-            )
+    val shape = RoundedCornerShape(ReedTheme.radius.sm)
+
+    Box(
+        modifier = modifier
+            .fillMaxWidth()
+            .clip(shape)
+            .background(bgColor)
+            .border(
+                width = 1.dp,
+                color = borderColor,
+                shape = shape,
+            )
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/component/QuoteItem.kt (1)

24-32: QuoteItem 카드도 shape 재사용으로 일관성 강화

QuoteItem 컨테이너도 다른 컴포넌트와 동일하게 clip + background 패턴으로 정리된 점 좋습니다. 여기에서도 RoundedCornerShape(ReedTheme.radius.md)를 로컬 상수로 빼두면 의미가 더 드러날 것 같습니다.

-    Box(
-        modifier = modifier
-            .fillMaxWidth()
-            .clip(RoundedCornerShape(ReedTheme.radius.md))
-            .background(color = ReedTheme.colors.baseSecondary)
+    val shape = RoundedCornerShape(ReedTheme.radius.md)
+
+    Box(
+        modifier = modifier
+            .fillMaxWidth()
+            .clip(shape)
+            .background(color = ReedTheme.colors.baseSecondary)
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/BookCard.kt (1)

65-66: 기술적으로 올바른 리팩토링이지만, 정적 값에서는 원래 방식도 유효합니다.

shape를 clip으로 분리하고 background에 color 파라미터를 명시한 변경은 기술적으로 정확하며, 시각적으로도 동일한 결과를 생성합니다.

다만 PR 코멘트에서 언급하신 것처럼, 애니메이션이 없는 정적 색상값의 경우 리컴포지션 최적화 이점이 제한적입니다. 이 경우 원래의 .background(color = ReedTheme.colors.basePrimary, shape = RoundedCornerShape(ReedTheme.radius.sm)) 방식이 더 간결하고 동일한 성능을 제공할 수 있습니다.

변경사항을 유지하신다면, PR 설명에 명시된 대로 UI 동일성 확인이 필요합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7eb465a and 41f3684.

📒 Files selected for processing (31)
  • core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/RecordProgressBar.kt (1 hunks)
  • core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/checkbox/CircleCheckBox.kt (2 hunks)
  • core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/checkbox/SquareCheckBox.kt (2 hunks)
  • core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/textfield/ReedRecordTextField.kt (2 hunks)
  • core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/textfield/ReedSearchTextField.kt (2 hunks)
  • core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/InfinityLazyColumn.kt (2 hunks)
  • core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedDialog.kt (2 hunks)
  • core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedTopAppBar.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/BookUpdateBottomSheet.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/component/QuoteItem.kt (2 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/component/ReviewItem.kt (1 hunks)
  • feature/edit/src/main/kotlin/com/ninecraft/booket/feature/edit/emotion/EmotionEditUi.kt (1 hunks)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (1 hunks)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/BookCard.kt (3 hunks)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/HomeHeader.kt (1 hunks)
  • feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/FilterChip.kt (1 hunks)
  • feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/LibraryHeader.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt (3 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/ImpressionGuideBox.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/OcrUi.kt (3 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt (4 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/SentenceBox.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (2 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt (1 hunks)
  • feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/component/MainBottomBar.kt (1 hunks)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/component/BookRegisterBottomSheet.kt (3 hunks)
  • feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt (1 hunks)
  • feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/ReedSwitch.kt (2 hunks)
  • feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/notification/NotificationUi.kt (2 hunks)
  • feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/osslicenses/OssLicensesUi.kt (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/HomeHeader.kt
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/OcrUi.kt
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/CustomTooltipBox.kt
  • feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/ReedSwitch.kt
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-28T18:08:47.298Z
Learnt from: seoyoon513
Repo: YAPP-Github/Reed-Android PR: 72
File: feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt:21-82
Timestamp: 2025-07-28T18:08:47.298Z
Learning: Jetpack Compose에서 scale() 변환은 시각적 변환만 적용하며 레이아웃 좌표계는 변경하지 않는다. 따라서 scale(scaleX = -1f, scaleY = -1f)로 반전된 아이콘에서 padding()은 원래 레이아웃 기준으로 동작하므로, 시각적으로 올바른 위치를 위해서는 변환 전 좌표계 기준으로 padding을 설정해야 한다.

Applied to files:

  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt
📚 Learning: 2025-08-28T12:25:54.058Z
Learnt from: easyhooon
Repo: YAPP-Github/Reed-Android PR: 174
File: feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt:128-133
Timestamp: 2025-08-28T12:25:54.058Z
Learning: In BookSearchPresenter.kt, when a guest user tries to register a book and is redirected to login, the bottom sheet (isBookRegisterBottomSheetVisible) and selection state (selectedBookIsbn, selectedBookStatus) are intentionally kept open/preserved so that when the user returns from login, they can continue from where they left off without losing context.

Applied to files:

  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/BookUpdateBottomSheet.kt
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/component/BookRegisterBottomSheet.kt
📚 Learning: 2025-07-31T23:17:40.054Z
Learnt from: easyhooon
Repo: YAPP-Github/Reed-Android PR: 88
File: feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordItem.kt:29-37
Timestamp: 2025-07-31T23:17:40.054Z
Learning: Reed-Android 프로젝트에서는 API가 준비되지 않은 상황에서 UI를 먼저 구현하고, API 연동 시점에 하드코딩된 데이터를 실제 데이터로 교체하는 개발 방식을 사용한다. RecordItem 컴포넌트의 emotionTags 매개변수도 API 연동 시점에 `text = emotionTags.joinToString(separator = "·") { "#$it" }`로 적용될 예정이다.

Applied to files:

  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ci-build
  • GitHub Check: Compose Stability Check
🔇 Additional comments (24)
feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/LibraryHeader.kt (1)

31-35: backgroundcolor 인자를 명시한 변경, 가독성과 일관성 측면에서 좋습니다.

기능 변경 없이 명시적 파라미터만 추가되어 기존 동작은 그대로 유지되면서, 다른 배경 관련 코드들과의 스타일 일관성도 좋아진 것 같습니다.

feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt (1)

74-74: 명시적 파라미터 사용으로 가독성 개선

color 파라미터를 명시적으로 지정하여 코드의 의도가 더 명확해졌습니다. 정적인 배경색 케이스이므로 .background()를 유지한 것도 적절한 판단입니다.

feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/component/MainBottomBar.kt (1)

68-68: LGTM! 코드 일관성 개선

named parameter를 사용하여 명시성을 높인 변경입니다. PR 코멘트에서 언급하신 대로, 애니메이션이 적용되지 않는 정적 배경색의 경우 .background를 유지하는 것이 직관성 측면에서 더 좋은 선택입니다. 이 변경은 코드베이스 전반의 일관성을 개선하면서도 가독성을 해치지 않습니다.

feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/osslicenses/OssLicensesUi.kt (3)

28-28: clip import 사용 적절

OssLicenseItem에서 Modifier.clip(...)를 실제로 사용하고 있어 필요한 import입니다. 현재 상태 그대로 두면 될 것 같습니다.


111-116: Circle 인디케이터의 clip + background 전환 LGTM

Box에 자식 컴포저블이 없어서, 기존 background(color, shape = CircleShape)clip(CircleShape).background(color = …)의 실질적인 시각/동작 차이는 없을 것 같습니다. PR에서 진행 중인 “shape는 clip, 색상은 background” 분리 패턴과도 잘 맞습니다.


128-136: URL 배지 Text에 대한 clip + background 전환도 무리 없어 보입니다

Text 자체가 레이아웃 bounds 안에서만 그려지고, 여기서는 단순 배경 + 패딩 조합이라 background(shape = RoundedCornerShape)clip(RoundedCornerShape).background(...) 변경으로 인한 시각/동작 차이는 거의 없을 것으로 보입니다. 디자인 확인만 한 번 해보셨다면 그대로 진행해도 좋겠습니다.

URL이 길어 여러 줄로 감싸지는 케이스에서도 padding/라운드 모양이 의도대로 유지되는지만 실제 기기에서 한 번만 확인 부탁드립니다.

feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/component/FilterChip.kt (1)

41-42: shape 분리는 좋으나, 이 케이스에서는 리컴포지션 최적화 효과가 제한적입니다.

.clip(shape).background(color) 패턴으로 shape와 color를 분리한 것은 단일 책임 원칙 측면에서 코드 구조를 개선합니다. 그러나 chipColorisSelected 상태에 따라 조건부로 계산되므로(라인 34), isSelected 변경 시 어차피 리컴포지션이 발생합니다.

따라서 이 변경은 코드 가독성/구조 개선의 효과는 있지만, PR 목표인 리컴포지션 최적화 효과는 제한적입니다. PR 작성자도 코멘트에서 "애니메이션이 적용되지 않는 단순 고정값이나 if/else 분기는 람다 Modifier 적용의 이점이 적음"이라고 언급하셨습니다.

추가로, .clip이 적용된 후 라인 50-54에서 조건부로 적용되는 .border가 동일한 shape을 사용하는데, clip된 영역에서 border가 의도대로 렌더링되는지 UI 확인이 필요합니다.

다음 사항을 확인해주세요:

  1. 선택되지 않은 상태(isSelected = false)에서 border가 올바르게 표시되는지
  2. clip과 border의 shape이 동일하여 시각적으로 이전과 동일한지
feature/edit/src/main/kotlin/com/ninecraft/booket/feature/edit/emotion/EmotionEditUi.kt (1)

141-142: shape를 clip으로 분리한 리팩토링 패턴이 올바르게 적용되었습니다.

코드 구조 측면에서 변경 사항이 적절합니다:

  • clip(shape).background(color) 패턴으로 shape와 color를 명확히 분리
  • 명시적 named parameter 사용(color =)으로 가독성 향상
  • Modifier 순서가 논리적: clip → background → border (conditional)

다만, PR 설명에서 언급하신 대로 UI 동일성 확인이 필요합니다:

  • 조건부 border(lines 144-148)가 clip 이후에 적용되는 패턴에서 시각적으로 정상 렌더링되는지 확인 필요
  • 특히 isSelected = true일 때 2dp border가 rounded corner와 정확히 정렬되어 표시되는지 검증 권장

참고: 이 변경은 리컴포지션 최적화보다는 구조적 리팩토링에 가깝습니다. PR 코멘트에서 언급하신 것처럼 애니메이션이 없는 경우 drawBehind 적용을 롤백하신 결정과 일관되게, 여기서는 background를 유지하면서 shape 분리만 수행하셨습니다.

feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/component/BookRegisterBottomSheet.kt (1)

38-38: No action needed. The ReedBottomSheet import at line 38 was already present in the previous version and is necessary for the composable to function correctly.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/CameraFrame.kt (1)

46-57: 고정 값에 대한 graphicsLayer 람다 형식 최적화 확인

graphicsLayer 람다는 State/애니메이션과 같은 동적 값에서 리컴포지션을 건너뛰도록 설계되었습니다. 여기서는 scaleX = -1f, scaleY = 1f 등 고정된 정적 값을 사용하므로 이 최적화 이점을 활용하지 못합니다.

추가로 line 64의 scaleX = 1f은 기본값과 동일하므로 생략 가능합니다.

이는 기능 결함은 아니며, 코드 스타일 관점에서의 선택사항입니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt (1)

86-90: 배경 Modifier의 named parameter 변경은 무난합니다

background(White)background(color = White)로 바꿔 의도가 더 명확해졌고, Compose API 관점에서도 동작은 완전히 동일합니다.

feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/notification/NotificationUi.kt (1)

135-148: NotificationGuideItem의 clip → background 체인 변경이 적절합니다

background(shape = …)에서 clip(RoundedCornerShape).background(color = …)로 분리해 다른 컴포넌트와 패턴을 맞췄고, noRippleClickable만 사용하고 자식도 overflow 하지 않아 시각적/동작 변화 없이 모서리 처리만 더 명확해진 수준으로 보입니다.

core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/InfinityLazyColumn.kt (1)

139-145: InfinityLazyColumn 프리뷰 카드의 모서리 처리 변경도 안전합니다

샘플 카드에 clip(RoundedCornerShape).background(color = …)를 적용해 다른 UI들과 동일 패턴을 사용하고 있고, 자식 뷰가 없어 clip에 따른 부작용 없이 프리뷰의 시각적 품질만 좋아진 변경입니다.

core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedDialog.kt (1)

45-51: ReedDialog 컨테이너에 clip 분리 적용이 잘 되어 있습니다

background(shape = …) 대신 clip(RoundedCornerShape).background(color = …)로 변경해 모서리 적용을 명확히 했고, 자식이 영역을 벗어나지 않는 구조라 레이아웃/동작 변화 없이 ripple 등이 모서리 안쪽으로 자연스럽게 잘리는 효과만 얻을 수 있을 것 같습니다.

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/checkbox/SquareCheckBox.kt (1)

37-45: SquareCheckBox의 모서리·배경 처리 리팩터링이 적절합니다

24dp 박스에 clip(RoundedCornerShape(ReedTheme.radius.xs))background(bgColor)를 적용하고, border도 동일 shape를 써서 체크/언체크 상태 모두 기존과 동일한 외형을 유지하면서 코드 구조만 더 일관성 있게 정리되었습니다.

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/textfield/ReedSearchTextField.kt (1)

79-91: 검색 텍스트 필드의 cornerShape 처리 리팩터링이 잘 되어 있습니다

modifier.clip(cornerShape).background(backgroundColor).then(border…)로 정리해 모서리·배경·테두리 역할이 분리되어 읽기 쉬워졌고, 기본적인 RoundedCornerShape 기준으로는 기존과 동일하게 렌더링될 것 같습니다. 혹시 비대칭 cornerShape를 넘겨 쓰는 곳이 있다면, 해당 케이스만 미리보기로 한 번 확인해 두시면 좋겠습니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt (1)

75-80: QuoteStep의 배경 Modifier도 named parameter로 통일된 점 좋습니다

background(color = White)로 변경해 ImpressionStep 등 다른 화면과 스타일을 맞췄고, Compose API 상 의미 변화 없이 가독성만 개선된 변경입니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/BookUpdateBottomSheet.kt (1)

134-149: BookStatusItem의 배경 색 계산을 변수로 분리한 점이 좋습니다

selected 여부에 따른 배경색을 bgColor로 추출해 표현해서 상태별 스타일이 한눈에 들어오고, .clip(...).background(bgColor).selectable(...) 체인도 기존과 동작을 유지하면서 읽기 쉬워졌습니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (1)

50-54: EmotionStep 루트 배경 named 파라미터 변경 👍

background(White)background(color = White)로 바뀌면서 가독성만 좋아지고, 동작 변화는 없어서 그대로 괜찮아 보입니다.

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/textfield/ReedRecordTextField.kt (1)

83-89: ReedRecordTextField에서 clip → background → border 순서 정리 좋습니다

데코레이터 Row

  • clip(cornerShape)
  • background(backgroundColor)
  • border(..., shape = cornerShape)

순서로 적용한 덕분에, 텍스트/플레이스홀더/배경/보더가 모두 동일한 라운드 모양을 공유하게 되어 시각적으로 자연스럽습니다. 기존 설정값들과도 잘 맞아서 그대로 가져가도 무리 없어 보입니다.

core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedTopAppBar.kt (1)

40-47: ReedTopAppBar 배경 색 분기 로컬 변수화 적절

if (isDark) Neutral950 else WhitebgColor 로컬 변수로 분리해서 background(bgColor)로 사용하는 패턴은 가독성이 좋아지고, 동일 로직을 재사용해야 할 때도 유리해서 괜찮아 보입니다.

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/checkbox/CircleCheckBox.kt (1)

37-43: CircleCheckBox의 clip + background 패턴 정리 👍

background(bgColor, shape = CircleShape)에서

  • clip(CircleShape)
  • background(bgColor)
  • border(..., CircleShape)

조합으로 바꾼 것은, 전체 컨테이너를 원형으로 클리핑하면서 보더와도 일관된 형태를 가지게 해줘서 좋습니다. 동작 변화도 없거나 매우 미미한 수준이라 그대로 괜찮아 보입니다.

feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/component/BookCard.kt (2)

148-149: 동일한 패턴이 일관되게 적용되었습니다.

이 영역에도 동일한 리팩토링 패턴(clip → background 분리)이 적용되었습니다. 기술적으로 정확하며, 파일 전체에서 일관성 있게 적용된 점은 좋습니다.

다만 이 Row도 정적 색상값을 사용하므로, 기록 횟수가 변경되어도 리컴포지션 최적화 이점은 크지 않을 수 있습니다. 일관성을 위해 현재 변경사항을 유지하는 것도 합리적입니다.


216-217: 파일 전체에 일관된 패턴이 적용되었습니다.

EmptyBookCard에도 동일한 리팩토링 패턴이 적용되어 파일 내 모든 카드 컴포넌트가 일관된 구조를 갖추게 되었습니다. 구현이 기술적으로 정확하며, 시각적 결과도 동일해야 합니다.

Copy link
Copy Markdown

@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: 0

🧹 Nitpick comments (1)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/ImpressionGuideBox.kt (1)

40-41: clip + background 패턴 변경이 PR 목표와 일치하는지 재검토가 필요합니다.

background(color, shape)clip(shape).background(color) 패턴으로 변경했지만, 두 방식은 내부적으로 거의 동일하게 동작합니다. 이 변경은 PR의 원래 목표인 람다 기반 Modifier 적용(예: offset { }, graphicsLayer { })과는 다른 방향의 리팩토링입니다.

또한 bgColorisSelected 상태에 따라 변경되므로, 상태 변경 시 어차피 리컴포지션이 발생합니다. PR 코멘트에서 언급하신 대로 애니메이션이 없는 경우 람다 기반 Modifier의 이점이 제한적이므로, 이 변경이 실질적인 성능 향상을 가져오는지 확인이 필요합니다.

기존 background(color = bgColor, shape = cornerShape) 패턴도 충분히 명확하고 관용적인 방식입니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41f3684 and f428b99.

📒 Files selected for processing (3)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/ImpressionGuideBox.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/SentenceBox.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/ocr/component/SentenceBox.kt
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Compose Stability Check
  • GitHub Check: ci-build
🔇 Additional comments (2)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/component/ImpressionGuideBox.kt (2)

35-35: shape 객체 재사용은 좋은 개선입니다.

cornerShape을 로컬 변수로 추출하여 clipborder에서 재사용함으로써 불필요한 RoundedCornerShape 객체 생성을 방지하고 코드 일관성을 높였습니다.


45-45: border에도 동일한 cornerShape 재사용은 적절합니다.

clip과 border에서 동일한 cornerShape 변수를 사용하여 일관성을 유지하고 중복 객체 생성을 방지했습니다.

.offset(
x = (-10).dp,
)
.offset {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

첨부해주신 레퍼런스 잘 봤습니다!
람다 내부 값 변경으로 수정하면 Layout 단계부터 재실행!(Composition 스킵 가능)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

https://angrypodo.tistory.com/10

Modifier 교체 방식과 값 자체를 람다 함수를 통헤 지연 읽기 방법도 존재하는데, 이를 적용하기 위해선 수정해야할 곳들이 많아질것같아 이후에 보이면 그때그때 개선해보도록 하겠습다~

.graphicsLayer {
scaleX = -1f
scaleY = 1f
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2.4 Modifier.graphicsLayer{}
Recommended when applying transformations:
Modifier.graphicsLayer {
rotationZ = rotation
alpha = opacity
}
Changes to rotation or opacity do not trigger composition.

시각 변환 사용 시 graphicsLayer 사용 권장 (Copmosition/Layout 스킵) 메모

@seoyoon513
Copy link
Copy Markdown
Contributor

애니메이션이 없는 단순 고정값이나, If else 구문의 경우 의미가 없을 것 같긴합니다.(if else 의 경우 어차피 리컴포지션이 1번은 일어나야함)

동의합니다!

@easyhooon easyhooon merged commit 194d574 into develop Dec 18, 2025
7 checks passed
@easyhooon easyhooon deleted the BOOK-473-refactor/#229 branch December 18, 2025 05:04
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.

[BOOK-473/refactor] 리컴포지션 최적화를 위한 람다 기반 Modifier 적용

2 participants