docs(live): 온에어 라이브 화면 구현을 기록한다

This commit is contained in:
2026-06-27 01:11:05 +09:00
parent 7c775efada
commit 0c1ad5c746
2 changed files with 52 additions and 9 deletions

View File

@@ -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`를 순차 실행해 모두 통과했다.

View File

@@ -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 확장 관례를 따른다.