feat: 앱내 전반적인 화면들에 대해 verticalScroll 적용하여 height가 작은 기기들 대응#130
feat: 앱내 전반적인 화면들에 대해 verticalScroll 적용하여 height가 작은 기기들 대응#130
Conversation
Walkthrough여러 UI 컴포저블에서 스크롤 지원 및 레이아웃 개선이 이루어졌습니다. spacing7(28.dp) 값이 디자인 시스템에 추가되었고, 이를 활용해 일부 간격이 조정되었습니다. 일부 화면에서는 버튼 추가/삭제, 레이아웃 구조 변경, 스크롤 기능이 도입되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant HomeScreen
participant UIColumn
User->>HomeScreen: 화면 진입
HomeScreen->>UIColumn: verticalScroll 적용된 Column 생성
UIColumn->>User: 스크롤 가능한 전체 Home 화면 제공
sequenceDiagram
participant User
participant EmotionStep
participant NextButton
User->>EmotionStep: 감정 선택/입력
EmotionStep->>NextButton: 상태에 따라 활성화
User->>NextButton: 클릭 시 OnNextButtonClick 이벤트 발생
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~18 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Poem
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (7)
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.kt (3)
66-72: 접근성/현지화: startIconDescription 하드코딩 문자열 사용 지양
"Close Icon"대신stringResource로 교체해 현지화와 접근성을 보장해 주세요. 리소스가 없다면 추가가 필요합니다.예:
startIconDescription = stringResource(R.string.review_detail_close_icon_desc)필요시 strings.xml 항목 추가 PR 패치 제안드릴게요.
104-113: 접근성/현지화: 이미지 contentDescription 하드코딩
"Book CoverImage"도 stringResource로 교체 권장합니다. 빈 문자열이 아닌 의미 있는 설명을 제공하거나, 장식 이미지라면 null 처리하여 스크린리더 제외를 고려하세요.예:
contentDescription = stringResource(R.string.review_detail_book_cover_desc) // 또는 장식용: contentDescription = null
161-164: scroll 컨테이너 내부에서의fillMaxSize제거 권장
verticalScroll내부 자식 Column에fillMaxSize()를 주면 불필요한 빈 공간 생성/측정 오버헤드가 발생할 수 있습니다. 콘텐츠 크기만큼 렌더하도록 변경을 권장합니다.-Column( - modifier = Modifier - .fillMaxSize() - .padding(horizontal = ReedTheme.spacing.spacing5), -) { +Column( + modifier = Modifier + .padding(horizontal = ReedTheme.spacing.spacing5), +) {feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (1)
110-115: verticalScroll 적용 위치 확인: Header/Banner를 스크롤에 포함할지 결정 필요현재는 HomeHeader/HomeBanner는 고정되고, 그 아래 HomeContent만 스크롤됩니다. 작은 높이 기기에서 Header+Banner가 차지하는 높이 때문에 본문 영역이 과도하게 압축되지 않는지 확인 부탁드립니다. 만약 홈 전체가 스크롤되어야 한다면
HomeUi의 상단 Column(내부padding(innerPadding)까지 적용된 곳)에verticalScroll(rememberScrollState())를 주는 방식이 더 안전합니다.대안(개념 예시):
Column( modifier = Modifier .fillMaxSize() .background(HomeBg) .padding(innerPadding) .verticalScroll(rememberScrollState()), ) { HomeHeader(...) HomeBanner(...) HomeContent(...) }feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt (1)
5-5: Next 버튼 제거 방향성 OK — 각 Step로 책임 이관 확인만 부탁드립니다
- Step(QUOTE/EMOTION/IMPRESSION) 내부에서
OnNextButtonClick과state.isNextButtonEnabled반영이 일관되게 처리되는지 확인 부탁드립니다.- 상위에서는 스크롤을 두지 않았으니, 각 Step에서 작은 높이 기기에서도 스크롤이 충분히 가능하도록
verticalScroll또는 스크롤 가능한 컴포넌트를 적용했는지 점검이 필요합니다.필요하시면 Step별 체크리스트/테스트 케이스 정리 도와드릴게요.
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt (1)
115-128: IME 가려짐 대응 누락입력 필드가 있는 화면이므로 키보드 등장 시 하단 “다음” 버튼이 가려질 수 있습니다.
modifier체인에.imePadding()을 추가해 IME 높이만큼 패딩을 주는 방식을 권장드립니다.feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt (1)
127-129:Spacer(weight)사용 위치 재검토
verticalScroll이 붙은Column내부의Spacer(weight = 1f)는 의미가 없어 버튼이 실질적으로 상단에 붙을 수 있습니다. 상단-스크롤 / 하단-버튼 2-영역 구조로 재구성하는 것을 권장드립니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Spacing.kt(1 hunks)feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt(1 hunks)feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.kt(2 hunks)feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt(3 hunks)feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt(1 hunks)feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt(4 hunks)feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt(4 hunks)feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt(3 hunks)feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt(3 hunks)
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#88
File: feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordsCollection.kt:25-59
Timestamp: 2025-07-31T23:22:02.816Z
Learning: BookDetailScreen의 RecordsCollection 컴포넌트는 상위 Column의 verticalScroll과 LazyColumn의 무한 스크롤을 동시에 지원해야 하는 중첩 스크롤 시나리오입니다. LazyColumn에 고정 높이를 설정하지 않으면 앱이 충돌하는 이슈가 있어서, 현재는 높이를 계산하여 설정하고 userScrollEnabled = false로 구현되어 있습니다. 향후 InfiniteLazyColumn과 nestedScrollConnection을 도입하여 전체 화면 스크롤 + LazyColumn 무한 스크롤을 지원할 예정입니다.
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#45
File: core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/appbar/ReedTopAppBar.kt:65-65
Timestamp: 2025-07-12T01:33:57.101Z
Learning: Reed Android 프로젝트에서 타이포그래피 사용 규칙: 톱 앱바(Top App Bar)에서는 `headline2SemiBold`를 사용하고, 바텀시트(Bottom Sheet)에서는 `heading2SemiBold`를 사용한다. 이는 의도적인 디자인 시스템 차별화이다.
📚 Learning: 2025-07-20T12:34:23.786Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#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/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.ktfeature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
📚 Learning: 2025-07-31T23:22:02.816Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#88
File: feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordsCollection.kt:25-59
Timestamp: 2025-07-31T23:22:02.816Z
Learning: BookDetailScreen의 RecordsCollection 컴포넌트는 상위 Column의 verticalScroll과 LazyColumn의 무한 스크롤을 동시에 지원해야 하는 중첩 스크롤 시나리오입니다. LazyColumn에 고정 높이를 설정하지 않으면 앱이 충돌하는 이슈가 있어서, 현재는 높이를 계산하여 설정하고 userScrollEnabled = false로 구현되어 있습니다. 향후 InfiniteLazyColumn과 nestedScrollConnection을 도입하여 전체 화면 스크롤 + LazyColumn 무한 스크롤을 지원할 예정입니다.
Applied to files:
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.ktfeature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.ktfeature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.ktfeature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.kt
📚 Learning: 2025-07-28T18:08:47.298Z
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#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/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.ktfeature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.ktfeature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.kt
📚 Learning: 2025-07-29T07:02:18.885Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#77
File: feature/onboarding/src/main/kotlin/com/ninecraft/booket/feature/onboarding/OnboardingUi.kt:73-73
Timestamp: 2025-07-29T07:02:18.885Z
Learning: Kotlin에서 같은 패키지 내의 파일들은 패키지 레벨에 정의된 const val 상수를 import 없이 직접 접근할 수 있습니다. OnboardingPresenter.kt와 OnboardingUi.kt 모두 com.ninecraft.booket.feature.onboarding 패키지에 속해 있어서 ONBOARDING_STEPS_COUNT 상수를 공유할 수 있습니다.
Applied to files:
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.ktfeature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt
📚 Learning: 2025-07-31T23:17:40.054Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#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/ImpressionStep.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.ktfeature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt
📚 Learning: 2025-07-31T23:30:37.547Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#88
File: feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailPresenter.kt:18-47
Timestamp: 2025-07-31T23:30:37.547Z
Learning: In Circuit architecture, presenters receive the Screen object directly as a constructor parameter (e.g., Assisted private val screen: RecordDetailScreen), and screen parameters are accessed through this screen object (e.g., screen.recordId). Screen parameters should not be added as separate constructor parameters.
Applied to files:
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt
📚 Learning: 2025-07-16T15:54:19.322Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegatingNavigator.kt:0-0
Timestamp: 2025-07-16T15:54:19.322Z
Learning: In the Reed-Android project using Circuit architecture, DelegatingNavigator was restored because NavigableCircuitContent can only inject a single navigator, but the dual-navigator architecture (childNavigator for bottom navigation screens, rootNavigator for full-screen screens) requires a delegating component to work within Circuit's constraint.
Applied to files:
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt
📚 Learning: 2025-07-31T16:58:59.404Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#88
File: core/model/src/main/kotlin/com/ninecraft/booket/core/model/EmotionModel.kt:11-18
Timestamp: 2025-07-31T16:58:59.404Z
Learning: Reed-Android 프로젝트에서 core:model 모듈은 순수 Kotlin 모듈이므로 Android 리소스(R.string 등)에 접근할 수 없다.
Applied to files:
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt
📚 Learning: 2025-07-17T23:41:33.929Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#55
File: core/designsystem/src/main/res/drawable/ic_x_circle.xml:6-11
Timestamp: 2025-07-17T23:41:33.929Z
Learning: Reed Android 프로젝트에서는 SVG에서 vector drawable로 변환시 색상 매핑 대신 모드별 별도 아이콘 파일을 사용하는 방식을 선호한다. Figma에서 SVG export한 형태를 그대로 사용하며, 다크모드 대응이 필요할 경우 drawable-night 폴더에 별도 아이콘을 배치하는 방식을 사용한다.
Applied to files:
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt
📚 Learning: 2025-07-09T01:14:29.836Z
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#35
File: feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/TermsAgreementScreen.kt:127-127
Timestamp: 2025-07-09T01:14:29.836Z
Learning: In the Reed-Android project's TermsAgreementScreen.kt, the OnTermDetailClick event is intentionally passed an empty string for the URL parameter because the actual URLs for terms detail pages haven't been decided yet. This is a temporary implementation that will be updated once the URLs are finalized.
Applied to files:
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt
📚 Learning: 2025-07-12T01:33:57.101Z
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#45
File: core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/appbar/ReedTopAppBar.kt:65-65
Timestamp: 2025-07-12T01:33:57.101Z
Learning: Reed Android 프로젝트에서 타이포그래피 사용 규칙: 톱 앱바(Top App Bar)에서는 `headline2SemiBold`를 사용하고, 바텀시트(Bottom Sheet)에서는 `heading2SemiBold`를 사용한다. 이는 의도적인 디자인 시스템 차별화이다.
Applied to files:
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt
🧬 Code Graph Analysis (2)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt (1)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ReedButton.kt (1)
ReedButton(34-114)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (1)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ReedButton.kt (1)
ReedButton(34-114)
⏰ 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). (1)
- GitHub Check: ci-build
🔇 Additional comments (4)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Spacing.kt (1)
17-17: spacing7(28.dp) 코드 안전성 검증 완료ReedSpacing은 Theme.kt의 LocalSpacing(staticCompositionLocalOf)로만 기본 생성되어, 직접 인스턴스화나
.copy(…)호출을 전혀 발견되지 않았습니다.
따라서 equals/hashCode/copy 서명 변경에 따른 코드 영향은 없습니다.– 디자인 토큰(Spacing.kt의
spacing7)은 Figma 및 디자인 문서에도 함께 업데이트해 주세요.feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt (1)
168-169: 하드코딩 dp 제거하고 spacing 토큰 사용 — 좋습니다디자인 토큰 일관성/테마 교체 용이성이 개선되었습니다.
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt (1)
172-173: 인디케이터 하단 여백을 spacing7로 통일 — 좋습니다토큰 기반 간격으로 일관성이 좋아졌습니다.
feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUi.kt (1)
68-73: 스크롤 적용은 좋으나 TopAppBar까지 스크롤되는 점 확인 필요
Column전체에verticalScroll을 부여하면서ReedBackTopAppBar까지 함께 스크롤됩니다. 일반적으로 설정 화면의 상단 앱바는 고정되는 편이 많으니 UX 의도에 맞는지 한 번 더 확인해주세요. 문제가 없다면 그대로 유지하셔도 됩니다.
| Column( | ||
| modifier = modifier | ||
| .fillMaxSize() | ||
| .padding(innerPadding) | ||
| .verticalScroll(rememberScrollState()), | ||
| ) { | ||
| ReedTopAppBar( | ||
| title = stringResource(R.string.review_detail_title), | ||
| startIconRes = designR.drawable.ic_close, | ||
| startIconDescription = "Close Icon", | ||
| startIconOnClick = { | ||
| state.eventSink(RecordDetailUiEvent.OnCloseClicked) | ||
| }, | ||
| ) | ||
| ReviewDetailContent(state = state) | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
verticalScroll 적용은 타당. 다만 내부에서 외부 modifier 재사용 지양 + AppBar 스크롤 여부 확인 필요
- 내부 Column에서
modifier = modifier를 재사용하면 상위에서 전달된 semantics/testTag/클릭 영역 등이 두 번 적용될 수 있습니다. 내부 노드에는Modifier를 사용하세요. - 현재 TopAppBar가 스크롤과 함께 사라집니다. 의도된 UX인지 확인 부탁드립니다. 고정 상단을 원하면 Scaffold의 topBar 슬롯으로 이동하는 편이 안전합니다.
권장 수정:
- Column(
- modifier = modifier
+ Column(
+ modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.verticalScroll(rememberScrollState()),
) {
ReedTopAppBar(
title = stringResource(R.string.review_detail_title),
startIconRes = designR.drawable.ic_close,
startIconDescription = "Close Icon",
startIconOnClick = {
state.eventSink(RecordDetailUiEvent.OnCloseClicked)
},
)
ReviewDetailContent(state = state)
}만약 AppBar를 고정하려면(대안 예시):
ReedScaffold(
modifier = modifier.fillMaxSize(),
containerColor = White,
topBar = {
ReedTopAppBar(
title = stringResource(R.string.review_detail_title),
startIconRes = designR.drawable.ic_close,
startIconDescription = stringResource(R.string.review_detail_close_icon_desc),
startIconOnClick = { state.eventSink(RecordDetailUiEvent.OnCloseClicked) },
)
},
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.verticalScroll(rememberScrollState()),
) {
ReviewDetailContent(state = state)
}
}
---
🏁 Script executed:
```shell
#!/bin/bash
# 1. Show RecordDetailUi signature and parameters
rg "fun RecordDetailUi" -A3 feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.kt
# 2. List occurrences of stringResource(R.string.review_detail) in the repo
rg "stringResource.*review_detail" -n .
# 3. Check available review_detail string resources
rg "review_detail" -n feature/detail/src/main/res
Length of output: 1167
🏁 Script executed:
# 4. Confirm if any Composables in this module reuse 'modifier' for nested scrollables
rg "verticalScroll" -n feature/detail/src/main/kotlinLength of output: 349
🏁 Script executed:
# 5. Find definitions of R.string.review_detail_close_icon_desc
rg "review_detail_close_icon_desc" -n .Length of output: 39
🏁 Script executed:
# 6. Show nearby R.string entries in res/values/strings.xml
sed -n '1,200p' feature/detail/src/main/res/values/strings.xml | rg "review_detail"Length of output: 262
🏁 Script executed:
# 7. Inspect usage of ReedTopAppBar elsewhere for startIconDescription parameter
rg "ReedTopAppBar" -n featureLength of output: 306
🏁 Script executed:
# 8. Verify if other components place AppBar in topBar slot of Scaffold
rg "Scaffold.*topBar" -n featureLength of output: 34
🏁 Script executed:
# 9. Check RecordDetailContent Composable for nested scrolling strategy
rg "ReviewDetailContent" -A3 -n feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.ktLength of output: 319
🏁 Script executed:
# 10. Show imports to ensure correct import for Modifier
sed -n '1,20p' feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.ktLength of output: 1072
🏁 Script executed:
# 11. Locate top-level @Composable annotation in the file
rg "@Composable" -n feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.ktLength of output: 157
수정 요청: Column modifier 재사용 제거, AppBar 스크롤 의도 확인 및 접근성 문자열 리소스 추가
다음 사항을 반영해 주세요.
- Column에서 외부로 전달된
modifier를 그대로 재사용할 경우 semantics/testTag/클릭 처리 등이 중복 적용될 수 있습니다. 내부 레이아웃에는Modifier를 사용해 주세요. - 현재
ReedTopAppBar가 스크롤 시 사라지는데, UX 의도가 맞는지 확인 부탁드립니다. AppBar를 고정하고 싶다면Scaffold의topBar슬롯으로 옮기는 것이 안전합니다. startIconDescription에 하드코딩된"Close Icon"대신 string 리소스를 사용하세요. 현재review_detail_close_icon_desc가 정의되어 있지 않으므로strings.xml에 리소스 추가가 필요합니다.
권장 변경 예시:
Column(
- modifier = modifier
+ modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.verticalScroll(rememberScrollState()),
) {
ReedTopAppBar(
title = stringResource(R.string.review_detail_title),
startIconRes = designR.drawable.ic_close,
- startIconDescription = "Close Icon",
+ startIconDescription = stringResource(R.string.review_detail_close_icon_desc),
startIconOnClick = {
state.eventSink(RecordDetailUiEvent.OnCloseClicked)
},
)feature/detail/src/main/res/values/strings.xml에 아래 리소스를 추가해 주세요:
<string name="review_detail_close_icon_desc">닫기</string>🤖 Prompt for AI Agents
In
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/record/RecordDetailUi.kt
around lines 59 to 74, avoid reusing the external modifier passed into the
Column to prevent duplicate semantics, testTag, or click handlers; instead, use
a fresh Modifier instance for the internal layout. Confirm if the current
behavior of ReedTopAppBar disappearing on scroll is intended; if the AppBar
should remain fixed, move it to the Scaffold's topBar slot. Replace the
hardcoded startIconDescription string "Close Icon" with a string resource by
adding <string name="review_detail_close_icon_desc">닫기</string> to
feature/detail/src/main/res/values/strings.xml and referencing it in the code.
| ReedButton( | ||
| onClick = { | ||
| state.eventSink(RecordRegisterUiEvent.OnNextButtonClick) | ||
| }, | ||
| colorStyle = ReedButtonColorStyle.PRIMARY, | ||
| sizeStyle = largeButtonStyle, | ||
| modifier = Modifier.fillMaxWidth(), | ||
| enabled = state.isNextButtonEnabled, | ||
| text = stringResource(R.string.record_next_button), | ||
| multipleEventsCutterEnabled = state.currentStep == RecordStep.IMPRESSION, | ||
| ) |
There was a problem hiding this comment.
multipleEventsCutterEnabled 조건이 잘못되었습니다
현재 값:
multipleEventsCutterEnabled = state.currentStep == RecordStep.IMPRESSIONEmotionStep이라면 RecordStep.EMOTION이 맞습니다. 잘못된 조건으로 디바운스가 비활성화되어 중복 클릭이 발생할 수 있습니다.
- multipleEventsCutterEnabled = state.currentStep == RecordStep.IMPRESSION,
+ multipleEventsCutterEnabled = state.currentStep == RecordStep.EMOTION,🤖 Prompt for AI Agents
In
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
between lines 98 and 108, the multipleEventsCutterEnabled property is
incorrectly set to activate only when the current step is RecordStep.IMPRESSION.
Change this condition to check if state.currentStep equals RecordStep.EMOTION to
correctly enable the debounce and prevent duplicate clicks during the Emotion
step.
| ReedButton( | ||
| onClick = { | ||
| state.eventSink(RecordRegisterUiEvent.OnNextButtonClick) | ||
| }, | ||
| colorStyle = ReedButtonColorStyle.PRIMARY, | ||
| sizeStyle = largeButtonStyle, | ||
| modifier = Modifier.fillMaxWidth(), | ||
| enabled = state.isNextButtonEnabled, | ||
| text = stringResource(R.string.record_next_button), | ||
| multipleEventsCutterEnabled = state.currentStep == RecordStep.IMPRESSION, | ||
| ) |
There was a problem hiding this comment.
이중 클릭 방지 플래그가 단계와 불일치합니다
QuoteStep에서도 RecordStep.IMPRESSION를 사용하고 있어 디바운스가 꺼집니다. RecordStep.QUOTE(혹은 해당 단계 enum)로 수정해주세요.
- multipleEventsCutterEnabled = state.currentStep == RecordStep.IMPRESSION,
+ multipleEventsCutterEnabled = state.currentStep == RecordStep.QUOTE,🤖 Prompt for AI Agents
In
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt
around lines 129 to 139, the multiple click prevention flag is incorrectly tied
to RecordStep.IMPRESSION, causing debounce to be disabled in the QuoteStep.
Update the multipleEventsCutterEnabled condition to check for RecordStep.QUOTE
(or the appropriate enum for the QuoteStep) instead of RecordStep.IMPRESSION to
correctly enable debounce for this step.
| } | ||
| } | ||
| Spacer(modifier = Modifier.weight(1f)) | ||
| Spacer(modifier = Modifier.height(108.dp)) |
There was a problem hiding this comment.
height 108.dp 들어간 이유가 잇을까요?
There was a problem hiding this comment.
height 108.dp 들어간 이유가 잇을까요?
verticalScroll이 적용되어 weight가 적용되지않아 하단의 최소한의 padding 영역을 설정해둔것인데, 버튼이 항상 화면 하단에 보일수 있게 sticky footer형식으로 만드는게 좋을것같네여
There was a problem hiding this comment.
저는 QuoteStep, ImpressionStep에서 height=108.dp를 제거해도 버튼이 바닥에 잘 붙어잇어요! -> 길이가 짧아지니까 버튼이 붙는군요
There was a problem hiding this comment.
@seoyoon513 버튼을 하단에 고정되도록 배치해서 height가 작은 화면에 대해서도 대응했고, 버튼 아래로 컴포넌트가 겹쳐져 보이지않는것을 방지하기 위해 버튼 height + padding 만큼 LazyColumn 하단에 padding을 추가했습니다!
| } | ||
|
|
||
| val emotionPairs = state.emotionTags.chunked(2) | ||
| items(emotionPairs) { pair -> |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (1)
113-114: multipleEventsCutterEnabled 조건이 잘못되었습니다 (EMOTION 단계여야 합니다).EmotionStep에서는
RecordStep.EMOTION을 확인해야 합니다. 현재 설정으로는 디바운스가 비활성화되어 다중 탭이 발생할 수 있습니다.- multipleEventsCutterEnabled = state.currentStep == RecordStep.IMPRESSION, + multipleEventsCutterEnabled = state.currentStep == RecordStep.EMOTION,
🧹 Nitpick comments (2)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (2)
76-78: items에 key를 지정해 재구성 안정성을 높이세요. (+ 미미한 성능: chunked 결과 remember)키 미지정 시 항목 재정렬/변경에서 상태가 흔들릴 수 있습니다. Enum 이름 기반 키를 권장합니다. 또한
chunked(2)결과는 상태 변경 시에만 갱신되면 충분하므로 remember를 사용할 수 있습니다.- val emotionPairs = state.emotionTags.chunked(2) - items(emotionPairs) { pair -> + val emotionPairs = remember(state.emotionTags) { state.emotionTags.chunked(2) } + items( + items = emotionPairs, + key = { pair -> pair.joinToString("|") { it.name } }, + ) { pair ->외부 변경(필요한 import):
import androidx.compose.runtime.remember
146-151: a11y/i18n: Image의 contentDescription은 하드코딩된 영문 대신 적절히 처리 필요지금은
"Emotion Image"로 고정되어 있어 접근성/현지화에 부적절합니다. 이 이미지는 장식용이라면null로 설정하여 보조기기의 중복 낭독을 피하세요. 만약 라벨 역할을 해야 한다면 로컬라이즈된 감정명으로 대체하십시오.Image( painter = painterResource(emotionTag.graphic), - contentDescription = "Emotion Image", + contentDescription = null, modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop, )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt(4 hunks)feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt(3 hunks)feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/QuoteStep.kt
- feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/ImpressionStep.kt
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#88
File: feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordsCollection.kt:25-59
Timestamp: 2025-07-31T23:22:02.816Z
Learning: BookDetailScreen의 RecordsCollection 컴포넌트는 상위 Column의 verticalScroll과 LazyColumn의 무한 스크롤을 동시에 지원해야 하는 중첩 스크롤 시나리오입니다. LazyColumn에 고정 높이를 설정하지 않으면 앱이 충돌하는 이슈가 있어서, 현재는 높이를 계산하여 설정하고 userScrollEnabled = false로 구현되어 있습니다. 향후 InfiniteLazyColumn과 nestedScrollConnection을 도입하여 전체 화면 스크롤 + LazyColumn 무한 스크롤을 지원할 예정입니다.
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#45
File: core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/appbar/ReedTopAppBar.kt:65-65
Timestamp: 2025-07-12T01:33:57.101Z
Learning: Reed Android 프로젝트에서 타이포그래피 사용 규칙: 톱 앱바(Top App Bar)에서는 `headline2SemiBold`를 사용하고, 바텀시트(Bottom Sheet)에서는 `heading2SemiBold`를 사용한다. 이는 의도적인 디자인 시스템 차별화이다.
📚 Learning: 2025-07-31T23:17:40.054Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#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
📚 Learning: 2025-07-28T18:08:47.298Z
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#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
📚 Learning: 2025-07-20T12:34:23.786Z
Learnt from: easyhooon
PR: YAPP-Github/Reed-Android#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/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
🧬 Code Graph Analysis (1)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (1)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ReedButton.kt (1)
ReedButton(34-114)
⏰ 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). (1)
- GitHub Check: ci-build
| LazyColumn( | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .padding(horizontal = ReedTheme.spacing.spacing5), | ||
| ) { |
There was a problem hiding this comment.
하단 고정 버튼과 콘텐츠가 겹칠 수 있습니다 — LazyColumn에 bottom contentPadding을 추가하세요.
현재 LazyColumn은 가로 padding만 적용되어 있어 마지막 행이 하단 고정 버튼 뒤에 가려질 수 있습니다(특히 화면 높이가 작은 기기). 아래처럼 bottom contentPadding을 추가해 겹침을 방지해 주세요. 버튼의 실제 높이에 맞춰 값은 조정 가능하며, 우선 spacing10 + spacing4 정도로 시작해보는 것을 권장합니다.
- LazyColumn(
- modifier = Modifier
- .fillMaxSize()
- .padding(horizontal = ReedTheme.spacing.spacing5),
- ) {
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(horizontal = ReedTheme.spacing.spacing5),
+ contentPadding = PaddingValues(
+ bottom = ReedTheme.spacing.spacing10 + ReedTheme.spacing.spacing4
+ ),
+ ) {외부 변경(필요한 import):
import androidx.compose.foundation.layout.PaddingValues🤖 Prompt for AI Agents
In
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
around lines 50 to 54, the LazyColumn only has horizontal padding, causing the
last item to potentially be obscured by the fixed bottom button. Fix this by
adding bottom contentPadding to the LazyColumn using PaddingValues, setting the
bottom padding to approximately spacing10 plus spacing4 from ReedTheme.spacing
to prevent overlap with the button.
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .align(Alignment.BottomCenter) | ||
| .padding(horizontal = ReedTheme.spacing.spacing5) | ||
| .padding(bottom = ReedTheme.spacing.spacing4), | ||
| enabled = state.isNextButtonEnabled, |
There was a problem hiding this comment.
🛠️ Refactor suggestion
IME/네비게이션 바 인셋 미반영 — 버튼에 인셋 패딩을 추가하세요.
키보드가 올라오거나 제스처 내비게이션 사용 시 버튼이 가려질 수 있습니다. 아래처럼 인셋 패딩을 부여하세요.
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
+ .navigationBarsPadding()
+ .imePadding()
.padding(horizontal = ReedTheme.spacing.spacing5)
.padding(bottom = ReedTheme.spacing.spacing4),외부 변경(필요한 import):
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding🤖 Prompt for AI Agents
In
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt
around lines 106 to 111, the button modifier lacks padding to account for IME
and navigation bar insets, causing it to be obscured when the keyboard is
visible or gesture navigation is used. Fix this by adding imePadding() and
navigationBarsPadding() to the modifier chain after the existing padding calls.
Also, ensure to import androidx.compose.foundation.layout.imePadding and
androidx.compose.foundation.layout.navigationBarsPadding.
height가 작을 경우 버튼 영역으로 컴포넌트가 겹쳐 패딩을 추가하여 스크롤하여 버튼 위로 올라올 수 있도록
| Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing10)) | ||
| } | ||
|
|
||
| val emotionPairs = state.emotionTags.chunked(2) |
There was a problem hiding this comment.
이거는 remember 안하면 매번 리컴포지션마다 O(N) 연산이 반복되고, 새로운 List 인스턴스 생성이 빈번할 거 같아요. remember 하는 건 어떨까요?
There was a problem hiding this comment.
좋은 지적 감사함니다! 바로 적용해야겠네요
🔗 관련 이슈
📙 작업 설명
🧪 테스트 내역 (선택)
📸 스크린샷 또는 시연 영상 (선택)
verticalScroll1.mp4
verticalScroll2.mp4
💬 추가 설명 or 리뷰 포인트 (선택)
Summary by CodeRabbit
신규 기능
UI 개선
버그 수정
기타