Skip to content

[feat/#32] card-history implement#38

Merged
cmj7271 merged 2 commits intodevelopfrom
feat/#32-card-history
Jan 15, 2026
Merged

[feat/#32] card-history implement#38
cmj7271 merged 2 commits intodevelopfrom
feat/#32-card-history

Conversation

@cmj7271
Copy link
Copy Markdown
Contributor

@cmj7271 cmj7271 commented Jan 14, 2026

Related issue 🛠️

Work Description ✏️

  • HistoryCardHistory 컴포넌트 구현

Screenshot 📸

스크린샷
스크린샷 2026-01-15 오전 4 29 44

Uncompleted Tasks 😅

  • [ ]

To Reviewers 📢

Summary by CodeRabbit

릴리스 노트

  • New Features
    • 히스토리 엔트리를 표시하는 새로운 카드 컴포넌트 추가
    • 두 가지 크기 변형(소형, 대형) 지원으로 다양한 레이아웃에 대응
    • 아티스트명, 제목, 썸네일 이미지 및 참여자 상태 정보 표시 기능 구현

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 14, 2026

📝 Walkthrough

Walkthrough

새로운 HistoryCardItem 컴포저블이 추가되었습니다. 두 가지 크기(SMALL, LARGE)를 지원하는 CardHistorySize enum, 각 크기별 텍스트 스타일을 제공하는 extension properties, 그리고 클릭 상호작용과 누른 상태 피드백을 처리하는 카드 컴포넌트가 구현되었습니다.

Changes

코호트 / 파일(s) 변경 사항
새 카드 컴포넌트 추가
app/src/main/java/com/poti/android/presentation/history/component/HistoryCardItem.kt
CardHistorySize enum (SMALL, LARGE)과 artistStyle, titleStyle extension properties 추가. HistoryCardItem 컴포저블이 AsyncImage, 텍스트, ParticipantStateLabel, 아이콘을 포함하는 클릭 가능한 카드 구현. MutableInteractionSource와 collectIsPressedAsState를 활용하여 누른 상태 시각 피드백 처리. 크기별 조건부 패딩, 텍스트 스타일, 스페이서 적용.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • doyeon0307
  • jyvnee

추가 검토 사항

Modern Android Development 권장사항 기준으로 몇 가지 확인해주시면 좋을 것 같습니다:

  • Compose Best Practices: remember { MutableInteractionSource() } 기본값이 매번 새 인스턴스를 생성하는 것은 의도한 설계인지 확인 부탁드립니다. 일반적으로 stateless 컴포저블을 선호하는 추세입니다.
  • 성능 고려: AsyncImage 로딩 중 placeholder 또는 fallback 처리가 구현되어 있는지 확인 부탁드립니다.
  • 접근성(Accessibility): 카드의 누른 상태가 시각적으로만 표현되는지, semantics를 통한 상태 전달이 필요한지 검토 부탁드립니다.
  • ParticipantStateLabel 통합: 관련 PR #30과의 호환성과 상태 라벨의 렌더링 방식이 명확한지 확인해주시면 좋겠습니다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 구현한 주요 변경사항을 명확하게 반영하고 있으며, card-history 컴포넌트 구현이라는 핵심 내용을 잘 전달합니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 있으며, 관련 이슈(#32), 작업 내용, 스크린샷, 완료되지 않은 작업 항목을 모두 포함하고 있습니다.
Linked Issues check ✅ Passed CardHistorySize enum을 통한 lg, sm 타입 구분과 MutableInteractionSource를 활용한 pressed 상태 구현이 모두 완료되어 이슈 #32의 요구사항을 충족합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 card-history 컴포넌트 구현이라는 범위 내에 있으며, participant-state 의존성을 적절히 활용한 예상 범위의 변경입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
app/src/main/java/com/poti/android/presentation/history/component/HistoryCardItem.kt (3)

64-66: remember를 기본 매개변수에서 사용하는 것은 권장되지 않습니다.

remember { MutableInteractionSource() }를 기본 매개변수로 사용하면 예기치 않은 recomposition 동작이 발생할 수 있습니다. Modern Android Development 권장 사항에 따르면, 함수 본문 내에서 remember를 처리하는 것이 더 안전합니다.

♻️ 권장 수정 방안
 `@Composable`
 fun HistoryCardItem(
     sizeType: CardHistorySize,
     imageUrl: String,
     artist: String,
     title: String,
     participantStageType: ParticipantStateLabelStage,
     participantStatusType: ParticipantStateLabelStatus,
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
-    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    interactionSource: MutableInteractionSource? = null,
 ) {
-    val isPressed by interactionSource.collectIsPressedAsState()
+    val actualInteractionSource = interactionSource ?: remember { MutableInteractionSource() }
+    val isPressed by actualInteractionSource.collectIsPressedAsState()

그리고 이후 interactionSource 사용 부분을 actualInteractionSource로 변경해주세요.


73-82: 하드코딩된 dimension 값들은 Dimens 리소스로 추출을 고려해주세요.

코딩 가이드라인에 따르면, 12.dp, 8.dp 등의 하드코딩된 크기 값들은 Dimens 리소스로 관리하는 것이 권장됩니다. 이렇게 하면 디자인 시스템 일관성 유지와 추후 수정이 용이해집니다.


94-136: 사이즈별 간격 값들을 extension property로 추출하면 가독성이 향상됩니다.

현재 sizeType에 따른 조건문이 여러 곳에 분산되어 있습니다. artistStyle, titleStyle처럼 extension property로 추출하면 코드가 더 깔끔해지고 유지보수가 쉬워집니다.

♻️ 예시
val CardHistorySize.verticalPadding: Dp
    get() = when (this) {
        CardHistorySize.SMALL -> 2.dp
        CardHistorySize.LARGE -> 4.dp
    }

val CardHistorySize.bottomSpacerHeight: Dp
    get() = when (this) {
        CardHistorySize.SMALL -> 12.dp
        CardHistorySize.LARGE -> 22.dp
    }

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4528c4 and e306f05.

📒 Files selected for processing (1)
  • app/src/main/java/com/poti/android/presentation/history/component/HistoryCardItem.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: 코드를 리뷰할 때 다음 Kotlin 및 Jetpack Compose 모범 사례를 중점적으로 확인:

  1. Jetpack Compose 성능 및 UI 최적화:

    • Recomposition 방지: 불필요한 리컴포지션을 유발하는 코드를 지적해줘. 특히 LazyColumn 등 리스트에서 key 파라미터가 누락되었는지 확인해줘.
    • 스마트한 계산: 계산 비용이 높은 로직은 rememberderivedStateOf로 감싸져 있는지 확인해줘.
    • 안정성(Stability): List나 일반 클래스를 State로 사용할 때, 불필요한 리컴포지션을 막기 위해 @Immutable이나 @Stable 어노테이션 사용을 제안해줘.
    • Modifier 규칙: Modifier는 항상 컴포저블 함수의 첫 번째 선택적 파라미터로 받아야 하며, 재사용성을 위해 외부에서 주입받아야 해.
    • 리소스 사용: 하드코딩된 값(색상, 크기, 문자열) 대신 Theme, Dimens, strings.xml 리소스를 사용하는지 체크해줘.
    • 접근성 예외: Icon이나 Image 컴포저블의 contentDescriptionnull인 경우는 장식용(Decorative) 이미지로 간주하고 지적하지 마.
  2. MVI (Model-View-Intent) 아키텍처 및 상태 관리:

    • 단방향 데이터 흐름(UDF): UI는 상태를 직접 변경할 수 없고, 반드시 Intent(또는 Event)를 통해 ViewModel로 요청을 보내야 해.
    • 불변 상태(Immutable State): UiState는 반드시 data class + val 프로퍼티로 구성되어야 하며, 상태 업데이트 시 .copy()를 사용해야 해.
    • Side Effect 분리: 네비게이션, Toast 같은 일회성 이벤트는 UiState가 아닌 Channel이나 SharedFlow로 처리하여 화면 회전 시 재발생하지 않도록 해야 해.
    • 안전한 수집: UI에서 Flow 수집 시 collectAsStateWithLifecycle()을 사용하여 생명주기를 준수하는지 확인해줘.
    • 상태 노출: ViewModel 내부에서 StateFlowSharedFlow를 올바르게 노출하고 있는지 확인해줘.
    • 호이스팅(Hoisting): 상태나 UI 이벤트 처리가 적절하게 호이스팅되었는지 확인해줘. UI 로직과 비즈니스 로직을 분리하고, UI가 로직을 직접 수행하지 않도록 확인해줘.
  3. Clean Architecture (Dependency Rule) 준수:

    • Domain 순수성: Domain 레이어(domain 패키지)는 절대로 안드로이드 의존성(android.*, R 클래스 등)을 가져서는 안 돼. 순수 Kotlin 코드인지 엄격히 확인해줘.
    • 데이터 노출 금지: Data 레이어의 DTO(@Entity, @SerializedName)가 UI나 Domain 레이어로 바로 노출되면 안 돼. 반드시 Mapper를 통해 변환했는지 확인해줘.
    • 계층 간 의존성: UI -> Domain <- Data 방향이 올바른지, UI가 Data 레이어를 직접 참조하고 있진 않은지 감시해줘.
  4. Kotlin & Coroutines 안전성:

    • Scope 사용: GlobalScope 사용을 금지하고, viewModelScopelifecycleScope 사용을 권장해줘.
    • Dispatcher 주입: Dispatchers.IO 등을 하드코딩하지 말고, 테스트 용이성을 위해 생성자를 통해 주입(Injection)받도록 제안해줘.
    • 예외 처리: Coroutine 실행 시 runCatching이나 CoroutineExceptionHandler 등을 통해 예외 처리가 누락되지 않았는지 확인해줘.
    • Null-Safety: 불필요한 !! 연산자 사용을 지적...

Files:

  • app/src/main/java/com/poti/android/presentation/history/component/HistoryCardItem.kt
🔇 Additional comments (2)
app/src/main/java/com/poti/android/presentation/history/component/HistoryCardItem.kt (2)

39-54: LGTM!

CardHistorySize enum과 extension property를 통한 스타일 분리가 깔끔하게 구현되어 있습니다. @Composable getter를 사용하여 테마 typography에 접근하는 패턴도 적절합니다.


147-177: LGTM!

Preview가 PotiTheme으로 감싸져 있고, SMALL과 LARGE 두 가지 사이즈 변형을 모두 보여주어 PR 목표에 맞게 잘 구현되어 있습니다.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

@cmj7271 cmj7271 self-assigned this Jan 14, 2026
@cmj7271 cmj7271 requested a review from a team January 14, 2026 19:30
Copy link
Copy Markdown
Contributor

@sonyerim sonyerim left a comment

Choose a reason for hiding this comment

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

컴포 잘쓸게요 ㅎㅎ

Comment on lines +76 to +80
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = onClick,
)
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.

.noRippleClickable(
    interactionSource = interactionSource,
    onClick = onClick,
)

P2: noRippleClickable() 확장함수 적용 가능할 것 같아유

Copy link
Copy Markdown
Contributor

@doyeon0307 doyeon0307 left a comment

Choose a reason for hiding this comment

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

리뷰어 달아저

고생고생 티티

Comment on lines +104 to +108
Text(
text = title,
style = sizeType.titleStyle,
color = colors.black,
)
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.

p1: 여기 maxLines=1 / Elipses(?) 라고 합니다! 제가 디쌤한테 물어봄

Comment on lines +98 to +102
Text(
text = artist,
style = sizeType.artistStyle,
color = colors.gray800,
)
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.

p1: 여기두 maxLines=1 적용해주면 좋을 듯!

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.

  • 혹시 모르니까 Ellipsis도?

color = colors.black,
)

Spacer(modifier = Modifier.height(12.dp))
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.

p1: verticalArrangement = Arrangement.spacedBy(2.dp)가 적용되어 있어, 본 Spacer로 인해 16dp 여백이 생기는 것 같아요!
verticalArrangement = Arrangement.spacedBy(2.dp) 없애주는 편이 좋아보입니당

또한 SMALL/LARGE일 때 여기 여백이 달라요! LARGE일 때는 22dp

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.

P1: 그리고 여기 column에도 위아래 여백 large일 때랑 small일 때 패딩 달라요. large일 때는 위아래 4.dp 패딩인데 small일 때는 위에 2.dp고 아래에 4.dp 임!

Comment on lines +41 to +45
) {
SMALL(imageSize = 81.dp),
LARGE(imageSize = 96.dp),
}

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.

