8.8 KiB
8.8 KiB
PRD: 시리즈 컴포넌트
1. Overview
Figma 20:3875, 20:3887, 20:3906, 20:3914 디자인을 기준으로 Android XML Views 기반 화면에서 재사용할 수 있는 Series Content Card Component와 ORIGINAL series tag를 개발한다.
2. Problem
- 시리즈 콘텐츠 카드는 기존 오디오 콘텐츠 카드와 텍스트 구조는 유사하지만 썸네일이 정사각형이 아니라 세로형 poster ratio다.
- 시리즈 카드가 화면마다 개별 구현되면 poster 크기, radius, label 폭, typography, ORIGINAL 태그 위치가 달라질 수 있다.
- ORIGINAL 태그는 시리즈 카드 위에 overlay로 쓰이고 단독 태그 컴포넌트로도 관리되어야 하므로, 카드와 태그의 계약을 분리해야 한다.
- ORIGINAL tag node는
20:3906이다.
3. Goals
- 동일한 구조를 갖는 시리즈 콘텐츠 카드의
large,small크기 변형을 제공한다. - 썸네일은 Figma 기준 세로형 poster ratio를 유지하고, corner radius
14dp,centerCrop기준으로 표시한다. - 제목과 크리에이터명은 한 줄 말줄임 처리하고, 크기별 Figma typography에 맞춘다.
- ORIGINAL 태그는
ic_series_original아이콘,ORIGINAL텍스트,gray_900배경,24dp높이를 가진 재사용 가능한 tag view 또는 include layout으로 제공한다. - 시리즈 카드에는 ORIGINAL 태그 overlay 표시 여부를 선택할 수 있는 API를 제공한다.
- 기존 오디오 콘텐츠 카드와 기존 화면 일괄 적용은 변경하지 않고, 컴포넌트 추가와 사용 계약 문서화에 한정한다.
4. Non-Goals
- 이번 범위에서는 기존
AudioContentCardView를 시리즈 카드로 리팩터링하거나 통합하지 않는다. - 기존 RecyclerView adapter나 기존 콘텐츠 목록 화면에 신규 시리즈 카드를 일괄 적용하지 않는다.
- 신규 Activity, Fragment, ViewModel을 만들지 않는다.
- Compose 컴포넌트 또는 Compose Theme를 추가하지 않는다.
- Figma에 표시된 하단 유료/무료 태그는 이번 범위에서 구현하지 않는다. 사용자 요청은 ORIGINAL 태그에 한정한다.
- Figma에 없는 그림자, dim overlay 색상, pressed animation, skeleton loading, placeholder 정책은 추가하지 않는다.
- 이미지 로딩 라이브러리 선택이나 실제 URL 로딩 정책을 컴포넌트 내부에 고정하지 않는다.
5. Target Users
- XML 레이아웃을 작성하거나 유지보수하는 Android 개발자.
- v2 화면에서 시리즈 콘텐츠 카드 UI를 리스트/캐러셀/그리드에 재사용하려는 개발자.
6. User Stories
- 개발자는 같은 시리즈 카드 형태를 크기만 바꿔 재사용하고 싶다.
- 개발자는 시리즈 콘텐츠가 ORIGINAL인지 여부에 따라 상단 태그를 표시하고 싶다.
- 개발자는 썸네일, 콘텐츠 제목, 크리에이터명을 ViewBinding 또는 custom view API로 바인딩하고 싶다.
- 개발자는 긴 제목과 크리에이터명이 레이아웃을 밀어내지 않고 한 줄 말줄임되기를 원한다.
7. Core Features
Series Content Card Component
Figma 2개 카드 크기와 ORIGINAL tag 사용 예시를 하나의 XML + Kotlin custom view 컴포넌트로 제공한다.
Figma References
- Series card 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-3875&m=dev
- Series card 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-3887&m=dev
- ORIGINAL tag: 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-3906&m=dev
- ORIGINAL tag usage example: 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-3914&m=dev
Requirements
- 공통 구조: 세로형 thumbnail + 하단 label contents 영역.
- Thumbnail corner radius:
radius_14. - Thumbnail scale type:
centerCrop. - Thumbnail과 label 영역 사이 gap은
spacing_8기준으로 맞춘다. - Title:
maxLines=1,ellipsize=end, text color white. - Creator name:
maxLines=1,ellipsize=end, text colorgray_500. - Title과 creator name 사이 gap은
2dp로 맞춘다. 기존spacing_2토큰이 없으므로 구현 단계에서 XML 직접값 또는 컴포넌트 내부 상수로 처리한다. - ORIGINAL 태그는 thumbnail 좌상단에 붙고, 태그 container는 thumbnail radius와 충돌하지 않도록 우하단 corner radius
8dp를 가진다. - ORIGINAL 태그는
ic_series_original아이콘을 사용한다.
Size Variants
| Size | Figma node | Card width | Thumbnail | Label width | Title style | Creator style | Thumbnail-label gap |
|---|---|---|---|---|---|---|---|
large |
20:3875 |
163dp |
163dp x 230dp |
151dp |
Typography.Heading4 |
Typography.Body5 |
spacing_8 |
small |
20:3887 |
122dp |
122dp x 172dp |
114dp |
Typography.Body1 |
Typography.Caption2 |
spacing_8 |
ORIGINAL Tag Contract
| Property | Value |
|---|---|
| Figma node | 20:3906 |
| Width | 101dp |
| Height | 24dp |
| Background | gray_900 (#202020) |
| Icon | ic_series_original, 14dp x 14dp, left 8dp, vertically centered |
| Text | ORIGINAL, white, Phosphate Solid style if available |
| Text fallback | 프로젝트에 Phosphate font가 없으면 이미지/폰트 자산 추가 여부를 확인하고, 없을 때는 기존 font 리소스 중 가장 가까운 bold 스타일을 사용한다 |
| Text position | left 26dp, top 2dp 기준 |
| Overlay position | thumbnail top-left |
| Overlay corner | bottomEnd radius 8dp |
Edge Cases
- 제목이 길면 한 줄 말줄임 처리한다.
- 크리에이터명이 길면 한 줄 말줄임 처리한다.
- 제목 또는 크리에이터명이 비어 있으면 호출부 데이터 문제로 간주하고 컴포넌트는 전달된 값을 그대로 표시한다.
- 썸네일 이미지가 없거나 로딩 실패한 경우의 placeholder 정책은 호출부 또는 이미지 로딩 계층에서 결정한다.
- size가 지정되지 않으면
large를 기본값으로 사용한다. - ORIGINAL 여부가 false이면 태그 영역은
gone처리되어 thumbnail만 표시된다.
8. UX / UI Expectations
- 두 크기 모두 같은 카드 구조와 세로형 poster thumbnail 형태를 유지한다.
- 썸네일 radius는 모든 크기에서 14dp로 동일하다.
large카드는 카드 폭 163dp, thumbnail 163dp x 230dp, label 폭 151dp로 사용한다.small카드는 카드 폭 122dp, thumbnail 122dp x 172dp, label 폭 114dp로 사용한다.- 텍스트는 어두운 배경 위 사용을 전제로 white/
gray_500색상 대비를 유지한다. - ORIGINAL 태그는 thumbnail 좌상단에 고정되어 Figma
20:3914처럼 이미지 위에 overlay된다.
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토큰을 우선 사용한다. - 기존
AudioContentCardSize처럼 size contract는 순수 Kotlin 객체 또는 enum으로 분리해 단위 테스트 가능하게 한다. ic_series_original.png리소스가 이미 존재하면 그대로 사용하고, 없으면 구현 전 디자인 에셋을 추가한다.- 기존 화면의 동작이나 레이아웃을 요청 없이 변경하지 않는다.
10. Metrics
large,small2개 size variant의 카드 폭, 썸네일 크기, label 폭이 문서와 구현에서 일치한다.- 제목과 크리에이터명은 한 줄 말줄임 처리된다.
- ORIGINAL 태그는
ic_series_original아이콘과ORIGINAL텍스트를 표시한다. - ORIGINAL 태그 표시 여부를 호출부에서 제어할 수 있다.
- size contract 단위 테스트가 통과한다.
- Android 리소스 병합 및 디버그 빌드가 성공한다.
- 기존 오디오 콘텐츠 카드와 기존 화면 파일은 변경되지 않는다.
11. Open Questions
- 사용자가
20:3096은 오타이고20:3906이 맞다고 정정했으므로, 이 문서는20:3906을 ORIGINAL 태그 구현 기준으로 삼는다. - Figma의 ORIGINAL 텍스트는 Phosphate Solid이며, 프로젝트의
@font/phosphate_solid리소스를 사용한다. - 하단 유료/무료 태그는 Figma generated code에 포함되지만 사용자 요청에 없으므로 제외한다.