docs(banner): 배너 wrap content 요구를 기록한다

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-05-28 11:14:12 +09:00
parent 49984cb651
commit db72c4bf7d
2 changed files with 25 additions and 0 deletions

View File

@@ -12,6 +12,7 @@
## 작업 목표
- 배너 item은 `1:1` 비율이며 width/height는 `screenWidth - 40dp`로 계산한다.
- `BannerView`는 XML에서 `layout_width="match_parent"`, `layout_height="wrap_content"`로 배치해도 화면 폭에 맞는 높이를 자체 계산한다.
- 현재 배너는 가운데 정렬하고 화면 좌우 `20dp` 기준 여백을 유지한다.
- 배너가 2개 이상이면 item 간격 `8dp`와 좌우 이전/다음 배너 일부 노출을 제공한다.
- 배너 목록 0개는 숨김, 1개는 단일 이미지, 2개 이상은 카운터/스와이프/자동 전환을 적용한다.
@@ -206,6 +207,7 @@
- 수정 파일: `BannerView.kt`, `BannerAdapter.kt`
- 요구사항:
- view width를 기준으로 item size를 `width - 40dp`로 계산한다.
- `layout_height="wrap_content"`이면 view 자체 measured height도 `width - 40dp` 기준으로 결정한다.
- item layout params는 width/height 동일 값으로 설정한다.
- RecyclerView horizontal padding 또는 item decoration을 조합해 현재 item 가운데 정렬, item 간격 `8dp`, 좌우 peek 노출을 적용한다.
- 단일 item은 peek 없이 가운데 정렬한다.
@@ -288,9 +290,24 @@
- 수정 파일: `BannerViewTest.kt`
- 테스트 항목:
- 측정된 width 기준 item layout params가 정사각형으로 설정된다.
- `width=match_parent`, `height=wrap_content` 조합으로 측정하면 root measured height가 `width - 40dp`와 일치한다.
- 복수 item일 때 item decoration 또는 padding이 `8dp` spacing과 좌우 peek 조건을 반영한다.
- 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"`
- [ ] **Task 6.5: `BannerView` wrap_content 높이 측정 보완**
- 수정 파일: `BannerView.kt`, `BannerViewTest.kt`
- 요구사항:
- 호출부 XML에서 `layout_width="match_parent"`, `layout_height="wrap_content"`를 사용해도 화면 폭별로 배너 높이가 자동 계산된다.
- root measured height는 measured width 기준 `width - 40dp`와 일치한다.
- 고정 `362dp` 같은 화면별 상수 height를 호출부에 요구하지 않는다.
- 기존 item size, 좌우 `20dp` inset, `8dp` spacing, counter 위치 동작은 유지한다.
- 테스트 항목:
- `BannerViewTest`에서 width `402dp`, height `wrap_content` 측정 시 measured height가 `362dp`인지 확인한다.
- width `360dp`, height `wrap_content` 측정 시 measured height가 `320dp`인지 확인한다.
- 명시 height가 들어온 경우 기존 부모 측정 제약을 깨지 않는지 확인한다.
- 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"`
### Phase 7: 문서, 검증, 마무리
- [ ] **Task 7.1: 테스트 실행 예시 문서 갱신**
@@ -346,3 +363,6 @@
- 2026-05-28 Phase 5 RED: `BannerViewTest`에 자동 전환, 수동 drag timer reset, detach cleanup 테스트를 추가한 뒤 production 변경 전 실행해 자동 전환/drag reset 시나리오 실패를 확인했다.
- 2026-05-28 Phase 5 구현: `BannerView`에 main looper `Handler/Runnable` 기반 5초 자동 전환, `SCROLL_STATE_DRAGGING` 중 timer 취소, `SCROLL_STATE_IDLE` 후 재예약, `onAttachedToWindow` 시작, `onDetachedFromWindow` callback 제거를 추가했다. `BannerAdapter.startPosition()`으로 carousel 시작 위치를 virtual range 중앙에 맞췄다.
- 2026-05-28 Phase 5 검증: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.*"`, `./gradlew :app:assembleDebug` 실행 결과 모두 `BUILD SUCCESSFUL`을 확인했다.
- 2026-05-28 Phase 4.3 보완 RED: `BannerViewTest``layout_width="match_parent"`, `layout_height="wrap_content"` 측정 시 width `402dp`는 height `362dp`, width `360dp`는 height `320dp`가 되어야 한다는 회귀 테스트를 추가했고, production 변경 전 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"` 실행에서 두 테스트 실패를 확인했다.
- 2026-05-28 Phase 4.3 보완 구현: `BannerView.onMeasure()`에서 height measure spec이 `EXACTLY`가 아닐 때 measured width 기준 `BannerLayoutCalculator` 결과로 root measured height를 계산하도록 수정했다. 명시 height가 들어온 경우에는 부모 측정 제약을 유지한다.
- 2026-05-28 Phase 4.3 보완 검증: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.*"`, `./gradlew :app:assembleDebug` 실행 결과 모두 `BUILD SUCCESSFUL`을 확인했다.

