diff --git a/docs/20260626_현재_진행_중인_라이브_리스트_페이지/plan-task.md b/docs/20260626_현재_진행_중인_라이브_리스트_페이지/plan-task.md index 983c0e12..535b3583 100644 --- a/docs/20260626_현재_진행_중인_라이브_리스트_페이지/plan-task.md +++ b/docs/20260626_현재_진행_중인_라이브_리스트_페이지/plan-task.md @@ -20,7 +20,7 @@ - 앱은 `size` query parameter를 보내지 않는다. - `HomeOnAirLiveResponse`에는 `beginDateTimeUtc: String`이 포함된다. - 목록 아이템은 `LIVE HH:mm`을 표시하며, `HH:mm`은 `beginDateTimeUtc`를 디바이스 Timezone으로 변환한 라이브 시작 시각이다. -- 유료 라이브는 `ic_bar_cash`, 가격, `입장 캔`을 표시한다. +- 유료 라이브는 `ic_bar_cash`와 가격을 표시한다. - 무료 라이브는 cash 아이콘 없이 `무료`를 표시한다. - 아이템 터치 시 `getRoomDetail(roomId)` 호출 후 기존 입장 정책을 따른다. - 구현 완료 후 최소 다음 명령을 실행한다. @@ -64,7 +64,7 @@ - Modify: `app/src/main/AndroidManifest.xml` - `HomeOnAirLiveActivity`를 등록한다. - Modify: `app/src/main/res/values/strings.xml` - - `On Air`, `입장 캔`, `무료` 등 필요한 문자열을 추가하거나 기존 문자열을 재사용한다. + - `On Air`, `무료` 등 필요한 문자열을 추가하거나 기존 문자열을 재사용한다. - Modify: `app/src/main/res/values-en/strings.xml` - 신규 문자열 번역을 추가한다. - Modify: `app/src/main/res/values-ja/strings.xml` @@ -175,7 +175,7 @@ ### Phase 3: 화면 UI와 홈 진입점 연결 -- [ ] **Task 3.1: string/layout 추가** +- [x] **Task 3.1: string/layout 추가** - 생성: - `app/src/main/res/layout/activity_home_on_air_live.xml` - `app/src/main/res/layout/item_home_on_air_live.xml` @@ -184,13 +184,14 @@ - `app/src/main/res/values-en/strings.xml` - `app/src/main/res/values-ja/strings.xml` - 작업: - - `On Air` title, `입장 캔`, 무료 문자열은 기존 리소스가 있으면 재사용하고 부족한 값만 추가한다. + - `On Air` title, 무료 문자열은 기존 리소스가 있으면 재사용하고 부족한 값만 추가한다. - `item_home_on_air_live.xml`은 75dp profile, `LIVE HH:mm`, title, creator, price/free 영역을 포함한다. - 검증: - Run: `./gradlew :app:mergeDebugResources` - Expected: 신규 layout/string resource가 merge된다. + - Result: Figma item node `185:4509`를 `Figma_get_design_context`, `Figma_get_screenshot`으로 확인한 뒤 `75dp` profile, `LIVE` pill/time 분리, title, creator, price/free 영역을 반영했다. `--no-daemon` 단독 실행 기준 BUILD SUCCESSFUL. -- [ ] **Task 3.2: adapter 구현** +- [x] **Task 3.2: adapter 구현** - 생성: - `app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/ui/HomeOnAirLiveAdapter.kt` - 작업: @@ -200,8 +201,9 @@ - 검증: - Run: `./gradlew :app:compileDebugKotlin` - Expected: adapter가 컴파일된다. + - Result: `HomeOnAirLiveAdapter`가 `loadUrl`, paid/free visibility, item click callback을 바인딩하도록 구현했고 `--no-daemon` 실행 기준 BUILD SUCCESSFUL. -- [ ] **Task 3.3: Activity 구현과 Manifest 등록** +- [x] **Task 3.3: Activity 구현과 Manifest 등록** - 생성: - `app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveActivity.kt` - 수정: @@ -214,8 +216,9 @@ - 검증: - Run: `./gradlew :app:compileDebugKotlin` - Expected: Activity와 Manifest 등록이 컴파일된다. + - Result: `HomeOnAirLiveActivity.newIntent(context)`, 첫 페이지 로드, pagination, toast/loading/empty 표시, 기존 `getRoomDetail(roomId)` 후 입장/비밀번호/결제 흐름을 연결했고 `--no-daemon` 실행 기준 BUILD SUCCESSFUL. -- [ ] **Task 3.4: 홈 추천 라이브 더보기 진입점 연결** +- [x] **Task 3.4: 홈 추천 라이브 더보기 진입점 연결** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeLiveAdapter.kt` - `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt` @@ -226,6 +229,42 @@ - 검증: - Run: `./gradlew :app:compileDebugKotlin` - Expected: 홈 추천 더보기에서 신규 Activity 진입 코드가 컴파일된다. + - Result: `HomeLiveAdapter.setOnMoreClick()`과 `HomeMainFragment.openHomeOnAirLive()`를 연결했고 기존 `onLiveClick()`은 미구현 상태로 유지했다. `--no-daemon` 실행 기준 BUILD SUCCESSFUL. + +- [x] **Task 3.5: Phase 3 코드 리뷰 및 검증** + - 리뷰 결과: + - `HomeOnAirLiveActivity`가 `LiveViewModel.getRoomDetail()`/`enterRoom()`을 호출하지만 `liveViewModel.isLoading`, `liveViewModel.toastLiveData`를 observe하지 않아 상세 조회/입장 실패 시 기존 loading/toast 패턴이 사용자에게 전달되지 않는다. + - `GetRoomDetailResponse.isAdult` 기준의 기존 `ensureLoginAndAdultAuth` 정책이 신규 화면에 연결되어 있지 않아 성인 라이브에서 본인인증/콘텐츠 설정 가드가 누락된다. + - 기존 `LiveNowAllActivity`는 상세 응답의 `channelName != null`일 때만 입장 분기를 수행하지만, 신규 화면에는 해당 가드가 없어 종료/예약 상태 응답에서 입장을 시도할 수 있다. + - 반영: + - 로그인 확인 후 `getRoomDetail(roomId)`를 호출하고, 응답의 `isAdult` 기준으로 기존 성인 인증/성인 콘텐츠 설정 가드를 수행한다. + - `LiveViewModel.isLoading`과 `LiveViewModel.toastLiveData`를 observe하고, 목록 로딩과 입장 로딩 상태를 OR 조건으로 합쳐 `LoadingDialog`를 제어한다. + - `channelName`이 blank인 상세 응답은 입장 분기를 중단하도록 정책 함수를 추가한다. + - 검증: + - Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon` + - Result: BUILD SUCCESSFUL. + - Run: `./gradlew :app:mergeDebugResources --no-daemon` + - Result: BUILD SUCCESSFUL. + - Run: `./gradlew :app:compileDebugKotlin --no-daemon` + - Result: BUILD SUCCESSFUL. + - Run: `./gradlew :app:ktlintCheck --no-daemon` + - Result: BUILD SUCCESSFUL. + - Run: `git diff --check` + - Result: whitespace error 없음. + - 종합: 리뷰 지적사항을 반영했고 빌드/린트/단위 테스트가 모두 통과했다. + - 추가 Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveEntryPolicyTest"` + - 추가 RED Result: `canEnterHomeOnAirLiveRoom` 미구현으로 컴파일 실패를 확인했다. + - 추가 GREEN Result: `channelName`이 blank인 상세 응답에서 입장 분기를 중단하는 정책 함수를 구현한 뒤 BUILD SUCCESSFUL. + - 추가 Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon` + - 추가 Result: BUILD SUCCESSFUL. + - 추가 Run: `./gradlew :app:mergeDebugResources --no-daemon` + - 추가 Result: 최초 sandbox 실행은 `~/.gradle` wrapper lock 접근 제한으로 실패했고, 승인 실행 기준 BUILD SUCCESSFUL. + - 추가 Run: `./gradlew :app:compileDebugKotlin --no-daemon` + - 추가 Result: BUILD SUCCESSFUL. + - 추가 Run: `./gradlew :app:ktlintCheck --no-daemon` + - 추가 Result: 기존 `.editorconfig`의 `disabled_rules` deprecation 경고가 출력되었지만 BUILD SUCCESSFUL. + - 추가 Run: `git diff --check` + - 추가 Result: whitespace error 없음. --- @@ -253,3 +292,7 @@ - 2026-06-26 Phase 2 RED: production 구현 전 `HomeOnAirLiveAuthHeaderTest`, `HomeOnAirLiveMapperTest` 실행 시 신규 `data/model` symbol 미존재로 컴파일 실패를 확인했다. - 2026-06-26 Phase 2 GREEN: `HomeOnAirLiveAuthHeaderTest`, `HomeOnAirLiveMapperTest`, `HomeOnAirLiveViewModelTest` 각각 `--no-daemon` 실행 기준 BUILD SUCCESSFUL을 확인했다. - 2026-06-26 Phase 2 최종 검증: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon`, `./gradlew :app:mergeDebugResources --no-daemon`, `./gradlew :app:compileDebugKotlin --no-daemon`, `./gradlew :app:ktlintCheck --no-daemon`, `git diff --check` 모두 통과했다. +- 2026-06-27 Phase 3 검증: `./gradlew :app:mergeDebugResources --no-daemon`, `./gradlew :app:compileDebugKotlin --no-daemon`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon`, `./gradlew :app:ktlintCheck --no-daemon`, `git diff --check` 모두 통과했다. 최초 병렬 실행 중 `mergeDebugResources`가 stripped 중간 파일 경합으로 1회 실패했으나, 순차 단독 재실행에서 BUILD SUCCESSFUL을 확인했다. +- 2026-06-27 Phase 3 Figma 재검증: 리뷰 지적에 따라 `item_home_on_air_live.xml`의 title을 `Typography.Heading4`, LIVE badge를 `Typography.Caption3` 기반 pill, time/creator/price를 `Typography.Body6`로 조정했다. 이후 `./gradlew :app:mergeDebugResources --no-daemon`, `./gradlew :app:compileDebugKotlin --no-daemon`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon`, `./gradlew :app:ktlintCheck --no-daemon`, `git diff --check` 모두 통과했다. +- 2026-06-27 Phase 3 리뷰 반영: `HomeOnAirLiveActivity`에 기존 라이브 입장 정책과 동일하게 로그인 확인, `getRoomDetail(roomId)` 응답의 `isAdult` 기준 성인 인증/성인 콘텐츠 설정 가드, `LiveViewModel.isLoading/toastLiveData` 관찰을 추가했다. 이후 `./gradlew :app:mergeDebugResources --no-daemon`, `./gradlew :app:compileDebugKotlin --no-daemon`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon`, `./gradlew :app:ktlintCheck --no-daemon`, `git diff --check` 모두 통과했다. +- 2026-06-27 Phase 3 코드 리뷰 및 재검증: `HomeOnAirLiveActivity`에 `LiveViewModel` loading/toast 관찰과 `GetRoomDetailResponse.isAdult` 기준 성인 인증/성인 콘텐츠 설정 가드를 추가한 뒤 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon`, `./gradlew :app:mergeDebugResources --no-daemon`, `./gradlew :app:compileDebugKotlin --no-daemon`, `./gradlew :app:ktlintCheck --no-daemon`, `git diff --check`를 순차 실행해 모두 통과했다. diff --git a/docs/20260626_현재_진행_중인_라이브_리스트_페이지/prd.md b/docs/20260626_현재_진행_중인_라이브_리스트_페이지/prd.md index 2cb8fe4c..72d75e00 100644 --- a/docs/20260626_현재_진행_중인_라이브_리스트_페이지/prd.md +++ b/docs/20260626_현재_진행_중인_라이브_리스트_페이지/prd.md @@ -19,7 +19,7 @@ - 서버 `size`는 20으로 고정되므로 앱은 `size` query parameter를 보내지 않는다. - 리스트 아이템은 Figma 기준으로 프로필 이미지, `LIVE ${라이브 시작시간}`, 제목, 크리에이터 닉네임, 가격/무료 정보를 표시한다. - `beginDateTimeUtc`는 디바이스 Timezone으로 변환한 뒤 `HH:mm` 형태로 표시한다. -- 유료 라이브는 `ic_bar_cash`와 가격, `입장 캔` 문구를 표시한다. +- 유료 라이브는 `ic_bar_cash`와 가격을 표시한다. - 무료 라이브는 cash 아이콘을 숨기고 `무료`라고 표시한다. - 아이템 터치 시 기존 `getRoomDetail(roomId)` 조회 후 상세 응답 기준으로 입장/비밀번호/결제/성인 인증 흐름을 결정한다. - 기존 레거시 라이브 입장 정책은 직접 수정하지 않고, v2 신규 화면에서 호출/재사용한다. @@ -102,7 +102,7 @@ data class HomeOnAirLiveResponse( - `HH:mm`은 `beginDateTimeUtc`를 UTC로 파싱한 뒤 디바이스 Timezone으로 변환한 시작 시각이다. - 제목은 18sp bold, 한 줄 말줄임으로 표시한다. - 크리에이터 닉네임은 14sp regular, 회색으로 표시한다. -- 유료 라이브는 `ic_bar_cash`, 가격, `입장 캔`을 표시한다. +- 유료 라이브는 `ic_bar_cash`와 가격을 표시한다. - 무료 라이브는 cash 아이콘을 숨기고 `무료` 텍스트만 표시한다. - 이미지 로드는 기존 `loadUrl` 또는 기존 Glide 확장 관례를 따른다.