docs(ranking): 반응형 크기 요구를 기록한다
This commit is contained in:
303
docs/20260710_메인_랭킹_UI_반응형_크기_조정/plan-task.md
Normal file
303
docs/20260710_메인_랭킹_UI_반응형_크기_조정/plan-task.md
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
# 메인 랭킹 UI 반응형 크기 조정 Plan / Task
|
||||||
|
|
||||||
|
**Goal:** 메인 홈 크리에이터 랭킹과 메인 콘텐츠 랭킹에서 402dp 이상은 현재 크기를 유지하고, 402dp 미만은 현재 크기를 `device width / 402` 비율로 축소한다. 크리에이터 랭킹 순위 숫자 폰트는 `Pattaya`로 맞춘다.
|
||||||
|
|
||||||
|
**Architecture:** 기존 `creatorranking`/`contentranking` 위젯 구조를 유지하고, 공통 402dp scale 계산은 두 랭킹 위젯에서 재사용 가능한 최소 단위로 분리한다. 기존 rank placement, card variant, mapper, API, 클릭 이동은 변경하지 않는다.
|
||||||
|
|
||||||
|
**Tech Stack:** Kotlin, Android XML Views, ViewBinding, RecyclerView, Android resource font, JUnit4/Robolectric local unit test.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 전제와 성공 기준
|
||||||
|
- PRD: `docs/20260710_메인_랭킹_UI_반응형_크기_조정/prd.md`
|
||||||
|
- 기준 폭은 `402dp`이다.
|
||||||
|
- `device width >= 402dp`이면 현재 글자/아이콘/UI 크기와 동일해야 한다.
|
||||||
|
- `device width < 402dp`이면 현재 기준값에 `device width / 402` scale을 적용한다.
|
||||||
|
- `Font - Pattaya` 적용 대상은 크리에이터 랭킹의 순위 숫자 텍스트로 확정한다.
|
||||||
|
- 402dp 미만 축소는 device width 기준 비율 적용이므로 별도 최소 글자 크기 하한은 두지 않는다.
|
||||||
|
- 콘텐츠 랭킹 순위 숫자 폰트는 기존 `Pattaya` 표시를 유지한다.
|
||||||
|
- 콘텐츠 닉네임은 현재 설정값을 기준으로 402dp 이상 유지, 402dp 미만 비율 축소한다.
|
||||||
|
- API, DTO, mapper, ranking type, click routing, empty/error/loading 정책은 변경하지 않는다.
|
||||||
|
- 구현 완료 후 최소 다음 명령을 실행한다.
|
||||||
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"`
|
||||||
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"`
|
||||||
|
- `./gradlew :app:mergeDebugResources`
|
||||||
|
- `./gradlew :app:compileDebugKotlin`
|
||||||
|
- `./gradlew :app:ktlintCheck`
|
||||||
|
- `git diff --check`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 현재 기준값
|
||||||
|
|
||||||
|
### 크리에이터 랭킹
|
||||||
|
| Rank group | 순위 글자 | 순위 변동 숫자 | 순위 변동 아이콘 | 크리에이터 닉네임 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: |
|
||||||
|
| 1위 | `96sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `32sp` |
|
||||||
|
| 2~7위 | `54sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` |
|
||||||
|
| 8~10위 | `36sp` | `14sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `14sp` |
|
||||||
|
| 11위 이상 | `40sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `18sp` |
|
||||||
|
|
||||||
|
### 콘텐츠 랭킹
|
||||||
|
| Rank group | 순위 글자 | 순위 변동 숫자 | 순위 변동 아이콘 | 콘텐츠 타이틀 | 콘텐츠 닉네임 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| 1위 Large | `96sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` | `12sp` |
|
||||||
|
| 2~7위 MediumGrid | `54sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` | `12sp` |
|
||||||
|
| 8~10위 SmallGrid | `widthPx <= 140`이면 `36sp`, 그 외 `54sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `widthPx <= 140`이면 `14sp`, 그 외 `22sp` | `12sp` |
|
||||||
|
| 11위 이상 Horizontal | `40sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `18sp` | `14sp` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 파일 구조
|
||||||
|
- 수정 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/ranking/RankingResponsiveScale.kt`
|
||||||
|
- 402dp 기준 scale 계산을 공통 로직으로 분리한다.
|
||||||
|
- 생성 후보: `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/ranking/RankingResponsiveScaleTest.kt`
|
||||||
|
- `402dp`, `401dp`, `360dp`, fallback scale 계약을 검증한다.
|
||||||
|
- 수정 후보: `app/src/main/res/layout/view_creator_ranking_top_card.xml`
|
||||||
|
- 크리에이터 랭킹 순위 숫자 fontFamily를 `@font/pattaya_regular`로 변경한다.
|
||||||
|
- 수정 후보: `app/src/main/res/layout/view_creator_ranking_lower_row.xml`
|
||||||
|
- 크리에이터 랭킹 순위 숫자 fontFamily를 `@font/pattaya_regular`로 변경한다.
|
||||||
|
- 수정 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTextStyle.kt`
|
||||||
|
- 현재 기준 크기와 scale 적용 결과를 분리해 계산한다.
|
||||||
|
- 수정 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardView.kt`
|
||||||
|
- 순위/닉네임/순위 변동 텍스트와 순위 변동 아이콘 크기에 scale을 적용한다.
|
||||||
|
- 수정 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLowerRowView.kt`
|
||||||
|
- 11위 이상 row의 순위/닉네임/순위 변동 텍스트와 순위 변동 아이콘 크기에 scale을 적용한다.
|
||||||
|
- 수정 후보: `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTextStyleTest.kt`
|
||||||
|
- rank group별 baseline과 402dp scale 적용 계약을 검증한다.
|
||||||
|
- 수정 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingLargeCardView.kt`
|
||||||
|
- Large 카드의 순위/타이틀/닉네임/순위 변동 UI에 scale을 적용한다.
|
||||||
|
- 수정 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingGridCardView.kt`
|
||||||
|
- MediumGrid/SmallGrid 카드의 조건부 baseline에 scale을 적용한다.
|
||||||
|
- 수정 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingHorizontalCardView.kt`
|
||||||
|
- Horizontal 카드의 순위/타이틀/닉네임/순위 변동 UI에 scale을 적용한다.
|
||||||
|
- 생성 후보: `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingResponsiveSizeTest.kt`
|
||||||
|
- 콘텐츠 랭킹 card variant별 baseline과 scale 적용 계약을 검증한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 1: 기존 구조와 기준값 재확인
|
||||||
|
|
||||||
|
- [x] **Task 1.1: 크리에이터 랭킹 현재 기준값 확인**
|
||||||
|
- 확인:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTextStyle.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingDeltaPresentation.kt`
|
||||||
|
- `app/src/main/res/layout/view_creator_ranking_top_card.xml`
|
||||||
|
- `app/src/main/res/layout/view_creator_ranking_lower_row.xml`
|
||||||
|
- 작업:
|
||||||
|
- rank group별 순위/닉네임/순위 변동 텍스트 baseline을 확인한다.
|
||||||
|
- caret/New 아이콘 baseline과 pill padding/margin 값을 확인한다.
|
||||||
|
- 현재 순위 숫자 fontFamily와 목표 `Pattaya` 차이를 확인한다.
|
||||||
|
- 검증:
|
||||||
|
- Run: `rg -n "rankTextSizeSp|nameTextSizeSp|deltaTextSizeSp|iconWidthDp|iconHeightDp|fontFamily" app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking app/src/main/res/layout/view_creator_ranking_top_card.xml app/src/main/res/layout/view_creator_ranking_lower_row.xml`
|
||||||
|
- Expected: PRD baseline 값과 변경 대상 fontFamily가 확인된다.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: `CreatorRankingTextStyle.kt`, `CreatorRankingDeltaPresentation.kt`, creator ranking layout 2개에서 PRD baseline과 현재 순위 숫자 fontFamily `@font/phosphate_solid`를 확인했다. `@font/pattaya_regular` 리소스가 존재하므로 변경 대상은 creator ranking 순위 숫자 TextView 2곳으로 확정했다.
|
||||||
|
|
||||||
|
- [x] **Task 1.2: 콘텐츠 랭킹 현재 기준값 확인**
|
||||||
|
- 확인:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingLargeCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingGridCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingHorizontalCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingDeltaPresentation.kt`
|
||||||
|
- `app/src/main/res/layout/view_content_ranking_large_card.xml`
|
||||||
|
- `app/src/main/res/layout/view_content_ranking_grid_card_content.xml`
|
||||||
|
- `app/src/main/res/layout/view_content_ranking_horizontal_card.xml`
|
||||||
|
- 작업:
|
||||||
|
- card variant별 순위/타이틀/닉네임/순위 변동 baseline을 확인한다.
|
||||||
|
- `SmallGrid`의 `widthPx <= 140` 조건부 baseline을 확인한다.
|
||||||
|
- 콘텐츠 랭킹 순위 숫자 fontFamily가 기존 `Pattaya` 계열인지 확인한다.
|
||||||
|
- 검증:
|
||||||
|
- Run: `rg -n "textSize|widthPx <= SMALL_THRESHOLD_PX|SMALL_THRESHOLD_PX|iconWidthDp|iconHeightDp|fontFamily" app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking app/src/main/res/layout/view_content_ranking_large_card.xml app/src/main/res/layout/view_content_ranking_grid_card_content.xml app/src/main/res/layout/view_content_ranking_horizontal_card.xml`
|
||||||
|
- Expected: PRD baseline 값과 조건부 `SmallGrid` 정책이 확인된다.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: `ContentRankingLargeCardView.kt`, `ContentRankingGridCardView.kt`, `ContentRankingHorizontalCardView.kt`, `ContentRankingDeltaPresentation.kt`, content ranking layout 3개에서 PRD baseline과 `SmallGrid`의 `widthPx <= 140` 분기를 확인했다. 콘텐츠 랭킹 순위 숫자 fontFamily는 이미 `@font/pattaya_regular`이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 2: 402dp 반응형 scale 계약 추가
|
||||||
|
|
||||||
|
- [x] **Task 2.1: 공통 scale 계산 테스트 작성**
|
||||||
|
- 생성:
|
||||||
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/ranking/RankingResponsiveScaleTest.kt`
|
||||||
|
- 테스트:
|
||||||
|
- `screenWidthDp=402`이면 `1.0`
|
||||||
|
- `screenWidthDp=430`이면 `1.0`
|
||||||
|
- `screenWidthDp=360`이면 `360f / 402f`
|
||||||
|
- `screenWidthDp<=0`이면 `1.0`
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.ranking.RankingResponsiveScaleTest"`
|
||||||
|
- Expected: 구현 전 RED 실패.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: 구현 전 `RankingResponsiveScale` 미존재로 `Unresolved reference` RED 실패를 확인했다.
|
||||||
|
|
||||||
|
- [x] **Task 2.2: 공통 scale 계산 로직 구현**
|
||||||
|
- 생성:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/ranking/RankingResponsiveScale.kt`
|
||||||
|
- 구현:
|
||||||
|
- 기준 폭 상수 `BASE_WIDTH_DP = 402`
|
||||||
|
- `screenWidthDp >= BASE_WIDTH_DP`이면 `1f`
|
||||||
|
- `screenWidthDp in 1 until BASE_WIDTH_DP`이면 `screenWidthDp / BASE_WIDTH_DP.toFloat()`
|
||||||
|
- fallback은 `1f`
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.ranking.RankingResponsiveScaleTest"`
|
||||||
|
- Expected: PASS.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.ranking.RankingResponsiveScaleTest"` PASS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 3: 크리에이터 랭킹 적용
|
||||||
|
|
||||||
|
- [x] **Task 3.1: 크리에이터 랭킹 텍스트 스타일 테스트 작성**
|
||||||
|
- 수정 또는 생성:
|
||||||
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTextStyleTest.kt`
|
||||||
|
- 테스트:
|
||||||
|
- 402dp 이상에서 기존 baseline 크기 유지
|
||||||
|
- 360dp에서 baseline에 `360 / 402` scale 적용
|
||||||
|
- rank group별 1위, 2~7위, 8~10위, 11위 이상 baseline 유지
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingTextStyleTest"`
|
||||||
|
- Expected: scale 적용 전 RED 실패.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: 구현 전 `CreatorRankingTextStyle.scaledBy` 미존재로 RED 실패를 확인했다.
|
||||||
|
|
||||||
|
- [x] **Task 3.2: 크리에이터 랭킹 폰트와 텍스트 scale 적용**
|
||||||
|
- 수정:
|
||||||
|
- `app/src/main/res/layout/view_creator_ranking_top_card.xml`
|
||||||
|
- `app/src/main/res/layout/view_creator_ranking_lower_row.xml`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTextStyle.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLowerRowView.kt`
|
||||||
|
- 구현:
|
||||||
|
- 순위 숫자 fontFamily를 `@font/pattaya_regular`로 변경한다.
|
||||||
|
- `resources.configuration.screenWidthDp`에서 scale을 계산한다.
|
||||||
|
- 순위/닉네임/순위 변동 숫자 `setTextSize()`에 scale 적용 값을 전달한다.
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"`
|
||||||
|
- Expected: PASS.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: creator ranking 순위 숫자 fontFamily를 `@font/pattaya_regular`로 변경하고, 순위/닉네임/순위 변동 텍스트에 402dp scale을 적용했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"` PASS.
|
||||||
|
|
||||||
|
- [x] **Task 3.3: 크리에이터 랭킹 순위 변동 UI scale 적용**
|
||||||
|
- 수정:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLowerRowView.kt`
|
||||||
|
- 구현:
|
||||||
|
- caret 아이콘 `14dp x 14dp`에 scale 적용
|
||||||
|
- NEW 아이콘 `36dp x 23dp`에 scale 적용
|
||||||
|
- pill padding과 icon margin이 시각 크기에 영향을 주는 경우 scale 적용
|
||||||
|
- `showRankChange=false` 숨김 정책은 유지
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"`
|
||||||
|
- Expected: PASS.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: creator ranking caret/New 아이콘, icon margin, pill horizontal padding에 402dp scale을 적용했다. creator ranking targeted test PASS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 4: 콘텐츠 랭킹 적용
|
||||||
|
|
||||||
|
- [x] **Task 4.1: 콘텐츠 랭킹 반응형 크기 테스트 작성**
|
||||||
|
- 생성:
|
||||||
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingResponsiveSizeTest.kt`
|
||||||
|
- 테스트:
|
||||||
|
- Large baseline은 402dp 이상에서 순위 `96sp`, 타이틀 `22sp`, 닉네임 `12sp`
|
||||||
|
- MediumGrid baseline은 402dp 이상에서 순위 `54sp`, 타이틀 `22sp`, 닉네임 `12sp`
|
||||||
|
- SmallGrid `widthPx <= 140` baseline은 순위 `36sp`, 타이틀 `14sp`, 닉네임 `12sp`
|
||||||
|
- Horizontal baseline은 순위 `40sp`, 타이틀 `18sp`, 닉네임 `14sp`
|
||||||
|
- 360dp에서는 각 baseline에 `360 / 402` scale 적용
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.ContentRankingResponsiveSizeTest"`
|
||||||
|
- Expected: scale 적용 전 RED 실패.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: 구현 전 `ContentRankingTextStyle` 미존재로 RED 실패를 확인했다.
|
||||||
|
- 2026-07-10: 후속 수정으로 `SmallGrid`가 `setCardSize()` 전 `bind()`만 호출되어도 402dp 미만 text size를 축소하는 회귀 테스트를 `ContentRankingCardViewTest`에 추가했다.
|
||||||
|
|
||||||
|
- [x] **Task 4.2: 콘텐츠 랭킹 텍스트 scale 적용**
|
||||||
|
- 수정:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingLargeCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingGridCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingHorizontalCardView.kt`
|
||||||
|
- 구현:
|
||||||
|
- `resources.configuration.screenWidthDp` 기준 scale을 적용한다.
|
||||||
|
- 순위/타이틀/닉네임/순위 변동 숫자에 scale 적용 값을 전달한다.
|
||||||
|
- `SmallGrid`는 기존 `widthPx <= 140` 분기 결과를 baseline으로 삼고 scale만 적용한다.
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"`
|
||||||
|
- Expected: PASS.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: content ranking Large/MediumGrid/SmallGrid/Horizontal의 순위/타이틀/닉네임/순위 변동 숫자에 402dp scale을 적용했고, `SmallGrid`의 `widthPx <= 140` 분기는 유지했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"` PASS.
|
||||||
|
- 2026-07-10: 후속 수정으로 `ContentRankingGridCardView`가 adapter의 `setCardSize()` 선호출에만 의존하지 않도록 `bind()`에서 fallback text style을 적용하게 보완했다.
|
||||||
|
|
||||||
|
- [x] **Task 4.3: 콘텐츠 랭킹 순위 변동 UI scale 적용**
|
||||||
|
- 수정:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingLargeCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingGridCardView.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingHorizontalCardView.kt`
|
||||||
|
- 구현:
|
||||||
|
- caret 아이콘 `14dp x 14dp`에 scale 적용
|
||||||
|
- NEW 아이콘 `36dp x 23dp`에 scale 적용
|
||||||
|
- pill padding과 icon margin이 시각 크기에 영향을 주는 경우 scale 적용
|
||||||
|
- `showRankChange=false` 숨김 정책은 유지
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"`
|
||||||
|
- Expected: PASS.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: content ranking caret/New 아이콘, icon margin, pill horizontal padding에 402dp scale을 적용했다. content ranking targeted test PASS.
|
||||||
|
- 2026-07-10: 후속 수정으로 delta text size도 각 카드의 `ContentRankingTextStyle.deltaTextSizeSp`를 사용하도록 정리해 텍스트 scale 기준을 단일화했다.
|
||||||
|
|
||||||
|
- [x] **Task 4.4: 콘텐츠 랭킹 SmallGrid 8~10위 순위 숫자 기준값 보정**
|
||||||
|
- 수정:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingTextStyle.kt`
|
||||||
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingResponsiveSizeTest.kt`
|
||||||
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/contentranking/ContentRankingCardViewTest.kt`
|
||||||
|
- 구현:
|
||||||
|
- `ContentRankingGridCardView`의 8~10위 SmallGrid가 사용하는 순위 숫자 baseline을 `36sp`로 맞춘다.
|
||||||
|
- 콘텐츠 타이틀 `14sp`, 콘텐츠 닉네임 `12sp`, 402dp 미만 비율 축소 정책은 유지한다.
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"`
|
||||||
|
- Expected: PASS.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: `ContentRankingTextStyle.smallGrid()`의 순위 숫자 baseline을 `40sp`에서 `36sp`로 보정했다. 콘텐츠 타이틀 `14sp`, 콘텐츠 닉네임 `12sp`, 402dp 미만 비율 축소 정책은 유지했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"` PASS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 5: 통합 검증
|
||||||
|
|
||||||
|
- [x] **Task 5.1: 리소스와 Kotlin 컴파일 검증**
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:mergeDebugResources`
|
||||||
|
- Expected: font resource 및 XML 변경이 정상 merge된다.
|
||||||
|
- Run: `./gradlew :app:compileDebugKotlin`
|
||||||
|
- Expected: Kotlin 컴파일 성공.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: `./gradlew :app:mergeDebugResources` PASS. `./gradlew :app:compileDebugKotlin` PASS.
|
||||||
|
|
||||||
|
- [x] **Task 5.2: 린트와 diff 검증**
|
||||||
|
- 검증:
|
||||||
|
- Run: `./gradlew :app:ktlintCheck`
|
||||||
|
- Expected: Kotlin style 위반 없음.
|
||||||
|
- Run: `git diff --check`
|
||||||
|
- Expected: trailing whitespace 또는 patch 오류 없음.
|
||||||
|
- 결과:
|
||||||
|
- 2026-07-10: 최초 `ktlintCheck`에서 신규 테스트 공백 2건과 미사용 import 1건을 수정했다. 재실행 결과 `./gradlew :app:ktlintCheck` PASS, `git diff --check` PASS.
|
||||||
|
|
||||||
|
- [x] **Task 5.3: 수동 화면 확인**
|
||||||
|
- 확인:
|
||||||
|
- 402dp 이상 기기 또는 emulator에서 기존 크기 유지
|
||||||
|
- 402dp 미만 기기 또는 emulator에서 비율 축소
|
||||||
|
- 크리에이터 랭킹 순위 숫자 폰트가 `Pattaya`
|
||||||
|
- 콘텐츠 닉네임이 402dp 이상에서 현재 크기 유지, 402dp 미만에서 축소
|
||||||
|
- 순위 변동 caret/New 아이콘과 pill이 텍스트와 함께 축소
|
||||||
|
- 검증 기록:
|
||||||
|
- 구현 후 실행 기기, 화면 폭, 확인 결과를 이 항목 아래에 누적한다.
|
||||||
|
- 2026-07-10: 실제 emulator 실행은 수행하지 못했다. 대신 402dp 이상/미만/폭 미확인 fallback 계약은 `RankingResponsiveScaleTest`, creator/content baseline 및 360dp scale 계약은 `CreatorRankingTextStyleTest`, `ContentRankingResponsiveSizeTest`로 검증했고, resource merge로 creator Pattaya font XML 적용을 확인했다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Log
|
||||||
|
- 2026-07-10: 콘텐츠 랭킹 SmallGrid 8~10위 순위 숫자 기준값을 요구사항에 맞춰 `36sp`로 보정했다. `ContentRankingResponsiveSizeTest`, `ContentRankingCardViewTest` 기대값을 함께 갱신했고, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"`, `./gradlew :app:ktlintCheck`, `git diff --check` PASS.
|
||||||
|
- 2026-07-10: 콘텐츠 랭킹 글자 크기 적용 누락 의심 후속 확인을 진행했다. 실제 `TextView.textSize` 검증 테스트를 `ContentRankingCardViewTest`에 추가했고, Large/MediumGrid/SmallGrid/Horizontal 카드에서 360dp 기준 축소가 적용됨을 확인했다. 콘텐츠 랭킹 view의 `setCardSize()`/`bind()` 순서와 무관하게 텍스트 스타일이 유지되도록 적용 위치를 보강했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"`, `./gradlew :app:ktlintCheck`, `git diff --check` PASS.
|
||||||
|
- 2026-07-10: 사용자 요청에 따라 문서만 생성했다. Production code, test code, resource file은 수정하지 않았고 Gradle 검증은 실행하지 않았다.
|
||||||
|
- 2026-07-10: 랭킹 402dp 반응형 scale 구현 후 targeted creator/content/ranking 테스트, resource merge, Kotlin compile, ktlintCheck, git diff --check를 실행해 PASS를 확인했다. 실제 emulator 수동 확인은 수행하지 못해 테스트와 resource merge 기반으로 대체 기록했다.
|
||||||
163
docs/20260710_메인_랭킹_UI_반응형_크기_조정/prd.md
Normal file
163
docs/20260710_메인_랭킹_UI_반응형_크기_조정/prd.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# PRD: 메인 랭킹 UI 반응형 크기 조정
|
||||||
|
|
||||||
|
## 1. Overview
|
||||||
|
메인 홈 `랭킹` 탭의 크리에이터 랭킹과 메인 콘텐츠 `랭킹` 탭의 콘텐츠 랭킹에서 순위/순위 변동/타이틀/닉네임 크기를 402dp 기준으로 반응형 조정한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Problem
|
||||||
|
- 현재 랭킹 UI는 카드 구간별 고정 `sp`/`dp` 값 중심으로 구성되어 있어 402dp 미만 폭의 기기에서 동일한 시각 밀도를 유지하기 어렵다.
|
||||||
|
- 크리에이터 랭킹 순위 숫자 폰트는 요구사항상 `Pattaya`로 맞춰야 한다.
|
||||||
|
- 기존 글자 크기 자체는 402dp 이상 기기에서 유지해야 하므로, 무조건적인 크기 변경이 아니라 화면 폭 기준 축소 정책이 필요하다.
|
||||||
|
- 크리에이터 랭킹과 콘텐츠 랭킹이 유사한 랭킹 구조를 사용하므로, 402dp 기준 동작을 두 위젯에 일관되게 적용해야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Goals
|
||||||
|
- 크리에이터 랭킹 순위 숫자 폰트를 `Pattaya`로 표시한다.
|
||||||
|
- 크리에이터 랭킹의 현재 순위 글자 크기, 순위 변동 UI 크기, 닉네임 글자 크기는 `device width >= 402dp`에서 그대로 유지한다.
|
||||||
|
- 크리에이터 랭킹의 위 항목은 `device width < 402dp`에서 `device width / 402` 비율로 축소한다.
|
||||||
|
- 콘텐츠 랭킹도 크리에이터 랭킹과 동일하게 `402dp` 기준 반응형 축소 정책을 적용한다.
|
||||||
|
- 콘텐츠 랭킹의 콘텐츠 닉네임은 현재 설정 크기를 `device width >= 402dp`에서 그대로 유지하고, `device width < 402dp`에서 비율대로 축소한다.
|
||||||
|
- 구현 전 현재 설정값과 변경 대상 파일을 계획 문서에서 검증 가능하게 정리한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Non-Goals
|
||||||
|
- 이번 요청에서는 코드, 리소스, 테스트 파일을 수정하지 않는다.
|
||||||
|
- API 스키마, 랭킹 정렬, 랭킹 데이터 매핑, 클릭 이동, 차단/접근 불가 정책은 변경하지 않는다.
|
||||||
|
- 랭킹 카드의 순위 구간 정책은 변경하지 않는다.
|
||||||
|
- 크리에이터 랭킹: 1위, 2~7위, 8~10위, 11위 이상
|
||||||
|
- 콘텐츠 랭킹: 1위 Large, 2~7위 MediumGrid, 8~10위 SmallGrid, 11위 이상 Horizontal
|
||||||
|
- 레거시 오디오 콘텐츠 랭킹 화면과 기존 `AudioContentRankingAllActivity` 계열은 수정하지 않는다.
|
||||||
|
- 새 화면, 새 API, 새 탭, 추가 필터, 디자인 리팩터링은 포함하지 않는다.
|
||||||
|
- 402dp 이상 기기의 현재 글자 크기를 키우거나 줄이지 않는다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Target Users
|
||||||
|
- 402dp 미만 폭의 Android 기기에서 메인 홈/콘텐츠 랭킹을 확인하는 앱 사용자.
|
||||||
|
- 랭킹 카드에서 순위, 순위 변동, 콘텐츠/크리에이터 이름을 읽는 앱 사용자.
|
||||||
|
- `kr.co.vividnext.sodalive.v2.widget.creatorranking` 및 `kr.co.vividnext.sodalive.v2.widget.contentranking` 위젯을 유지보수하는 Android 개발자.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. User Stories
|
||||||
|
- 사용자는 좁은 기기에서도 랭킹 순위와 이름이 과도하게 커 보이지 않길 원한다.
|
||||||
|
- 사용자는 402dp 이상 기기에서는 현재 랭킹 UI와 동일한 크기를 기대한다.
|
||||||
|
- 사용자는 크리에이터 랭킹과 콘텐츠 랭킹에서 동일한 기준으로 축소되는 UI를 기대한다.
|
||||||
|
- 개발자는 랭킹별 현재 기준값과 축소 기준을 문서로 확인한 뒤 최소 변경으로 구현하고 싶다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Core Features
|
||||||
|
|
||||||
|
### Responsive Ranking Size Policy
|
||||||
|
402dp를 기준 폭으로 사용하고, 기준 폭 미만에서만 현재 설정 크기를 비율대로 축소한다.
|
||||||
|
|
||||||
|
#### Requirements
|
||||||
|
- 기준 폭은 `402dp`이다.
|
||||||
|
- `device width >= 402dp`이면 scale은 `1.0`이다.
|
||||||
|
- `device width < 402dp`이면 scale은 `device width / 402`이다.
|
||||||
|
- 축소 대상은 다음 항목이다.
|
||||||
|
- 순위 숫자 글자 크기
|
||||||
|
- 순위 변동 숫자 글자 크기
|
||||||
|
- 순위 변동 caret/New 아이콘 크기
|
||||||
|
- 순위 변동 pill의 현재 padding/margin 중 시각 크기에 직접 영향을 주는 값
|
||||||
|
- 크리에이터 랭킹 닉네임 글자 크기
|
||||||
|
- 콘텐츠 랭킹 타이틀 글자 크기
|
||||||
|
- 콘텐츠 랭킹 닉네임 글자 크기
|
||||||
|
- 스케일 계산은 px 기반 parent width가 아니라 기기 폭 dp 기준으로 정의한다.
|
||||||
|
- 402dp 이상에서 현재 값과 동일해야 하므로 `fontScale`, 접근성 설정, display density에 따른 Android 기본 변환을 임의로 우회하지 않는다.
|
||||||
|
|
||||||
|
#### Edge Cases
|
||||||
|
- `screenWidthDp`를 확인할 수 없는 환경에서는 scale `1.0`을 사용해 기존 UI를 유지한다.
|
||||||
|
- scale 적용 후 너무 작은 값 방지를 위한 최소값은 별도 요구가 없으므로 임의로 추가하지 않는다.
|
||||||
|
- 기존 콘텐츠 랭킹 `SmallGrid`의 조건부 크기 정책은 현재 동작을 기준값으로 유지하고, 선택된 기준값에 scale을 곱한다.
|
||||||
|
|
||||||
|
### Creator Ranking UI
|
||||||
|
메인 홈 `랭킹` 탭의 크리에이터 랭킹 위젯에 폰트와 반응형 크기 정책을 적용한다.
|
||||||
|
|
||||||
|
#### Current Baseline
|
||||||
|
| Rank group | 순위 글자 | 순위 변동 숫자 | 순위 변동 아이콘 | 크리에이터 닉네임 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: |
|
||||||
|
| 1위 | `96sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `32sp` |
|
||||||
|
| 2~7위 | `54sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` |
|
||||||
|
| 8~10위 | `36sp` | `14sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `14sp` |
|
||||||
|
| 11위 이상 | `40sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `18sp` |
|
||||||
|
|
||||||
|
#### Requirements
|
||||||
|
- 순위 숫자 폰트는 `Pattaya`를 사용한다.
|
||||||
|
- 위 baseline 값은 `device width >= 402dp`에서 동일해야 한다.
|
||||||
|
- `device width < 402dp`에서는 baseline 값에 scale을 곱해 표시한다.
|
||||||
|
- 기존 `CreatorRankingPlacement`의 rank group 분류는 유지한다.
|
||||||
|
- 기존 `RankingChangeType.Increase`, `Decrease`, `Stay`, `New` 표시 의미는 유지한다.
|
||||||
|
|
||||||
|
#### Edge Cases
|
||||||
|
- `showRankChange=false` item은 기존처럼 순위 변동 UI를 숨긴다.
|
||||||
|
- `RankingChangeType.New`는 숫자 텍스트 없이 NEW 아이콘만 표시하는 기존 의미를 유지한다.
|
||||||
|
- 긴 닉네임의 `ellipsize`, `maxLines` 정책은 변경하지 않는다.
|
||||||
|
|
||||||
|
### Content Ranking UI
|
||||||
|
메인 콘텐츠 `랭킹` 탭의 콘텐츠 랭킹 위젯에 크리에이터 랭킹과 동일한 반응형 크기 정책을 적용한다.
|
||||||
|
|
||||||
|
#### Current Baseline
|
||||||
|
| Rank group | 순위 글자 | 순위 변동 숫자 | 순위 변동 아이콘 | 콘텐츠 타이틀 | 콘텐츠 닉네임 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| 1위 Large | `96sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` | `12sp` |
|
||||||
|
| 2~7위 MediumGrid | `54sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` | `12sp` |
|
||||||
|
| 8~10위 SmallGrid | 조건부 | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | 조건부 | `12sp` |
|
||||||
|
| 11위 이상 Horizontal | `40sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `18sp` | `14sp` |
|
||||||
|
|
||||||
|
#### SmallGrid Baseline Detail
|
||||||
|
- 현재 `SmallGrid`는 카드 폭 기준으로 분기한다.
|
||||||
|
- `widthPx <= 140`이면 순위 `36sp`, 타이틀 `14sp`를 사용한다.
|
||||||
|
- `widthPx > 140`이면 순위 `54sp`, 타이틀 `22sp`를 사용한다.
|
||||||
|
- 반응형 구현 시 이 분기 자체를 바꾸지 않고, 분기 결과로 선택된 baseline 값에 402dp scale을 적용한다.
|
||||||
|
|
||||||
|
#### Requirements
|
||||||
|
- 콘텐츠 랭킹도 `device width >= 402dp`이면 현재 baseline 값을 유지한다.
|
||||||
|
- `device width < 402dp`이면 크리에이터 랭킹과 동일한 scale을 적용한다.
|
||||||
|
- 콘텐츠 닉네임은 현재 설정 크기를 기준으로 유지/축소한다.
|
||||||
|
- 콘텐츠 랭킹 순위 숫자 폰트는 기존 `Pattaya` 계열 표시를 유지한다.
|
||||||
|
- 기존 `ContentRankingPlacement`, card variant, layout 계산 정책은 유지한다.
|
||||||
|
|
||||||
|
#### Edge Cases
|
||||||
|
- 접근 불가 콘텐츠의 대체 텍스트 표시 정책은 변경하지 않는다.
|
||||||
|
- `showRankChange=false` item은 기존처럼 순위 변동 UI를 숨긴다.
|
||||||
|
- 긴 콘텐츠 타이틀/닉네임의 `ellipsize`, `maxLines` 정책은 변경하지 않는다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. UX / UI Expectations
|
||||||
|
- 402dp 이상 기기에서는 사용자가 기존과 동일한 랭킹 UI 크기를 보아야 한다.
|
||||||
|
- 402dp 미만 기기에서는 랭킹 숫자, 순위 변동 UI, 타이틀/닉네임이 동일 비율로 줄어 화면 폭에 맞아야 한다.
|
||||||
|
- 크리에이터 랭킹과 콘텐츠 랭킹의 축소 체감은 일관되어야 한다.
|
||||||
|
- 순위 변동 pill, caret, NEW 아이콘은 텍스트와 따로 커지거나 작아 보여서는 안 된다.
|
||||||
|
- 텍스트 크기 축소가 기존 정렬, 말줄임, 카드 variant 구분을 깨지 않아야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Technical Constraints
|
||||||
|
- Android XML Views, ViewBinding, RecyclerView 기반 기존 구조를 유지한다.
|
||||||
|
- 신규 구현이 필요할 경우 기존 `v2.widget.creatorranking`, `v2.widget.contentranking`, 공통 `v2.widget.ranking` 하위 구조를 우선 검토한다.
|
||||||
|
- 신규 `Activity`, `Fragment`, `ViewModel`은 만들지 않는다.
|
||||||
|
- 레거시 파일은 직접 수정하지 않는다.
|
||||||
|
- 구현 전 `docs/20260710_메인_랭킹_UI_반응형_크기_조정/plan-task.md`의 checklist를 먼저 갱신한 뒤 진행한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Metrics
|
||||||
|
- `device width >= 402dp`에서 크리에이터 랭킹 baseline 크기가 유지된다.
|
||||||
|
- `device width < 402dp`에서 크리에이터 랭킹 baseline 크기에 `device width / 402` scale이 적용된다.
|
||||||
|
- `device width >= 402dp`에서 콘텐츠 랭킹 baseline 크기가 유지된다.
|
||||||
|
- `device width < 402dp`에서 콘텐츠 랭킹 baseline 크기에 `device width / 402` scale이 적용된다.
|
||||||
|
- 크리에이터 랭킹 순위 숫자 폰트가 `Pattaya`로 표시된다.
|
||||||
|
- 콘텐츠 닉네임은 402dp 이상에서 현재 크기, 402dp 미만에서 비율 축소 크기를 사용한다.
|
||||||
|
- 기존 API/mapper/click routing 관련 테스트나 컴파일 결과가 회귀하지 않는다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Decisions
|
||||||
|
- `Font - Pattaya` 적용 대상은 크리에이터 랭킹의 순위 숫자 텍스트로 확정한다.
|
||||||
|
- 402dp 미만 축소는 device width 기준 비율 적용이므로 별도 최소 글자 크기 하한은 두지 않는다.
|
||||||
Reference in New Issue
Block a user