fix(home): 라이브 전체 항목을 항상 표시한다
This commit is contained in:
@@ -1225,6 +1225,134 @@ git diff --check
|
||||
- 2026-07-31: 사용자 인터뷰에서 모든 `모두 팔로우` 동작에 확인 절차를 적용하되 현재 구현은 `최근 응원이 많은 크리에이터` 섹션만 대상으로 하는 B안을 확정했다. 기존 `HomeMainFragment`의 직접 API 호출 경로와 `V2ModalDialog`의 취소·확인·중복 클릭 방지 계약을 확인해 Phase 17을 작성했다. 이번 요청 범위에 따라 production·test·resource 구현은 시작하지 않았으며 모든 구현 및 Gate 체크박스는 미완료로 유지한다.
|
||||
- 2026-07-31: Phase 17 구현으로 `HomeMainFragment`의 응원 크리에이터 모두 팔로우 callback을 기존 즉시 `followCreators()` 호출에서 `V2ModalDialog` 확인창 표시로 변경했다. 확인 버튼에서만 기존 `homeRecommendationViewModel.followCreators(SECTION_KEY_CHEER_CREATORS, creatorIds)`를 호출하고, 취소 버튼은 기존 `R.string.cancel`과 `V2ModalDialog` 기본 닫기 동작을 재사용한다. 한국어·영어·일본어 `home_recommendation_follow_all_confirm_title`, `home_recommendation_follow_all_confirm_description`, `home_recommendation_follow_all_confirm_button` resource를 추가했다.
|
||||
|
||||
## Phase 18: 현재 진행 중인 라이브 `전체` 항목 상시 표시
|
||||
|
||||
**Phase 결과:** 메인 홈 추천 탭의 현재 진행 중인 라이브가 1개 이상이면 최대 20개의 라이브 뒤에 `전체` 항목이 항상 표시되고, 0개이면 기존처럼 라이브 섹션이 숨겨진다.
|
||||
|
||||
**선행 조건:** `prd.md`의 `2026-07-31 변경: 현재 진행 중인 라이브 전체 항목 상시 표시` 승인, 기존 `HomeLiveAdapter`의 20개 상한·`MoreViewHolder` 디자인·`HomeOnAirLiveActivity` 이동 계약 유지.
|
||||
|
||||
**Phase 완료 조건:** `P18-T1`과 `P18-GATE` 완료, Task 검증 기록과 `Verification Log`에 실제 결과 누적.
|
||||
|
||||
### 구현 항목
|
||||
|
||||
#### Task 18.1: 라이브가 1개 이상이면 `전체` 항목 추가
|
||||
|
||||
**Goal 실행 `P18-T1`:** `HomeLiveAdapter`가 빈 목록에는 항목을 만들지 않고, 라이브가 1개 이상이면 라이브 개수와 관계없이 마지막에 기존 `전체` 항목을 추가한다.
|
||||
|
||||
- **시작 조건:** Phase 18 선행 조건 충족.
|
||||
- **완료 증거:** RED/GREEN 체크박스 완료, 0개·1개·20개·21개 이상 경계 자동 검증, focused 회귀·compile·lint·diff 결과 누적.
|
||||
- **범위 밖:** 라이브 최대 표시 개수 변경, `전체` 항목 디자인·문구·클릭 목적지·로그인 가드 변경, 라이브 item 입장 흐름, 추천/전체 라이브 API 계약, 신규 abstraction·dependency 추가.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeLiveAdapter.kt`
|
||||
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt`
|
||||
- Modify: `docs/20260601_메인_홈_추천_UI와_API_연동/plan-task.md`
|
||||
|
||||
**Interfaces:**
|
||||
|
||||
- Consumes: `HomeLiveAdapter.submitItems(items: List<HomeRecommendationLiveUiModel>)`, `MAX_VISIBLE_LIVE_COUNT = 20`, 기존 `MoreViewHolder`와 `setOnMoreClick(listener: (() -> Unit)?)`.
|
||||
- Produces: `showAllItem: Boolean` 내부 상태와 `0개 -> itemCount 0`, `1~20개 -> lives + 전체`, `21개 이상 -> live 20개 + 전체` adapter 계약.
|
||||
|
||||
- [x] **RED:** `HomeMainFragmentLayoutTest`에 아래 경계 테스트를 추가한다.
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
fun `홈 라이브 어댑터는 라이브가 있으면 전체 항목을 추가한다`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val adapter = HomeLiveAdapter()
|
||||
|
||||
adapter.submitItems(emptyList())
|
||||
assertEquals(0, adapter.itemCount)
|
||||
|
||||
adapter.submitItems(listOf(liveItem(1L)))
|
||||
assertEquals(2, adapter.itemCount)
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, adapter.getItemViewType(1))
|
||||
assertEquals(
|
||||
context.getString(R.string.screen_home_theme_all),
|
||||
(viewHolder.itemView as TextView).text.toString()
|
||||
)
|
||||
|
||||
adapter.submitItems((1L..20L).map(::liveItem))
|
||||
assertEquals(21, adapter.itemCount)
|
||||
}
|
||||
```
|
||||
|
||||
- [x] **RED 확인:** 아래 focused test를 실행해 기존 `hasMore = items.size > MAX_VISIBLE_LIVE_COUNT` 조건에서는 라이브 1개의 `itemCount`가 `1`이라 `assertEquals(2, adapter.itemCount)`에서 의도대로 실패하는지 확인한다.
|
||||
|
||||
```bash
|
||||
./gradlew :app:testDebugUnitTest \
|
||||
--tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest"
|
||||
```
|
||||
|
||||
- [x] **GREEN:** `HomeLiveAdapter`의 `hasMore` 이름과 조건만 아래처럼 최소 수정한다.
|
||||
|
||||
```kotlin
|
||||
private var showAllItem: Boolean = false
|
||||
|
||||
fun submitItems(items: List<HomeRecommendationLiveUiModel>) {
|
||||
this.items = items.take(MAX_VISIBLE_LIVE_COUNT)
|
||||
showAllItem = items.isNotEmpty()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size + if (showAllItem) 1 else 0
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (showAllItem && position == itemCount - 1) VIEW_TYPE_MORE else VIEW_TYPE_LIVE
|
||||
}
|
||||
```
|
||||
|
||||
- [x] **GREEN 확인:** RED 확인과 같은 focused test를 다시 실행해 신규 0개·1개 계약과 기존 21개 표시·22개 입력 cap 테스트가 모두 성공하는지 확인한다.
|
||||
- [x] **REFACTOR:** 새 abstraction 없이 변수명과 조건 변경만 유지하고 아래 직접 영향 회귀와 품질 검증 결과를 Task 검증 기록 및 `Verification Log`에 누적한다. 공용 계약·API·Fragment 흐름을 변경하지 않는 단일 adapter 분기는 `HomeMainFragmentLayoutTest`의 0개·1개·20개·21개·22개 경계로 직접 검증하고, 최종 branch 완료 검증에서 전체 unit test도 실행한다.
|
||||
|
||||
```bash
|
||||
./gradlew :app:testDebugUnitTest \
|
||||
--tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest"
|
||||
./gradlew :app:compileDebugKotlin
|
||||
./gradlew :app:ktlintCheck
|
||||
git diff --check
|
||||
```
|
||||
|
||||
검증 기록:
|
||||
|
||||
- 2026-07-31: 구현 전 baseline `HomeMainFragmentLayoutTest` 73개가 성공했다. 신규 `홈 라이브 어댑터는 라이브가 있으면 전체 항목을 추가한다` 테스트를 추가한 RED 실행은 총 74개 중 신규 1개만 `expected:<2> but was:<1>`로 실패해 기존 `items.size > MAX_VISIBLE_LIVE_COUNT` 조건을 재현했다.
|
||||
- 2026-07-31: `HomeLiveAdapter`의 `hasMore`를 `showAllItem`으로 변경하고 `showAllItem = items.isNotEmpty()`를 적용했다. 동일 focused test 74개, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`가 모두 `BUILD SUCCESSFUL`이었고 `git diff --check`는 출력 없이 성공했다. ktlint의 `.editorconfig disabled_rules` 및 Gradle deprecation warning은 기존 경고다.
|
||||
- 2026-07-31: REFACTOR에서는 신규 abstraction 없이 테스트명을 한글 의도에 맞게 정리하고 focused test와 ktlint를 재실행해 성공을 확인했다. 최종 완료 검증으로 전체 `:app:testDebugUnitTest --no-parallel --console=plain`도 실행해 162 suites, 1,199 tests, 실패 0·오류 0·skip 0을 확인했다.
|
||||
- 2026-07-31: Phase 18 코드 리뷰에서 PRD·Task와 `HomeLiveAdapter` 및 `HomeMainFragment` 호출 흐름을 대조해 확정 발견 사항이 없음을 확인했다. focused 74 tests, debug Kotlin compile, ktlint는 성공했고, 전체 unit test를 `--rerun-tasks`로 재실행해 162 suites·1,199 tests·실패 0·오류 0·skip 0을 확인했다. `lintDebug`는 변경되지 않은 `AndroidManifest.xml:316`의 `FacebookActivity` `MissingClass`를 포함한 기존 28 errors·767 warnings로 실패했으며, 이번 production 변경 파일에는 기존 `notifyDataSetChanged()` warning 외 신규 lint error가 없었다. 문서 기록 후 `./gradlew tasks --all --console=plain`도 성공했고 결과는 `reviews/phase18-live-all-item-review.md`에 기록했다.
|
||||
|
||||
### 완료 조건
|
||||
|
||||
- [x] 빈 `lives` 입력에서 adapter item이 0개이고 기존 Fragment의 라이브 섹션 숨김 정책이 유지된다.
|
||||
- [x] 라이브가 1개 이상 20개 이하이면 모든 라이브 뒤에 `전체` 항목이 표시된다.
|
||||
- [x] 라이브가 21개 이상이면 라이브 최대 20개와 `전체` 항목 1개만 표시된다.
|
||||
- [x] 기존 `전체` 디자인·문구·클릭 목적지와 라이브 item 입장 흐름이 변경되지 않는다.
|
||||
- [x] 변경 파일이 Phase 18 Files 범위 안이고 신규 파일·dependency·commit이 생성되지 않는다.
|
||||
|
||||
### 검증 방법
|
||||
|
||||
#### Phase 18 Gate
|
||||
|
||||
**Goal 실행 `P18-GATE`:** Phase 18의 0개·1개·20개·21개 이상 경계와 기존 `전체` 항목 회귀를 최종 판정한다.
|
||||
|
||||
- **시작 조건:** `P18-T1` 체크박스와 검증 기록 완료.
|
||||
- **완료 증거:** Task 18.1 REFACTOR 명령이 모두 성공하고 아래 대조를 완료한다.
|
||||
- **범위 밖:** Gate 통과를 위한 test 삭제·완화, `HomeMainFragment`·전체 라이브 화면·API 수정, 관련 없는 홈 코드 정리.
|
||||
|
||||
대조:
|
||||
|
||||
- [x] `HomeLiveAdapter.submitItems()`가 표시 라이브를 `take(20)`으로 제한한다.
|
||||
- [x] `showAllItem`은 원본 `items.isNotEmpty()`로만 결정된다.
|
||||
- [x] 기존 `MoreViewHolder`, `createMoreView()`, `onMoreClick` 연결은 변경되지 않는다.
|
||||
- [x] Git diff가 Phase 18 Files와 승인된 PRD 범위 안에 있고 커밋이 생성되지 않았다.
|
||||
|
||||
계획 기록:
|
||||
|
||||
- 2026-07-31: 사용자 인터뷰에서 라이브 0개는 기존처럼 섹션을 숨기고 1개 이상이면 최대 20개 뒤에 `전체` 항목을 항상 표시하는 정책을 확정했다. 기존 20개 상한·`전체` 디자인·클릭 목적지·로그인 가드·API 계약을 유지하고, `HomeLiveAdapter` 내부 상태명과 조건 및 `HomeMainFragmentLayoutTest` 경계 테스트만 변경하는 Phase 18을 작성했다. production·test 구현은 시작하지 않았다.
|
||||
- 2026-07-31: Phase 18을 TDD로 구현했다. RED는 라이브 1개에서 `itemCount`가 기대 2, 실제 1로 실패했고, GREEN은 `showAllItem = items.isNotEmpty()` 최소 변경 후 focused 74개 테스트 성공으로 확인했다. 전체 1,199 tests와 compile·ktlint·diff 검증도 성공했으며 기존 `MoreViewHolder`·클릭 연결·20개 cap은 변경하지 않았다.
|
||||
|
||||
## Decision Log
|
||||
|
||||
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 Goal/문서 |
|
||||
@@ -1232,8 +1360,12 @@ git diff --check
|
||||
| 2026-07-31 | `DEC-017` | 확정 | 모든 `모두 팔로우` 동작은 공통 확인 절차를 사용하고, 현재 구현은 노출 중인 응원 크리에이터 섹션으로 제한한다. 신규 공통 abstraction 없이 기존 `V2ModalDialog`를 재사용한다. | 사용자 `deep-interview`의 B안 선택과 현재 `genreCreators` 숨김 정책 | `P17-T1`, `P17-GATE`, `prd.md`의 `2026-07-31 변경` |
|
||||
| 2026-07-31 | `DEC-018` | 확정 | Phase 7의 2026-06-05 보안 재리뷰에서 승인된 유료 미구매 원본 이미지 미로드 정책을 기준으로 삼고, commit `2d58a876`에서 재도입된 client-side blur 원본 로드를 회귀로 수정한다. | 보안 재리뷰·검증 기록, 현재 `HomePopularCommunityAdapter`와 반대 방향의 test 변경 이력 교차 검토 | `REV-P7-001`, `P7-R1` |
|
||||
| 2026-07-31 | `DEC-019` | 확정 | 두 번째 `Phase 12`와 그 하위 `Task 10.*`는 기존 기록을 보존하면서 `P12B` 계열 고유 별칭을 추가해 이후 리뷰와 회귀 작업에서 사용한다. | `work-plan-docs.md`의 Goal/Task 추적성 규칙과 현재 문서의 중복 식별자 | `REV-P12B-001`, `P12B-R1` |
|
||||
| 2026-07-31 | `DEC-020` | 확정 | 현재 진행 중인 라이브가 0개이면 섹션을 숨기고, 1개 이상이면 최대 20개 라이브 뒤에 `전체` 항목을 항상 표시한다. | 사용자 인터뷰 승인과 기존 `HomeLiveAdapter`·전체 라이브 이동 계약 확인 | `P18-T1`, `P18-GATE`, `prd.md`의 `2026-07-31 변경: 현재 진행 중인 라이브 전체 항목 상시 표시` |
|
||||
|
||||
## Verification Log
|
||||
- 2026-07-31: Phase 18 변경 코드 리뷰 및 최신 검증을 수행했다. `HomeLiveAdapter`의 0개·1~20개·21개 이상 경계와 기존 `MoreViewHolder`, 로그인 가드, `HomeOnAirLiveActivity` 이동 경로를 대조해 확정 발견 사항이 없음을 판정했다. focused 74 tests·compile·ktlint와 `--rerun-tasks` 전체 162 suites·1,199 tests가 실패 0·오류 0으로 성공했고 staged·unstaged diff check와 문서 변경 후 `./gradlew tasks --all --console=plain`도 성공했다. 프로젝트 전체 `lintDebug`는 이번 diff 밖의 기존 28 errors·767 warnings로 실패했으며 첫 오류는 `AndroidManifest.xml:316`의 `FacebookActivity` `MissingClass`다. 상세 결과는 `reviews/phase18-live-all-item-review.md`에 기록했다.
|
||||
- 2026-07-31: Phase 18 TDD와 Gate 검증을 완료했다. 구현 전 focused baseline 73개 성공 후 신규 경계 테스트가 라이브 1개에서 `expected:<2> but was:<1>`로 RED 실패했고, `HomeLiveAdapter`의 `hasMore`를 `showAllItem`으로 바꾸고 `items.isNotEmpty()` 조건을 적용한 뒤 focused 74개가 성공했다. `:app:testDebugUnitTest --no-parallel --console=plain` 전체 실행은 162 suites, 1,199 tests, 실패 0·오류 0·skip 0으로 성공했고 `:app:compileDebugKotlin`, `:app:ktlintCheck`, `git diff --check`도 성공했다. 기존 deprecation warning 외 실패는 없었으며 신규 파일·dependency·commit은 생성하지 않았다.
|
||||
- 2026-07-31: Phase 18 문서 준비 검증으로 PRD의 0개·1~20개·21개 이상 표시 계약과 Non-Goal을 `P18-T1` 및 `P18-GATE`에 대조했고 누락된 확정 요구사항이 없음을 확인했다. `P18`, `Task 18`, `showAllItem` 추적 검색과 placeholder/TODO 검색, `git diff --check`가 성공했으며 변경 파일은 `prd.md`, `plan-task.md` 두 문서뿐이다. `./gradlew tasks --all --console=plain` 최초 sandbox 실행은 사용자 Gradle cache lock 접근 제한으로 실패했고, 승인된 동일 명령 재실행은 `BUILD SUCCESSFUL`로 완료됐다. production·test 구현은 시작하지 않았고 커밋은 생성하지 않았다.
|
||||
- 2026-07-31: `REV-P7-003` 후속 `Task R7.3` / `P7-R3`를 실행했다. `HomeMainFragmentLayoutTest`의 source 문자열 검사를 제거하고 `HomePopularCommunityAdapterTest`에 실제 adapter/ViewHolder bind 회귀 2건을 추가해 잠금 유료 원본 미로드·기존 Coil 요청 해제·drawable 제거·overlay/가격 유지와 무료·구매 완료 URL 전달을 검증했다. 보안 분기 mutation에서는 잠금 test가 `HomePopularCommunityAdapterTest.kt:72`에서 의도대로 실패했고 원상 복구 후 다시 통과했다. 직접 영향 test·compile·ktlint와 전체 162 suites/1,198 tests가 실패 0·error 0으로 성공했고, 문서 반영 후 `./gradlew tasks --all --console=plain`도 BUILD SUCCESSFUL이었다. 최종 production 코드는 이번 Task에서 추가 변경하지 않았다. Phase별 리뷰를 재검색한 결과 새 확정 항목은 확인되지 않았다.
|
||||
- 2026-07-31: Phase별 리뷰 리포트 최종 문서 검증으로 `git diff --check`를 실행해 출력 없이 성공했고, `reviews/` 아래 Phase 1~17 및 별도 이력 Phase 12B 보고서 18개 존재와 `REV-P7-003` ↔ `Task R7.3` ↔ `P7-R3` 연결을 확인했다. `./gradlew tasks --all --console=plain` 최초 sandbox 실행은 사용자 Gradle cache lock 접근 제한으로 실패했으며, 승인된 동일 명령 재실행은 BUILD SUCCESSFUL로 완료되어 프로젝트 task 인식 문제와 분리했다.
|
||||
- 2026-07-31: 현재 working tree를 Phase별 리뷰 보고서와 다시 대조했다. 신규 확정 항목은 Phase 7의 유료 미구매 원본 이미지 미로드 테스트가 실제 adapter bind, 기존 request/drawable 제거, lock overlay와 가격 유지를 실행하지 않고 production source 문자열만 검사하는 회귀 보호 공백(`REV-P7-003`) 1건이다. 이를 `Task R7.3` / `P7-R3`의 미완료 실행형 회귀 테스트 보강 Task로 Phase 7에 추가했으며 production 코드는 변경하지 않았다. Task 12.2는 사용자 수동 확인 완료 상태로 Phase 5·6·8·9·10·11·12·13 리포트의 오래된 blocker/남은 항목을 현재 상태와 동기화했다.
|
||||
|
||||
Reference in New Issue
Block a user