From ecb9f5a260865395dbed607a90e921f5bdaf30eb Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 28 May 2026 13:11:12 +0900 Subject: [PATCH] =?UTF-8?q?docs(banner):=20Phase=208=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=EC=9D=84=20=EA=B8=B0=EB=A1=9D=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- docs/plan-task/20260527_배너컴포넌트.md | 85 +++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/docs/plan-task/20260527_배너컴포넌트.md b/docs/plan-task/20260527_배너컴포넌트.md index 43db4e7c..c43ce742 100644 --- a/docs/plan-task/20260527_배너컴포넌트.md +++ b/docs/plan-task/20260527_배너컴포넌트.md @@ -340,6 +340,87 @@ - 마지막/첫 번째 경계에서 무한 순환이 자연스럽다. - 기록 위치: 이 문서 하단 `검증 기록` 섹션. +### Phase 8: PRD 불일치 및 검증 갭 보완 + +- [x] **Task 8.1: counter 시각 형식 회귀 테스트 작성** + - 수정 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt` + - 대상 리스크: counter가 PRD의 `01 / 20` 형식, `14sp`, line-height `1.45` 기준과 다르게 표시될 수 있다. + - 테스트 항목: + - 복수 배너 counter가 실제 조합 기준으로 `01 / 02`처럼 slash 앞뒤 공백을 포함해 보이는지 검증한다. + - 현재 index는 `white`, separator/total count는 `gray_400`을 유지하는지 검증한다. + - counter text style이 PRD 기준 `14sp` token 또는 동등한 typography로 적용되는지 검증한다. + - 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"` + - 기대: 구현 전에는 counter 공백 또는 typography mismatch로 실패하고, 구현 후 성공한다. + +- [x] **Task 8.2: counter 시각 형식 구현 보완** + - 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt`, `app/src/main/res/layout/view_banner.xml` + - 요구사항: + - counter가 실제 렌더링에서 `01 / 20` 형태로 표시되도록 separator 주변 공백 또는 동등한 간격을 명시한다. + - 현재 index는 `white`, separator와 total count는 `gray_400`을 유지한다. + - PRD 기준 `14sp`, line-height `1.45`에 맞는 기존 typography token을 우선 사용한다. + - 검증: Task 8.1 테스트가 통과한다. + +- [x] **Task 8.3: lifecycle stop timer 중지 테스트 작성** + - 수정 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt` + - 대상 리스크: view가 detach되지 않고 lifecycle만 stop되는 경우 자동 전환 timer가 계속 동작할 수 있다. + - 테스트 항목: + - `BannerView`가 attached 상태에서 lifecycle `ON_STOP`을 받으면 pending auto scroll callback이 제거된다. + - lifecycle `ON_START` 또는 재개 조건에서 배너가 2개 이상이면 auto scroll timer가 다시 예약된다. + - 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"` + - 기대: 구현 전에는 lifecycle stop 시나리오가 실패하고, 구현 후 성공한다. + +- [x] **Task 8.4: lifecycle stop timer 중지 구현** + - 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt` + - 요구사항: + - `ViewTreeLifecycleOwner` 또는 기존 프로젝트 관례에 맞는 lifecycle 관찰 방식으로 stop 시 timer를 중지한다. + - detach cleanup은 기존대로 유지한다. + - lifecycle owner가 없는 preview/test 경로에서 crash가 발생하지 않아야 한다. + - 검증: Task 8.3 테스트와 기존 attach/detach cleanup 테스트가 모두 통과한다. + +- [x] **Task 8.5: 목록 갱신 시 첫 번째 배너 재시작 테스트 작성** + - 수정 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt` + - 대상 리스크: `setItems()`가 기존 `currentIndex`를 유지해 PRD의 "목록 갱신 후 2개 이상이면 첫 번째 배너 기준으로 다시 시작" 요구와 다를 수 있다. + - 테스트 항목: + - 현재 counter가 두 번째 이상인 상태에서 새 복수 배너 목록을 `setItems()`로 설정하면 counter가 `01`로 초기화된다. + - 목록 갱신 후 auto scroll timer도 첫 번째 배너 기준으로 다시 시작된다. + - 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"` + - 기대: 구현 전에는 기존 index 유지로 실패하고, 구현 후 성공한다. + +- [x] **Task 8.6: 목록 갱신 시 첫 번째 배너 재시작 구현** + - 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt` + - 요구사항: + - 새 목록이 2개 이상이면 `currentIndex`와 adapter position을 첫 번째 배너 기준으로 초기화한다. + - 새 목록이 0개이면 숨김과 timer 중지를 유지한다. + - 새 목록이 1개이면 첫 번째 이미지만 표시하고 counter/auto scroll을 비활성화한다. + - 검증: Task 8.5 테스트와 기존 0/1/2개 상태 테스트가 모두 통과한다. + +- [x] **Task 8.7: 수동 경계 스와이프 및 빠른 연속 스와이프 View 테스트 보강** + - 수정 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt` + - 대상 리스크: 순수 index 계산은 검증됐지만 실제 `RecyclerView` snap/counter가 수동 경계 스와이프와 빠른 연속 스와이프에서 일치하는지 직접 검증하지 않는다. + - 테스트 항목: + - 첫 번째 배너에서 이전 방향으로 이동한 뒤 idle 상태가 되면 마지막 배너 counter가 표시된다. + - 마지막 배너에서 다음 방향으로 이동한 뒤 idle 상태가 되면 첫 번째 배너 counter가 표시된다. + - 빠른 연속 position 변경 후 idle 상태가 되면 snap된 adapter position의 실제 index와 counter가 일치한다. + - 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"` + - 기대: 구현이 이미 충족하면 GREEN을 확인하고, 실패하면 Task 8.8에서 최소 수정한다. + +- [x] **Task 8.8: 수동 스와이프 counter 동기화 보완** + - 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt`, 필요 시 `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerAdapter.kt` + - 요구사항: + - `SCROLL_STATE_IDLE` 시 snap된 adapter position을 기준으로 실제 item index와 counter를 항상 동기화한다. + - 첫 번째/마지막 경계에서 수동 이전/다음 이동이 끊김 없이 순환한다. + - 빠른 연속 스와이프 후에도 counter가 실제 표시 item과 일치한다. + - 검증: Task 8.7 테스트와 기존 자동 전환, drag reset, 무한 순환 테스트가 모두 통과한다. + +- [x] **Task 8.9: Phase 8 최종 검증 실행 및 기록** + - 실행: + - `./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` + - `./gradlew :app:ktlintCheck` + - 기록 위치: 이 문서 하단 `검증 기록` 섹션. + - 기대 결과: 모두 `BUILD SUCCESSFUL`이며, 실제 기기 또는 Android Studio XML layout editor 확인이 가능하면 counter 공백/typography, preview, peek, radius를 수동 확인한다. + ## 검증 기록 - 2026-05-27 Phase 1 완료: PRD `docs/prd/20260527_배너컴포넌트_prd.md`의 Goals, Visual Requirements, Behavior Requirements, Metrics가 계획의 Phase 2~7 task로 매핑됨을 확인했다. Figma 기준 `24:5525`에서 계획에 명시된 `1:1`, `screenWidth - 40dp`, 좌우 `20dp`, item 간격 `8dp`, 좌우 peek, `radius_14`, counter `top/right 14dp`, `01 / 20` 형식과 불일치하는 항목은 발견하지 못했다. - 2026-05-27 Phase 1 패턴 확인: `AudioContentCardView`의 `@JvmOverloads` custom view, `thumbnailView(): ImageView` 노출, `radius_14` outline clipping 패턴을 확인했다. `FeedAdapter`의 `RecyclerView.Adapter`, click callback, image binding callback 패턴과 `FeedViewTest`의 Robolectric XML inflate test 패턴을 확인했다. @@ -374,3 +455,7 @@ - 2026-05-28 Phase 7 단위 테스트 검증: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerLayoutCalculatorTest" --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerCounterFormatterTest" --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerStateTest" --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"`와 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.*"` 실행 결과 모두 `BUILD SUCCESSFUL`을 확인했다. - 2026-05-28 Phase 7 리소스/빌드/스타일 검증: `./gradlew :app:assembleDebug`와 `./gradlew :app:ktlintCheck` 실행 결과 모두 `BUILD SUCCESSFUL`을 확인했다. `ktlintCheck` 과정에서 배너 파일의 wrapping/blank line 지적과 테스트 소스의 unused import 지적을 최소 수정했다. - 2026-05-28 Phase 7 수동 확인 기록: 실제 기기/Android Studio XML layout editor는 이 환경에서 열 수 없어 직접 시각 확인은 수행하지 못했다. 대신 Robolectric `BannerViewTest`와 `assembleDebug`로 preview attrs 반영, counter 표시, radius outline provider, 0/1/2개 상태, 좌우 peek/spacing 계산, 자동 전환 5초, 수동 drag timer reset, attach/detach cleanup, 무한 순환 index 동작을 검증했다. +- 2026-05-28 Phase 8 RED: `BannerViewTest`에 counter `01 / 02` 공백/색상/14sp, lifecycle `ON_STOP`/`ON_START`, `setItems()` 목록 갱신 첫 번째 배너 재시작, 수동 경계/빠른 위치 변경 idle counter 동기화 테스트를 추가했다. Production 변경 전 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"` 실행 결과 의도한 4개 시나리오가 실패함을 확인했다. +- 2026-05-28 Phase 8 구현: `view_banner.xml` counter typography를 `Typography.Body5`로 맞추고, `BannerView`에서 separator를 ` / `로 표시하도록 보완했다. `findViewTreeLifecycleOwner()`와 `DefaultLifecycleObserver`로 lifecycle stop/start timer 제어를 추가하고, detach 시 observer를 제거한다. `setItems()`는 새 목록을 첫 번째 배너 기준으로 초기화하며, idle 시 snap view가 없으면 현재 adapter position 기준으로 counter를 동기화한다. +- 2026-05-28 Phase 8 GREEN: 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.BannerViewTest"` 실행 결과 `BUILD SUCCESSFUL`을 확인했다. +- 2026-05-28 Phase 8 최종 검증: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.banner.*"`, `./gradlew :app:assembleDebug`, `./gradlew :app:ktlintCheck` 실행 결과 모두 `BUILD SUCCESSFUL`을 확인했다. 실제 기기/Android Studio XML layout editor는 이 환경에서 열 수 없어 직접 시각 확인은 수행하지 못했고, Robolectric/빌드 검증으로 counter 공백/typography, lifecycle stop/start, 목록 갱신 초기화, 수동 경계/연속 위치 변경 counter 동기화를 확인했다.