View File

@@ -24,6 +24,7 @@ Figma `24:5525` 디자인을 기준으로 이미지 배너를 자동 전환, 수
- 사용자가 직접 스와이프하면 자동 전환 타이머를 초기화한다.
- 호출부는 배너 아이템별 터치 액션을 콜백으로 연결할 수 있어야 한다.
- XML에서 배치할 때 디자인 타임 미리보기가 가능해야 한다.
- 개발자는 화면별 고정 높이 상수를 계산하지 않고 `match_parent` width와 `wrap_content` height 조합으로 배너를 배치할 수 있어야 한다.
---
@@ -64,6 +65,7 @@ Figma `24:5525` 기준의 이미지 배너를 XML + Kotlin custom view 기반
- 기본 배너 비율은 `1:1` 정사각형이다.
- 기본 배너 item width는 `screenWidth - 40dp`로 계산한다.
- 배너 item height는 계산된 item width와 동일하게 적용한다.
- `BannerView` root height가 `wrap_content`이면 measured width를 기준으로 자체 높이를 `screenWidth - 40dp`에 맞춰 측정한다.
- 현재 배너 item은 부모 영역의 가로 가운데에 정렬한다.
- 현재 배너 item은 화면 왼쪽에서 `20dp`, 오른쪽에서 `20dp` 떨어진 위치를 기준으로 표시한다.
- 배너가 여러 개이면 item 사이 간격은 `8dp`다.
@@ -105,6 +107,7 @@ Figma `24:5525` 기준의 이미지 배너를 XML + Kotlin custom view 기반
#### XML Preview Requirements
- XML layout editor에서 배너 컴포넌트의 기본 형태를 미리 볼 수 있어야 한다.
- XML layout에서 `layout_width="match_parent"`, `layout_height="wrap_content"`로 선언해도 배너가 화면 폭에 맞는 정사각형 높이로 표시되어야 한다.
- 디자인 타임에는 샘플 이미지 또는 placeholder 배경과 샘플 카운터가 표시되어야 한다.
- `tools:` 속성 또는 커스텀 preview 속성으로 샘플 count와 current index를 확인할 수 있어야 한다.
- 런타임 데이터가 없어도 XML 미리보기에서 배너 높이, radius, 카운터 위치가 확인되어야 한다.
@@ -124,6 +127,7 @@ Figma `24:5525` 기준의 이미지 배너를 XML + Kotlin custom view 기반
- 배너는 이미지 중심 컴포넌트이며 텍스트 정보는 카운터만 표시한다.
- 배너 radius와 카운터 위치는 Figma와 일관되게 유지한다.
- 배너는 화면 좌우 `20dp` 여백을 기준으로 가운데 정렬되고, 정사각형 비율을 유지해야 한다.
- 배너 높이는 호출부가 화면별 상수 dp 값을 지정하지 않아도 컴포넌트가 width 기반으로 결정해야 한다.
- 여러 배너를 표시할 때는 `8dp` 간격과 좌우 peek 노출로 다음/이전 콘텐츠가 있음을 사용자가 알 수 있어야 한다.
- 카운터는 이미지 위에서 읽히되 배너 콘텐츠를 과도하게 가리지 않아야 한다.
- 자동 전환은 사용자의 수동 스와이프보다 우선하지 않아야 하며, 사용자가 조작한 직후에는 타이머가 초기화되어야 한다.
@@ -146,6 +150,7 @@ Figma `24:5525` 기준의 이미지 배너를 XML + Kotlin custom view 기반
## 10. Metrics
- Figma `24:5525` 기준의 `14dp` radius와 우상단 카운터가 구현된다.
- 배너 item은 `1:1` 비율이며 width와 height가 `screenWidth - 40dp`로 계산된다.
- `BannerView``layout_width="match_parent"`, `layout_height="wrap_content"` 선언에서 기기 폭에 따라 적절한 높이로 측정된다.
- 현재 배너는 가운데 정렬되고 화면 좌우에 각각 `20dp` 기준 여백을 가진다.
- 배너 목록 2개 이상에서는 item 간격 `8dp`와 좌우 이전/다음 배너 일부 노출이 적용된다.
- 배너 목록 0개에서는 컴포넌트 영역이 숨겨진다.