From d719470f8cf009ab6bc24975edc1179d289302a0 Mon Sep 17 00:00:00 2001 From: klaus Date: Tue, 16 Jun 2026 14:35:51 +0900 Subject: [PATCH] =?UTF-8?q?docs(creator):=20=EC=B1=84=EB=84=90=20=ED=99=88?= =?UTF-8?q?=20=ED=83=AD=20=EC=A0=84=ED=99=98=20=EA=B2=80=EC=A6=9D=EC=9D=84?= =?UTF-8?q?=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 --- .../plan-task.md | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/20260611_크리에이터_채널_홈_탭/plan-task.md b/docs/20260611_크리에이터_채널_홈_탭/plan-task.md index a60b6478..1ad50bcc 100644 --- a/docs/20260611_크리에이터_채널_홈_탭/plan-task.md +++ b/docs/20260611_크리에이터_채널_홈_탭/plan-task.md @@ -1002,7 +1002,7 @@ > PRD `Future Tab Architecture Decision` 반영 Phase다. 후속 `라이브`, `오디오`, `시리즈`, `커뮤니티`, `팬Talk`, `후원` 탭은 API/목록/UI가 독립적이므로, 기존 단일 Activity 내부 커스텀 tab/홈 RecyclerView 구조를 탭별 Fragment를 담는 컨테이너 구조로 바꾼다. -- [ ] **Task 10.1: 컨테이너 전환 source test와 구조 경계 고정** +- [x] **Task 10.1: 컨테이너 전환 source test와 구조 경계 고정** - 수정: - `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt` - 확인: @@ -1018,8 +1018,12 @@ - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` - 기대 결과: - 구현 전에는 기존 단일 Activity tab 구조 때문에 RED 실패한다. + - 검증 기록: + - 2026-06-16: 기존 프로젝트 사용 사례를 확인한 결과 `TabLayout`은 여러 화면에서 XML ``과 `TabLayout.OnTabSelectedListener` 조합으로 쓰이고, `ViewPager2`는 `fragment_character_gallery_viewer.xml`과 `CharacterGalleryViewerDialogFragment`에서 제한적으로 쓰인다. 현재 production/test 코드에는 `FragmentStateAdapter`, `TabLayoutMediator` 사용 사례가 없어 Phase 10 컨테이너 전환에서 신규 도입될 구조 경계로 source test에 고정했다. + - 2026-06-16: `CreatorChannelActivitySourceTest`에 `activity_creator_channel.xml`이 `TabLayout`/`ViewPager2`를 가져야 하고 기존 `HorizontalScrollView`/`tab_container`/`rv_home_sections` 구조를 제거해야 한다는 RED source test를 추가했다. 또한 `CreatorChannelActivity`가 `FragmentStateAdapter` 또는 `CreatorChannelPagerAdapter`로 `binding.viewPager.adapter`를 설정하고, 홈 탭 구현을 `CreatorChannelHomeFragment`로 위임하며 `CreatorChannelHomeViewModel`/`CreatorChannelHomeSectionAdapter`/`viewModel.loadHome(creatorId)`/동적 tab `TextView` 생성 로직을 직접 소유하지 않아야 한다는 RED source test를 추가했다. + - 2026-06-16: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`를 실행해 `Phase 10 컨테이너 layout은 TabLayout과 ViewPager2를 가진다`가 `CreatorChannelActivitySourceTest.kt:78`에서, `Phase 10 Activity는 pager adapter를 사용하고 홈 탭 구현을 Fragment로 위임한다`가 `CreatorChannelActivitySourceTest.kt:94`에서 실패하는 RED를 확인했다. 실패 원인은 현재 구현이 아직 `HorizontalScrollView` 기반 커스텀 tab-bar와 Activity 직접 홈 API/section adapter 소유 구조이기 때문이며, 이는 Task 10.1의 기대 결과와 일치한다. -- [ ] **Task 10.2: 홈 탭을 `CreatorChannelHomeFragment`로 분리** +- [x] **Task 10.2: 홈 탭을 `CreatorChannelHomeFragment`로 분리** - 생성: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.kt` - `app/src/main/res/layout/fragment_creator_channel_home.xml` @@ -1039,8 +1043,13 @@ - `./gradlew :app:compileDebugKotlin` - 수동 확인: - 홈 탭 기본 진입 시 기존 홈 컨텐츠가 동일하게 표시된다. + - 검증 기록: + - 2026-06-16: RED로 `CreatorChannelActivitySourceTest`를 Task 10.2 책임 분리에 맞게 갱신했다. Activity가 `CreatorChannelHomeViewModel`/`CreatorChannelHomeSectionAdapter`/`viewModel.loadHome(creatorId)`를 직접 소유하지 않고, `CreatorChannelHomeFragment`가 `ARG_CREATOR_ID`, `newInstance(creatorId)`, `CreatorChannelHomeViewModel by viewModel()`, `CreatorChannelHomeSectionAdapter`, `viewModel.homeStateLiveData.observe(viewLifecycleOwner)`, `creatorId > 0L` guard, `viewModel.loadHome(creatorId)`를 소유해야 한다는 source 계약을 추가했다. 구현 전 실행한 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`는 새 Fragment/layout 부재와 기존 Activity 직접 소유 구조 때문에 9개 테스트가 실패해 RED를 확인했다. + - 2026-06-16: `fragment_creator_channel_home.xml`을 추가해 홈 section `RecyclerView(rv_home_sections)`를 이동하고, `activity_creator_channel.xml`에는 공통 header/title 영역과 `TabLayout(tab_layout)`, `ViewPager2(view_pager)` 컨테이너만 남겼다. `CreatorChannelHomeFragment`는 `creatorId` argument를 받아 홈 API observe, 홈 section adapter, follow/chat ViewModel 액션, schedule/audio callback forwarding을 담당하도록 추가했다. `CreatorChannelActivity`는 header/title bind, follow sheet, DM/AI chat room navigation, schedule/audio navigation, 최소 Home 1-page `FragmentStateAdapter`만 담당하도록 정리했다. + - 2026-06-16: GREEN 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `git diff --check`가 모두 PASS했다. `compileDebugKotlin`의 Kotlin/Gradle deprecation warning은 기존 경고로 이번 변경과 무관하다. 실제 기기 수동 확인은 이번 Task 10.2 검증 명령 범위에 포함되지 않아 실행하지 않았으며, 홈 탭 기본 진입 육안 확인은 Phase 10.4 또는 Phase 14 수동 검증에서 이어서 확인한다. + - 2026-06-16: reviewer gate에서 `NestedScrollView` 내부 `ViewPager2`의 `wrap_content` 측정 리스크를 blocking issue로 확인했다. `ViewPager2` 초기 높이를 `1dp`로 두고, `CreatorChannelHomeFragment`가 홈 section submit 후 `onCreatorChannelHomeContentChanged()`를 호출하면 Activity가 현재 page view를 `UNSPECIFIED` height로 측정해 `binding.viewPager.updateLayoutParams { height = measuredHeight }`로 갱신하도록 보정했다. 이 계약을 `CreatorChannelActivitySourceTest`에 추가했고, 재검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 모두 PASS했다. 병렬 Gradle 실행 중 Kotlin incremental cache 경합 로그가 있었지만 fallback compile 후 최종 `BUILD SUCCESSFUL`로 종료했다. -- [ ] **Task 10.3: 탭별 placeholder Fragment와 pager adapter 추가** +- [x] **Task 10.3: 탭별 placeholder Fragment와 pager adapter 추가** - 생성: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.kt` - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPlaceholderFragment.kt` @@ -1057,8 +1066,11 @@ - 검증 명령: - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` - `./gradlew :app:compileDebugKotlin` + - 검증 기록: + - 2026-06-16: RED로 `CreatorChannelActivitySourceTest`에 `CreatorChannelPagerAdapter`, `CreatorChannelPlaceholderFragment`, `fragment_creator_channel_placeholder.xml` source 계약을 추가했다. 구현 전 실행한 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`는 `CreatorChannelPagerAdapter`/placeholder 파일 부재와 Activity의 기존 1-page inline `FragmentStateAdapter` 구조 때문에 3개 테스트가 실패해 RED를 확인했다. + - 2026-06-16: `CreatorChannelPagerAdapter`를 추가해 `CreatorChannelTab.entries` 7개 순서를 유지하고, `Home`은 `CreatorChannelHomeFragment.newInstance(creatorId)`, 나머지 6개 탭은 `CreatorChannelPlaceholderFragment.newInstance(tab)`을 반환하도록 구현했다. `CreatorChannelPlaceholderFragment`와 `fragment_creator_channel_placeholder.xml`은 후속 탭 상세 구현 전까지 crash 없는 최소 빈 화면 역할만 하도록 추가했다. -- [ ] **Task 10.4: `TabLayoutMediator` 연결과 sticky/header 동작 재검증** +- [x] **Task 10.4: `TabLayoutMediator` 연결과 sticky/header 동작 재검증** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt` - `app/src/main/res/layout/activity_creator_channel.xml` @@ -1079,6 +1091,11 @@ - 홈 탭 컨텐츠가 Fragment 안에서 표시된다. - 홈 외 탭 선택 시 crash가 없고 placeholder가 표시된다. - 공통 header와 sticky title/tab 동작이 깨지지 않는다. + - 검증 기록: + - 2026-06-16: `CreatorChannelActivity`의 inline 1-page adapter와 수동 `TabLayout.addTab()` 호출을 제거하고, `binding.viewPager.adapter = CreatorChannelPagerAdapter(this, creatorId)`와 `TabLayoutMediator(binding.tabLayout, binding.viewPager)`를 연결했다. tab label은 `CreatorChannelTab.entries[position].labelResId`에서 가져오며, 기존 Task 10.2의 `ViewPager2` 동적 높이 보정은 page 변경 시에도 실행되도록 `ViewPager2.OnPageChangeCallback`을 등록했다. Activity destroy 시 `tabLayoutMediator.detach()`와 `unregisterOnPageChangeCallback()`을 호출해 mediator/callback을 정리한다. + - 2026-06-16: GREEN 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 모두 PASS했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation warning과 Gradle deprecation warning은 기존 경고로 이번 변경과 무관하다. 실제 기기 수동 확인은 수행하지 못했으며, 7개 탭 표시/placeholder 선택/스크롤 동작 육안 검증은 Phase 14 최종 수동 검증에서 이어서 확인한다. + - 2026-06-16: 후속 리뷰에서 `CreatorChannelHomeFragment`가 Fragment property adapter를 유지하면서 `RecyclerView.adapter`를 해제하지 않는 view tree leak 가능성, `TabLayout` sticky translation 제거로 tab-bar가 스크롤과 함께 사라지는 문제, 홈 Fragment view 파괴 시 `homeActionDelegate`가 null이 되어 공통 follow/bell/chat 액션이 no-op이 될 수 있는 문제를 확인했다. RED로 `CreatorChannelActivitySourceTest`에 `binding.rvHomeSections.adapter = null`, `binding.tabLayout.translationY = tabTranslationY.toFloat()`, `val tabBarTop = headerHeight - scrollY + tabTranslationY`, `binding.viewPager.offscreenPageLimit = CreatorChannelTab.entries.size - 1` 계약을 추가했고, 구현 전 3개 테스트 실패를 확인했다. 수정 후 `CreatorChannelHomeFragment.onDestroyView()`에서 adapter를 null로 해제하고, Activity scroll 계산에 `TabLayout` sticky translation을 복구했으며, 홈 Fragment delegate가 탭 전환만으로 사라지지 않도록 `ViewPager2.offscreenPageLimit`을 6으로 설정했다. 재검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 모두 PASS했다. + - 2026-06-16: 실제 확인 중 `ViewPager2`가 동작하지 않는 것처럼 보인다는 피드백을 받아 `binding.viewPager.isUserInputEnabled = true`로 swipe 입력을 허용하고, 홈 외 placeholder 화면이 1dp/숨김 텍스트라 전환이 보이지 않던 문제를 막기 위해 `fragment_creator_channel_placeholder.xml` 높이를 160dp로 조정하고 placeholder text를 표시하도록 변경했다. `CreatorChannelActivitySourceTest`에 swipe 허용과 visible placeholder 계약을 갱신했으며, 최초 검증 중 KSP cache corruption으로 한 차례 실패했지만 재실행 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 모두 PASS했다. ---