[Feat] 프로필 키워드 그래프 컴포넌트 구현#89
Conversation
📝 WalkthroughWalkthrough프로필 취향 키워드 그래프 표시를 위한 도메인 타입과 UI 컴포넌트를 추가합니다. 새로운 sealed class KeywordType과 enum PreferenceType을 정의하고, 색상별 키워드와 진행률을 표시하는 ProfileKeywordGraph 컴포넌트를 구현합니다. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10분 Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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)
✏️ Tip: You can disable this entire section by setting Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
@app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt:
- Around line 26-47: Add a Modifier parameter to the public composable
ProfileKeywordChip (e.g., modifier: Modifier = Modifier) and forward it into the
child composables by passing modifier = modifier to ProfileSmallKeywordChip and
ProfileLargeKeywordChip; ensure you import androidx.compose.ui.Modifier and keep
the modifier as the last parameter with a default value so callers can customize
layout without breaking existing callers.
🧹 Nitpick comments (4)
app/src/main/java/com/flint/core/common/extension/ModifierExt.kt (1)
85-97: 성능 최적화 권장: drawable 및 Rect 캐싱 고려현재 구현은 매 draw 호출마다
ContextCompat.getDrawable()을 호출하고 새로운Rect객체를 생성합니다.composed모디파이어 패턴을 사용하면 drawable을 캐싱할 수 있습니다.♻️ 성능 개선 제안
-fun Modifier.draw9Patch( +fun Modifier.draw9Patch( context: Context, @DrawableRes ninePatchRes: Int, -) = this.drawBehind { - drawIntoCanvas { - ContextCompat.getDrawable(context, ninePatchRes)?.let { ninePatch -> - ninePatch.run { - bounds = Rect(0, 0, size.width.toInt(), size.height.toInt()) - draw(it.nativeCanvas) - } - } +) = composed { + val drawable = remember(ninePatchRes) { + ContextCompat.getDrawable(context, ninePatchRes) + } + drawBehind { + drawIntoCanvas { canvas -> + drawable?.apply { + bounds = Rect(0, 0, size.width.toInt(), size.height.toInt()) + draw(canvas.nativeCanvas) + } + } } }app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordGraph.kt (1)
27-71: LGTM! 구조가 잘 구성되어 있습니다.컴포넌트 구조와 레이아웃이 깔끔합니다. 다만,
percent파라미터에 대한 범위 검증을 추가하면 더 안전합니다. 현재 0 미만이나 100 초과 값이 전달되면 예기치 않은 UI가 표시될 수 있습니다.💡 Optional: percent 범위 검증
@Composable fun ProfileKeywordGraph( keyword: String, preferenceType: PreferenceType, percent: Int, modifier: Modifier = Modifier, ) { + val safePercent = percent.coerceIn(0, 100) Row( horizontalArrangement = Arrangement.SpaceBetween, modifier = modifier, ) { // ... ProfileKeywordProgressBar( preferenceType = preferenceType, - percent = percent.toFloat() / 100, + percent = safePercent.toFloat() / 100, modifier = Modifier.width(160.dp), ) Text( - text = "${percent}%", + text = "${safePercent}%", // ... ) // ... } }app/src/main/java/com/flint/domain/type/PreferenceType.kt (1)
1-40: 아키텍처 고려사항: 도메인 레이어에 UI 의존성 포함
domain패키지에Color(Compose UI)와DrawableRes(Android 리소스)가 포함되어 있습니다. Clean Architecture 관점에서 도메인 레이어는 순수 Kotlin으로 유지하는 것이 권장됩니다.현재 프로젝트 규모에서는 수용 가능할 수 있으나, 향후 확장성을 위해 presentation 레이어로 이동하거나 도메인과 UI 타입을 분리하는 것을 고려해볼 수 있습니다.
프로젝트의 아키텍처 방향성에 따라 결정해 주세요. 현재 구조를 유지해도 기능상 문제는 없습니다.
app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt (1)
70-102: 빈 imageUrl 처리 고려
imageUrl이 빈 문자열일 때도NetworkImage가 렌더링되어 회색 placeholder가 표시됩니다. 의도된 동작이 아니라면 조건부 렌더링을 고려해 보세요.💡 조건부 이미지 렌더링
Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center, ) { - NetworkImage( - imageUrl = imageUrl, - contentDescription = null, - modifier = Modifier.size(20.dp), - ) - Spacer(modifier = Modifier.width(12.dp)) + if (imageUrl.isNotBlank()) { + NetworkImage( + imageUrl = imageUrl, + contentDescription = null, + modifier = Modifier.size(20.dp), + ) + Spacer(modifier = Modifier.width(12.dp)) + } Text( text = keyword, // ... ) }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
app/src/main/res/drawable/bg_tag_blue.9.pngis excluded by!**/*.pngapp/src/main/res/drawable/bg_tag_gray.9.pngis excluded by!**/*.pngapp/src/main/res/drawable/bg_tag_green.9.pngis excluded by!**/*.pngapp/src/main/res/drawable/bg_tag_orange.9.pngis excluded by!**/*.pngapp/src/main/res/drawable/bg_tag_pink.9.pngis excluded by!**/*.pngapp/src/main/res/drawable/bg_tag_yellow.9.pngis excluded by!**/*.png
📒 Files selected for processing (4)
app/src/main/java/com/flint/core/common/extension/ModifierExt.ktapp/src/main/java/com/flint/domain/type/PreferenceType.ktapp/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.ktapp/src/main/java/com/flint/presentation/profile/component/ProfileKeywordGraph.kt
🧰 Additional context used
🧬 Code graph analysis (2)
app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordGraph.kt (1)
app/src/main/java/com/flint/core/designsystem/theme/Theme.kt (1)
FlintTheme(8-16)
app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt (2)
app/src/main/java/com/flint/core/designsystem/component/image/NetworkImage.kt (1)
NetworkImage(22-46)app/src/main/java/com/flint/core/designsystem/theme/Theme.kt (1)
FlintTheme(8-16)
⏰ 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: PR Build Check
- GitHub Check: PR Lint Check
🔇 Additional comments (1)
app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordGraph.kt (1)
73-95: LGTM!프로그레스 바 구현이 깔끔합니다.
fillMaxWidth(percent)를 사용한 진행률 표시와RoundedCornerShape적용이 적절합니다.
| @Composable | ||
| fun ProfileKeywordChip( | ||
| keyword: String, | ||
| keywordType: KeywordType, | ||
| keywordImageUrl: String = "", | ||
| ) { | ||
| when (keywordType) { | ||
| is KeywordType.Small -> { | ||
| ProfileSmallKeywordChip( | ||
| keyword = keyword, | ||
| ) | ||
| } | ||
|
|
||
| is KeywordType.Large -> { | ||
| ProfileLargeKeywordChip( | ||
| keyword = keyword, | ||
| keywordType = keywordType, | ||
| imageUrl = keywordImageUrl, | ||
| ) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Public 컴포저블에 Modifier 파라미터 추가 권장
Compose 컨벤션에 따라 public 컴포저블은 modifier 파라미터를 받아 호출자가 레이아웃을 커스터마이징할 수 있도록 해야 합니다.
♻️ Modifier 파라미터 추가
@Composable
fun ProfileKeywordChip(
keyword: String,
keywordType: KeywordType,
keywordImageUrl: String = "",
+ modifier: Modifier = Modifier,
) {
when (keywordType) {
is KeywordType.Small -> {
ProfileSmallKeywordChip(
keyword = keyword,
+ modifier = modifier,
)
}
is KeywordType.Large -> {
ProfileLargeKeywordChip(
keyword = keyword,
keywordType = keywordType,
imageUrl = keywordImageUrl,
+ modifier = modifier,
)
}
}
}🤖 Prompt for AI Agents
In
@app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt
around lines 26 - 47, Add a Modifier parameter to the public composable
ProfileKeywordChip (e.g., modifier: Modifier = Modifier) and forward it into the
child composables by passing modifier = modifier to ProfileSmallKeywordChip and
ProfileLargeKeywordChip; ensure you import androidx.compose.ui.Modifier and keep
the modifier as the last parameter with a default value so callers can customize
layout without breaking existing callers.
…eyword-graph-component
📮 관련 이슈
📌 작업 내용
📸 스크린샷
😅 미구현
🫛 To. 리뷰어
Summary by CodeRabbit
릴리스 노트
✏️ Tip: You can customize this high-level summary in your review settings.