feat(widget): 오디오 콘텐츠 카드 컴포넌트를 추가한다
This commit is contained in:
113
docs/prd/20260519_오디오콘텐츠카드컴포넌트_prd.md
Normal file
113
docs/prd/20260519_오디오콘텐츠카드컴포넌트_prd.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# PRD: 오디오 콘텐츠 카드 컴포넌트
|
||||
|
||||
## 1. Overview
|
||||
Figma `20:3800`, `20:3818`, `20:3829` 디자인을 기준으로 XML Views 기반 화면에서 재사용할 수 있는 Audio Content Card Component를 개발한다.
|
||||
|
||||
---
|
||||
|
||||
## 2. Problem
|
||||
- 오디오 콘텐츠 카드가 화면마다 개별 구현되면 썸네일 크기, radius, 텍스트 영역 폭, typography, 말줄임 규칙이 달라질 수 있다.
|
||||
- 제공된 3개 Figma 컴포넌트는 형태는 같고 크기만 다르므로, 별도 컴포넌트로 중복 구현하면 유지보수 비용이 커진다.
|
||||
- RecyclerView, horizontal carousel, grid 등 다양한 콘텐츠 목록에서 같은 데이터 바인딩 계약으로 카드 크기만 바꿔 사용할 수 있어야 한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. Goals
|
||||
- 동일한 구조를 갖는 오디오 콘텐츠 카드의 `large`, `medium`, `small` 크기 변형을 제공한다.
|
||||
- 썸네일은 정사각형, corner radius `14dp`, center crop 기준으로 표시한다.
|
||||
- 제목과 크리에이터명은 한 줄 말줄임 처리하고, 크기별 Figma typography에 맞춘다.
|
||||
- 카드 크기, 썸네일 크기, 텍스트 영역 폭, 텍스트 스타일은 size contract로 한 곳에서 관리한다.
|
||||
- 기존 화면에 일괄 적용하지 않고, 컴포넌트 추가와 사용 계약 문서화에 한정한다.
|
||||
|
||||
---
|
||||
|
||||
## 4. Non-Goals
|
||||
- 이번 범위에서는 series 타입 콘텐츠 카드, ORIGINAL 태그, first 태그, 무료 태그를 구현하지 않는다.
|
||||
- 기존 RecyclerView adapter나 기존 콘텐츠 목록 화면에 신규 카드를 일괄 적용하지 않는다.
|
||||
- 신규 Activity, Fragment, ViewModel을 만들지 않는다.
|
||||
- Compose 컴포넌트 또는 Compose Theme를 추가하지 않는다.
|
||||
- Figma에 없는 그림자, dim overlay, pressed animation, skeleton loading, badge, aspect ratio 변형은 추가하지 않는다.
|
||||
- 이미지 로딩 라이브러리 선택이나 실제 URL 로딩 정책을 컴포넌트 내부에 고정하지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 5. Target Users
|
||||
- XML 레이아웃을 작성하거나 유지보수하는 Android 개발자.
|
||||
- v2 화면에서 오디오 콘텐츠 카드 UI를 리스트/캐러셀/그리드에 재사용하려는 개발자.
|
||||
|
||||
---
|
||||
|
||||
## 6. User Stories
|
||||
- 개발자는 같은 오디오 콘텐츠 카드 형태를 크기만 바꿔 재사용하고 싶다.
|
||||
- 개발자는 화면별 목록 구조에 맞게 `large`, `medium`, `small` 카드 크기를 선택하고 싶다.
|
||||
- 개발자는 썸네일, 콘텐츠 제목, 크리에이터명을 ViewBinding 또는 custom view API로 바인딩하고 싶다.
|
||||
- 개발자는 긴 제목과 크리에이터명이 레이아웃을 밀어내지 않고 한 줄 말줄임되기를 원한다.
|
||||
|
||||
---
|
||||
|
||||
## 7. Core Features
|
||||
|
||||
### Audio Content Card Component
|
||||
Figma 3개 노드의 공통 구조를 하나의 XML + Kotlin custom view 컴포넌트로 제공한다.
|
||||
|
||||
#### Requirements
|
||||
- Figma large: https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=20-3800&m=dev
|
||||
- Figma medium: https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=20-3818&m=dev
|
||||
- Figma small: https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=20-3829&m=dev
|
||||
- 공통 구조: 정사각형 thumbnail + 하단 label contents 영역.
|
||||
- Thumbnail corner radius: `radius_14`.
|
||||
- Thumbnail scale type: `centerCrop`.
|
||||
- Title: `maxLines=1`, `ellipsize=end`, text color white.
|
||||
- Creator name: `maxLines=1`, `ellipsize=end`, text color `gray_500`.
|
||||
- Title과 creator name 사이 gap은 `2dp`로 맞춘다. 기존 `spacing_2` 토큰이 없으므로 구현 단계에서 신규 dimen 추가 또는 XML 직접값 사용 중 하나를 계획에서 명시한다.
|
||||
- Thumbnail과 label 영역 사이 gap은 large는 `11dp`, medium/small은 `spacing_8` 기준으로 맞춘다. 기존 `spacing_11` 토큰이 없으므로 large gap은 구현 단계에서 신규 dimen 추가 또는 XML 직접값 사용 중 하나를 계획에서 명시한다.
|
||||
|
||||
#### Size Variants
|
||||
| Size | Figma node | Card width | Thumbnail | Label width | Title style | Creator style | Thumbnail-label gap |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `large` | `20:3800` | `185dp` | `185dp x 185dp` | `185dp` | `Typography.Heading4` | `Typography.Body5` | `11dp` |
|
||||
| `medium` | `20:3818` | `163dp` | `163dp x 163dp` | `151dp` | `Typography.Heading4` | `Typography.Body5` | `spacing_8` |
|
||||
| `small` | `20:3829` | `122dp` | `122dp x 122dp` | `114dp` | `Typography.Body1` | `Typography.Caption2` | `spacing_8` |
|
||||
|
||||
#### Edge Cases
|
||||
- 제목이 길면 한 줄 말줄임 처리한다.
|
||||
- 크리에이터명이 길면 한 줄 말줄임 처리한다.
|
||||
- 제목 또는 크리에이터명이 비어 있으면 호출부 데이터 문제로 간주하고 컴포넌트는 전달된 값을 그대로 표시한다.
|
||||
- 썸네일 이미지가 없거나 로딩 실패한 경우의 placeholder 정책은 호출부 또는 이미지 로딩 계층에서 결정한다.
|
||||
- size가 지정되지 않으면 `medium`을 기본값으로 사용한다.
|
||||
|
||||
---
|
||||
|
||||
## 8. UX / UI Expectations
|
||||
- 세 크기 모두 같은 카드 구조와 정사각형 썸네일 형태를 유지한다.
|
||||
- 썸네일 radius는 모든 크기에서 14dp로 동일하다.
|
||||
- `large` 카드는 카드 전체 폭과 label 폭을 185dp로 사용한다.
|
||||
- `medium` 카드는 카드 폭 163dp, label 폭 151dp로 사용해 Figma처럼 label이 썸네일보다 좌우 6dp 좁게 배치된다.
|
||||
- `small` 카드는 카드 폭 122dp, label 폭 114dp로 사용해 Figma처럼 label이 썸네일보다 좌우 4dp 좁게 배치된다.
|
||||
- 텍스트는 어두운 배경 위 사용을 전제로 white/`gray_500` 색상 대비를 유지한다.
|
||||
|
||||
---
|
||||
|
||||
## 9. Technical Constraints
|
||||
- 현재 프로젝트는 XML Views + ViewBinding 기반이므로 XML 레이아웃과 Kotlin custom view 패턴을 우선한다.
|
||||
- 신규 Kotlin 코드는 `kr.co.vividnext.sodalive.v2.widget` 패키지 하위에 둔다.
|
||||
- 재사용 레이아웃은 `app/src/main/res/layout` 아래에 둔다.
|
||||
- 색상, spacing, radius, typography는 기존 `colors.xml`, `dimens.xml`, `typography.xml` 토큰을 우선 사용한다.
|
||||
- 기존 `CapsuleTabBarView`처럼 size/state 계약은 순수 Kotlin 객체 또는 enum으로 분리해 단위 테스트 가능하게 한다.
|
||||
- 기존 화면의 동작이나 레이아웃을 요청 없이 변경하지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 10. Metrics
|
||||
- `large`, `medium`, `small` 3개 size variant의 카드 폭, 썸네일 크기, label 폭이 문서와 구현에서 일치한다.
|
||||
- 제목과 크리에이터명은 한 줄 말줄임 처리된다.
|
||||
- size contract 단위 테스트가 통과한다.
|
||||
- Android 리소스 병합 및 디버그 빌드가 성공한다.
|
||||
- 기존 화면 파일은 변경되지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 11. Open Questions
|
||||
- 사용자 응답 없이 진행하므로 3개 Figma 노드는 `audio` 타입 콘텐츠 카드의 크기 변형으로 문서화한다.
|
||||
- Figma generated code에는 태그 옵션이 포함되어 있지만, 제공된 스크린샷과 사용자 설명은 “형태 동일, 크기만 다름”이므로 이번 문서 범위에서는 태그를 제외한다.
|
||||
- `2dp`, `11dp`, `185dp`, `163dp`, `151dp`, `122dp`, `114dp`는 현재 공통 dimen 토큰에 없으므로 구현 계획에서 최소 리소스 추가 여부를 명시한다.
|
||||
Reference in New Issue
Block a user