p1: 고정 사이즈가 아닌 것 같은데..!
텍스트 Column에 의해 높이가 결정되고 이미지가 높이를 가득 채우는 구조로 보여용
image

Copy link
Copy Markdown
Contributor

@jyvnee jyvnee left a comment

Choose a reason for hiding this comment

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

코리 반영하고 알려줘~~

color = colors.black,
)

Spacer(modifier = Modifier.height(12.dp))
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.

P1: 그리고 여기 column에도 위아래 여백 large일 때랑 small일 때 패딩 달라요. large일 때는 위아래 4.dp 패딩인데 small일 때는 위에 2.dp고 아래에 4.dp 임!

Comment on lines +130 to +134
val (text, color) = when (state) {
"done" -> "모집 완료" to colors.poti600
"wait" -> "입금 대기" to colors.sementicRed
else -> "상태" to colors.gray800
}
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.

P1: 스트링 추출 해주세요! 그리고 이거 enum class로 빼면 좋을 듯

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.

요고는 임시 컴포넌트인데 필요한 컴포넌트 머지되서 수정할게요

}

@Composable
fun HistoryCardHistory(
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.

P1: 이거 History가 두 번 들어가서 좀 어색한듯?? 그냥 HistoryCard나 HistoryCardItem 어떠신가요

Comment on lines +98 to +102
Text(
text = artist,
style = sizeType.artistStyle,
color = colors.gray800,
)
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.

  • 혹시 모르니까 Ellipsis도?

Copy link
Copy Markdown
Contributor

@doyeon0307 doyeon0307 left a comment

Choose a reason for hiding this comment

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

조아용

Copy link
Copy Markdown
Contributor

@jyvnee jyvnee left a comment

Choose a reason for hiding this comment

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

수고햇서~~

@cmj7271 cmj7271 merged commit 945f047 into develop Jan 15, 2026
2 checks passed
@github-project-automation github-project-automation bot moved this from To-do to Done in POTI-ANDROID Jan 15, 2026
@cmj7271 cmj7271 deleted the feat/#32-card-history branch January 15, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Feat] card-history 컴포넌트 구현

4 participants