diff --git a/docs/20260619_크리에이터_채널_오디오_탭/plan-task.md b/docs/20260619_크리에이터_채널_오디오_탭/plan-task.md index 957f7c9a..d507f24a 100644 --- a/docs/20260619_크리에이터_채널_오디오_탭/plan-task.md +++ b/docs/20260619_크리에이터_채널_오디오_탭/plan-task.md @@ -453,7 +453,7 @@ ### Phase 5: Adapter, item bind, theme tab, sort UI 구현 -- [ ] **Task 5.1: 라이브 다시듣기 adapter를 공통 오디오 콘텐츠 adapter로 rename/move** +- [x] **Task 5.1: 라이브 다시듣기 adapter를 공통 오디오 콘텐츠 adapter로 rename/move** - move/rename: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveReplayAdapter.kt` → `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelAudioContentAdapter.kt` @@ -479,8 +479,14 @@ - `./gradlew :app:compileDebugKotlin` - 기대 결과: - 오디오 layout/source 테스트, 기존 라이브 다시듣기 layout/source 테스트, 컴파일이 모두 PASS한다. + - 검증 기록: + - 2026-06-19 `CreatorChannelLiveReplayAdapter`를 `creator/channel/ui/CreatorChannelAudioContentAdapter`로 move/rename하고, item bind model/status를 `creator/channel/model/CreatorChannelAudioContentUiModel`, `CreatorChannelAudioContentStatus`로 공통화했다. + - 2026-06-19 `CreatorChannelLiveMappers.toReplayUiModel()`과 `CreatorChannelAudioMappers.toAudioContentUiModels()`가 공통 item model/status를 반환하도록 수정했고, live/audio Fragment layout/source test의 adapter 경로와 mapper test import를 공통 이름 기준으로 갱신했다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioFragmentLayoutTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. + - 2026-06-19 `./gradlew :app:compileDebugKotlin --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. -- [ ] **Task 5.2: `CapsuleTabBarView`로 theme tab-bar 연결** +- [x] **Task 5.2: `CapsuleTabBarView`로 theme tab-bar 연결** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/audio/CreatorChannelAudioFragment.kt` - 작업: @@ -495,8 +501,12 @@ - `./gradlew :app:mergeDebugResources` - 기대 결과: - theme 선택 테스트와 resource merge가 PASS한다. + - 검증 기록: + - 2026-06-19 `CreatorChannelAudioFragment`에서 `CapsuleTabBarView.setMenus()` 표시 상태에 더해 `setOnTabSelectedListener`를 연결하고, 선택 index를 `CreatorChannelAudioThemeUiModel.themeId`로 역매핑해 `viewModel.changeTheme(themeId)`를 호출하도록 구현했다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. + - 2026-06-19 `./gradlew :app:mergeDebugResources --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. -- [ ] **Task 5.3: Sort-bar와 sort popup 연결** +- [x] **Task 5.3: Sort-bar와 sort popup 연결** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/audio/CreatorChannelAudioFragment.kt` - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt` @@ -516,8 +526,13 @@ - `./gradlew :app:compileDebugKotlin` - 기대 결과: - 정렬 변경 테스트와 컴파일이 PASS한다. + - 검증 기록: + - 2026-06-19 Phase 3에서 공통화된 `CreatorChannelSortPopup`을 오디오 Sort-bar에 연결했다. Sort-bar 클릭 시 현재 `Content` 상태 기준 popup을 표시하고, option 선택 시 `viewModel.changeSort(sort)`를 호출한다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioFragmentLayoutTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelPagerAdapterTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. + - 2026-06-19 `./gradlew :app:compileDebugKotlin --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. -- [ ] **Task 5.4: 소장률 card bind 구현** +- [x] **Task 5.4: 소장률 card bind 구현** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/audio/CreatorChannelAudioFragment.kt` - 작업: @@ -530,12 +545,16 @@ - `./gradlew :app:compileDebugKotlin` - 기대 결과: - 소장률 mapper 테스트와 컴파일이 PASS한다. + - 검증 기록: + - 2026-06-19 Phase 4에서 작성된 소장률 card bind를 유지하면서, 오디오 Fragment가 Activity Host의 `isCreatorChannelOwner()` 값을 `viewModel.loadAudio(creatorId, isOwner)`에 전달하도록 연결해 본인 채널 소장률 숨김 정책이 실제 탭 진입에도 반영되도록 했다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelPagerAdapterTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. + - 2026-06-19 `./gradlew :app:compileDebugKotlin --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. --- ### Phase 6: 탭 연결, Activity callback, owner CTA, pagination 통합 -- [ ] **Task 6.1: 오디오 탭을 pager에 연결** +- [x] **Task 6.1: 오디오 탭을 pager에 연결** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.kt` - `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapterTest.kt` @@ -546,8 +565,11 @@ - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelPagerAdapterTest"` - 기대 결과: - pager adapter 테스트가 PASS한다. + - 검증 기록: + - 2026-06-19 `CreatorChannelPagerAdapter`에서 `CreatorChannelTab.Audio -> CreatorChannelAudioFragment.newInstance(creatorId)` 분기를 추가하고, `CreatorChannelPagerAdapterTest`는 Home/Live/Audio 실제 Fragment와 나머지 placeholder 정책을 검증하도록 갱신했다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelPagerAdapterTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. -- [ ] **Task 6.2: Activity host callback 연결** +- [x] **Task 6.2: Activity host callback 연결** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt` - `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt` @@ -560,8 +582,12 @@ - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` - 기대 결과: - Activity source test가 PASS한다. + - 검증 기록: + - 2026-06-19 `CreatorChannelAudioFragment.Host`를 추가하고 `CreatorChannelActivity`가 이를 구현하도록 연결했다. 오디오 item click은 `startAudioContentDetail(audioContentId)`로 이동하고, 오디오 content changed는 `updateViewPagerHeight()`와 현재 탭 load-more 재평가를 호출한다. + - 2026-06-19 live 전용 scroll bottom helper를 `calculateCreatorChannelRemainingScroll`, `postCheckCreatorChannelCurrentTabNeedsMore`, `checkCreatorChannelCurrentTabNeedsMore`, `notifyCurrentCreatorChannelTabScrolledToBottom` 등 공통 이름으로 확장하고 Live/Audio 현재 탭에 따라 각 Fragment load-more hook을 호출하도록 했다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioPaginationTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. -- [ ] **Task 6.3: owner CTA를 공통 이름으로 rename하고 오디오 탭에 재사용** +- [x] **Task 6.3: owner CTA를 공통 이름으로 rename하고 오디오 탭에 재사용** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt` - `app/src/main/res/layout/activity_creator_channel.xml` @@ -580,8 +606,13 @@ - `./gradlew :app:mergeDebugResources` - 기대 결과: - source test와 resource merge가 PASS한다. + - 검증 기록: + - 2026-06-19 `activity_creator_channel.xml`의 live 전용 owner CTA id를 `layout_creator_channel_owner_cta`, `btn_creator_channel_owner_cta`, `iv_creator_channel_owner_cta`, `tv_creator_channel_owner_cta` 공통 id로 rename했다. + - 2026-06-19 `CreatorChannelActivity.updateOwnerCtaVisibility()`가 현재 탭에 따라 Live이면 `ic_new_create_live`/`creator_channel_live_start_button`/`onOwnerFabLiveClicked()`, Audio이면 `ic_new_upload_audio`/`creator_channel_audio_upload_button`/`onOwnerFabAudioClicked()`를 사용하도록 구현했다. CTA visibility 변경은 Live/Audio Fragment의 하단 padding hook으로 전달한다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioPaginationTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. + - 2026-06-19 `./gradlew :app:mergeDebugResources --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. -- [ ] **Task 6.4: pagination 통합** +- [x] **Task 6.4: pagination 통합** - 수정: - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/audio/CreatorChannelAudioFragment.kt` - `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/audio/CreatorChannelAudioViewModel.kt` @@ -594,6 +625,10 @@ - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` - 기대 결과: - pagination 테스트와 Activity source test가 PASS한다. + - 검증 기록: + - 2026-06-19 `CreatorChannelAudioFragment.onCreatorChannelAudioScrolledToBottom()`을 추가해 Activity 공통 scroll-to-bottom hook에서 현재 탭이 Audio일 때 `viewModel.loadMore()`를 호출하도록 연결했다. + - 2026-06-19 `CreatorChannelAudioFragment`가 pagination error message를 Toast로 표시한 뒤 `viewModel.consumePaginationErrorMessage()`를 호출하도록 구현해 기존 목록 유지 + error consume 계약을 UI에 연결했다. + - 2026-06-19 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioPaginationTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. --- @@ -662,3 +697,12 @@ - 2026-06-19 Phase 3 코드 리뷰 재검증으로 `git diff --check` 실행 결과 whitespace error 없음. - 2026-06-19 Phase 4 코드 리뷰로 `CreatorChannelAudioFragment.kt`, `fragment_creator_channel_audio.xml`, `item_creator_channel_audio_content.xml`, `CreatorChannelSortPopup.kt`, `CreatorChannelSortModels.kt`, 오디오/라이브 layout test 변경을 확인했다. Phase 4 범위에서 추가 blocker는 발견하지 않았다. - 2026-06-19 Phase 4 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioFragmentLayoutTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 실행 결과 모두 BUILD SUCCESSFUL 또는 whitespace error 없음. +- 2026-06-19 Phase 5/6 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. +- 2026-06-19 Phase 5/6 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Audio*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. +- 2026-06-19 Phase 5/6 회귀 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false` 실행 결과 BUILD SUCCESSFUL. +- 2026-06-19 Phase 5/6 리소스/컴파일/스타일 검증으로 `./gradlew :app:mergeDebugResources --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:compileDebugKotlin --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:ktlintCheck --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `git diff --check` 실행 결과 모두 BUILD SUCCESSFUL 또는 whitespace error 없음. ktlint 실행 중 기존 `.editorconfig`의 `disabled_rules` deprecation 경고가 출력됐으나 실패는 발생하지 않았다. +- 2026-06-19 Phase 5/6 리뷰 게이트에서 오디오 탭이 header 확정 전 `isOwner=false`로 선로드될 수 있는 문제와 Audio empty/CTA viewport 보정 및 pagination error 재평가 loop 가능성이 blocker로 지적됐다. 후속 수정으로 `CreatorChannelAudioFragment`의 즉시 로드를 제거하고 `onCreatorChannelAudioTabSelected()`에서 현재 Host owner 상태로 로드하도록 변경했으며, `CreatorChannelActivity`는 Audio 탭 선택 및 header 변경 시 해당 진입점을 호출한다. +- 2026-06-19 Phase 5/6 리뷰 후속 수정으로 `CreatorChannelAudioFragment`에 empty min-height hook, `CreatorChannelAudioContentLayoutKey` 기반 content changed guard, Audio viewport height 전달을 추가해 empty/CTA 보정과 pagination error consume 후 즉시 재요청 가능성을 차단했다. +- 2026-06-19 Phase 5/6 리뷰 후속 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Audio*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:mergeDebugResources --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:compileDebugKotlin --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:ktlintCheck --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `git diff --check` 실행 결과 모두 BUILD SUCCESSFUL 또는 whitespace error 없음. +- 2026-06-19 Phase 5/6 후속 리뷰에서 같은 `creatorId`로 `isOwner=false` 선로드 후 header 확정으로 `isOwner=true`가 전달돼도 `CreatorChannelAudioViewModel.loadAudio()`가 early return하는 owner race가 추가 blocker로 지적됐다. `loadAudio()`의 skip 조건을 `creatorId`, `isOwner`, 기존 state가 모두 동일한 경우로 제한하고, `CreatorChannelAudioViewModelTest`에 같은 creatorId라도 owner 상태가 바뀌면 첫 페이지를 재조회하고 소장률이 `null`로 갱신되는 회귀 테스트를 추가했다. +- 2026-06-19 owner race 후속 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.CreatorChannelAudioViewModelTest" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.audio.*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Audio*" --tests "kr.co.vividnext.sodalive.v2.creator.channel.*" --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:mergeDebugResources --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:compileDebugKotlin --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `./gradlew :app:ktlintCheck --no-daemon -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false`, `git diff --check` 실행 결과 모두 BUILD SUCCESSFUL 또는 whitespace error 없음.