30 KiB
크리에이터 채널 라이브 탭 구현 계획/TASK
For agentic workers: 각 단계는 체크박스(
- [ ])로 추적하고, 완료 즉시- [x]로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다.
Goal: GET /api/v2/creator-channels/{creatorId}/live 응답을 기반으로 크리에이터 채널의 라이브 탭에 현재 라이브, 라이브 다시듣기 목록, 정렬, pagination, 본인 채널 전용 하단 라이브 시작하기 CTA를 표시한다.
Architecture: 기존 CreatorChannelActivity의 ViewPager2/CreatorChannelPagerAdapter 구조를 유지하고, CreatorChannelTab.Live의 placeholder를 신규 CreatorChannelLiveFragment로 교체한다. 라이브 탭 전용 Fragment/ViewModel/mapper/UI model/adapter/popup은 kr.co.vividnext.sodalive.v2.creator.channel.live 하위에 둔다. API/Repository는 홈 탭과 라이브 탭이 함께 쓰는 채널 공통 계층으로 보고 기존 CreatorChannelHomeApi/CreatorChannelHomeRepository를 CreatorChannelApi/CreatorChannelRepository로 rename한다. 홈 탭에서 이미 쓰는 CreatorChannelLiveResponse, CreatorChannelAudioContentResponse, 본인 판정, 라이브 시작 진입 흐름은 가능한 한 재사용한다.
Tech Stack: Kotlin, Android XML Views, ViewBinding, RecyclerView, Retrofit, Gson, RxJava3, Koin, JUnit4/Robolectric local unit test.
전제와 성공 기준
- PRD:
docs/20260617_크리에이터_채널_라이브_탭/prd.md - 기존 채널 컨테이너:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt - 기존 탭 adapter:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.kt - 기존 채널 API/DTO/Repository:
- rename 대상:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.kt - rename 대상:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt - 유지/확장:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt
- rename 대상:
- 별도
CreatorChannelLiveApi,CreatorChannelLiveRepository는 생성하지 않는다. - Figma:
- 전체:
290:8945 - Sort-bar:
290:8949 - 현재 진행 중인 라이브:
290:8950 - 라이브 다시듣기 item:
290:8954,290:8956 - 정렬 컨텍스트 메뉴:
290:9041 - 본인 채널 하단 CTA:
665:19359,665:19371
- 전체:
- 첫 페이지
page는0이다. - 다음 페이지는 마지막 성공 응답의
page + 1로 요청한다. ContentSort기본값은LATEST이다.isOwned == true와isRented == true가 동시에 내려오면소장중을 우선 표시한다.seriesName은 라이브 다시듣기 item에 표시하지 않는다.isFirstContent,isOriginalSeries는 기존 오디오 item 정책과 동일하게 매핑한다.- drawable 리소스는 기존 파일을 재사용한다.
ic_new_sortic_new_shield_smallic_new_player_playic_new_create_live
- 구현 완료 후 최소 다음 명령을 실행한다.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin./gradlew :app:ktlintCheck
Figma 참조 필요 Phase
- Phase 1: 부분 참조
- 기존 코드 경계와 리소스 존재 여부 확인이 중심이며, Figma는 PRD 기준만 확인한다.
- Phase 2: Figma 참조 불필요
- API/DTO/Repository/ViewModel 상태 모델은 서버 계약과 기존 코드 패턴을 따른다.
- Phase 3: 부분 참조
- mapper와 presenter 정책은 PRD와 Figma item variant의 상태 표시를 함께 확인한다.
- Phase 4: 필수 참조
fragment_creator_channel_live.xml, sort-bar, current live card, replay item layout은 Figma290:8949,290:8950,290:8954,290:8956을 기준으로 구현한다.
- Phase 5: 필수 참조
- 정렬 컨텍스트 메뉴는 Figma
290:9041기준으로 구현한다.
- 정렬 컨텍스트 메뉴는 Figma
- Phase 6: 필수 참조
- 본인 채널 하단 CTA는 Figma
665:19359,665:19371기준으로 구현한다.
- 본인 채널 하단 CTA는 Figma
- Phase 7: 부분 참조
- 탭 연결, 화면 이동, pagination 동작은 기존 코드 패턴 중심으로 검증한다.
- Phase 8: 필수 참조
- 최종 수동 화면 검증은 PRD의 모든 Figma 노드와 실제 화면을 대조한다.
파일 구조
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.ktCreatorChannelTab.Live를 신규CreatorChannelLiveFragment로 연결한다.
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt- 라이브 탭 UI, adapter, sort menu, pagination, CTA click 연결을 담당한다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModel.kt- 라이브 탭 API 호출, 정렬 변경, pagination 상태, loading/error/content 상태를 관리한다.
- rename:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.kt- 홈 API와 라이브 API endpoint를 함께 가진 채널 공통 API로 변경한다.
- rename:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt- 홈 API, 라이브 API, 팔로우, 대화, 후원, 신고 등 채널 공통 동작을 제공한다.
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.ktCreatorChannelLiveTabResponse,ContentSort를 추가하고CreatorChannelAudioContentResponse에 라이브 탭 전용 필드isAdult,isOwned,isRented를 서버 계약에 맞춰 추가한다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveUiModels.kt- sort option, replay item status, pagination 상태, CTA 노출 여부를 순수 UI model로 정의한다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveMappers.kt- DTO를 UI model로 변환하고 소장/대여/무료/가격/포인트/19금 상태를 결정한다.
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveReplayAdapter.kt- 라이브 다시듣기 목록 RecyclerView adapter를 담당한다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.kt- Sort-bar anchor 기준 컨텍스트 메뉴 표시를 담당한다.
- 생성:
app/src/main/res/layout/fragment_creator_channel_live.xml- sort-bar, current live card container, replay RecyclerView, owner CTA를 포함한다.
- 생성:
app/src/main/res/layout/item_creator_channel_live_replay.xml- 라이브 다시듣기 item layout이다.
- 생성 후보:
app/src/main/res/layout/view_creator_channel_live_sort_menu.xml- 정렬 컨텍스트 메뉴를 XML로 분리할 때만 추가한다.
- 수정:
app/src/main/res/values/strings.xml- 정렬 label,
소장중,대여중,라이브 시작하기, empty/error 문구를 추가한다.
- 정렬 label,
- 수정:
app/src/main/res/values-en/strings.xml,app/src/main/res/values-ja/strings.xml- 신규 문자열의 다국어 값을 추가한다.
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt- 신규 ViewModel/API/Repository binding이 필요하면 추가한다.
- 테스트 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveMapperTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLivePaginationTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModelTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragmentLayoutTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapterTest.kt
Phase 1: 기존 구조 확인과 작업 경계 고정
-
Task 1.1: 크리에이터 채널 탭 구조와 본인 판정 경로 확인
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeMappers.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeUiModels.kt
- 작업:
CreatorChannelTab.Live가 현재 placeholder로 연결되는 지점을 확인한다.- 본인 여부(
isOwner)가 Activity와 탭 Fragment로 전달되는 기존 경로를 확인한다. - 라이브 시작 진입이 기존
CreatorChannelActivity의onOwnerFabLiveClicked()또는LiveRoomCreateActivity경로를 재사용할 수 있는지 확인한다.
- 검증:
- 라이브 탭 구현이 홈 탭 section adapter를 변경하지 않고 독립 Fragment로 추가 가능한지 기록한다.
- 검증 기록:
- 2026-06-17:
CreatorChannelPagerAdapter는 현재CreatorChannelTab.Home만CreatorChannelHomeFragment.newInstance(creatorId)로 연결하고,CreatorChannelTab.Live를 포함한 나머지 탭은CreatorChannelPlaceholderFragment.newInstance(tab)로 처리함을 확인했다. 따라서 Phase 7에서 Live 탭만 신규 Fragment로 교체해도 홈 탭 section adapter 변경 없이 독립 추가 가능하다. - 2026-06-17: 본인 여부는
CreatorChannelHomeMappers.toUiContent()에서creator.creatorId == currentMemberId로 계산되어CreatorChannelHeaderUiModel.isOwner와 donation section에 전달되고,CreatorChannelActivity는 이 값을 owner FAB/상단 액션/DM/후원 분기 조건으로 사용함을 확인했다. - 2026-06-17: 라이브 시작 진입은
CreatorChannelActivity.onOwnerFabLiveClicked()가liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))를 호출하는 기존 경로를 사용하며, 생성 결과는homeActionDelegate?.refreshHome()후Constants.EXTRA_ROOM_ID,Constants.EXTRA_ROOM_CHANNEL_NAME에 따라CreatorChannelLiveCoordinator.enterLiveRoom()또는 생성 완료 toast로 처리됨을 확인했다.
- 2026-06-17:
- 확인:
-
Task 1.2: 기존 오디오 item 정책과 drawable/string 리소스 확인
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeAudioContentCardView.ktapp/src/main/res/layout/item_creator_channel_home_audio_content.xmlapp/src/main/java/kr/co/vividnext/sodalive/v2/widget/AudioContentTag.ktapp/src/main/res/drawable-mdpi/ic_new_sort.pngapp/src/main/res/drawable-mdpi/ic_new_shield_small.pngapp/src/main/res/drawable-mdpi/ic_new_player_play.pngapp/src/main/res/drawable-mdpi/ic_new_create_live.png
- 작업:
isFirstContent,isOriginalSeries, point/free/original tag의 기존 표시 정책을 정리한다.- 라이브 다시듣기 item에서
seriesName은 표시하지 않는다는 PRD 결정을 재확인한다.
- 검증:
- 위 4개 drawable 리소스가 존재함을 확인한다.
- 검증 기록:
- 2026-06-17: 기존 홈 오디오 item은
CreatorChannelHomeAudioContentCardView.bind()에서isOriginalSeries == true이면 original tag,isPointAvailable이면 point tag,isFirstContent이면 first tag,price <= 0이면 free tag를 표시한다. secondary text는 기존 홈 카드에서duration과seriesName을 조합하지만, 라이브 다시듣기 item에서는 PRD/계획 기준에 따라seriesName을 표시하지 않는 것으로 재확인했다. - 2026-06-17:
AudioContentTag의 top tag 순서는Original,First, bottom tag 순서는Point,Free로 정의되어 있음을 확인했다. - 2026-06-17:
test -f로app/src/main/res/drawable-mdpi/ic_new_sort.png,ic_new_shield_small.png,ic_new_player_play.png,ic_new_create_live.png가 모두 존재함을 확인했다.
- 2026-06-17: 기존 홈 오디오 item은
- 확인:
-
Task 1.3: 채널 공통 API/Repository rename
- rename:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.ktapp/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt- 기타
CreatorChannelHomeApi,CreatorChannelHomeRepositoryimport 참조 파일
- 작업:
- class/interface 이름을
CreatorChannelApi,CreatorChannelRepository로 변경한다. - 기존 홈 탭 동작은 변경하지 않는다.
- 별도
CreatorChannelLiveApi,CreatorChannelLiveRepository는 만들지 않는다.
- class/interface 이름을
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"./gradlew :app:compileDebugKotlin
- 기대 결과:
- rename 후 기존 홈 탭 ViewModel 테스트와 컴파일이 PASS한다.
- 검증 기록:
- 2026-06-17: rename-only 변경으로
CreatorChannelHomeApi.kt/CreatorChannelHomeRepository.kt를 각각CreatorChannelApi.kt/CreatorChannelRepository.kt로 변경하고 interface/class/import/DI/test 참조를 갱신했다. 홈 endpointGET /api/v2/creator-channels/{creatorId}/home와 기존 repository method 동작은 변경하지 않았다. - 2026-06-17: 신규 동작 추가가 없는 rename-only 작업이므로 RED 테스트 신규 작성 대상에서 제외했다. 기존 회귀 검증은 아래 명령 실행 결과로 누적한다.
- 2026-06-17: 최초 병렬 검증 실행 중
:app:kspDebugKotlin이 KSP incremental cache(app/build/kspCaches/debug) 경합/손상으로 실패했다. 생성물 캐시만 삭제한 뒤 순차 재실행했다. - 2026-06-17:
./gradlew :app:compileDebugKotlin순차 재실행 결과BUILD SUCCESSFUL로 통과했다. 기존 deprecation/annotation 경고는 출력되었으나 rename 변경과 무관하다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"순차 재실행 결과BUILD SUCCESSFUL로 통과했다.
- 2026-06-17: rename-only 변경으로
- rename:
Phase 2: API/DTO/Repository/ViewModel 계약 추가
-
Task 2.1: 라이브 탭 DTO와
ContentSort추가- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt
- 작업:
CreatorChannelLiveTabResponse를@Keep,@SerializedName기반 data class로 추가한다.ContentSortenum에LATEST,POPULAR,OWNED,PRICE_HIGH,PRICE_LOW를 추가한다.- 기존
CreatorChannelAudioContentResponse에isAdult,isOwned,isRented필드를 추가할 때 홈 탭 API 하위 호환성이 깨지지 않는지 확인한다. - 하위 호환이 필요하면 라이브 탭 전용 DTO 분리 또는 nullable/default 정책을 테스트로 고정한다.
- 검증 명령:
./gradlew :app:compileDebugKotlin
- 기대 결과:
- DTO 추가 후 컴파일된다.
- 수정:
-
Task 2.2: 라이브 탭 endpoint와 Repository method 추가
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt
- 작업:
@GET("/api/v2/creator-channels/{creatorId}/live")endpoint를 추가한다.- query parameter
page,size,sort를 전달한다. sort는ContentSort.name또는 Retrofit enum 변환의 기존 정책을 확인해 서버 값이LATEST등 대문자로 나가도록 한다.
- 검증 명령:
./gradlew :app:compileDebugKotlin
- 기대 결과:
- API/Repository가 기존 Koin graph와 충돌 없이 컴파일된다.
- 수정:
-
Task 2.3: ViewModel RED 테스트 작성
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModelTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLivePaginationTest.kt
- 작업:
- 최초 로딩이
page=0,sort=LATEST로 호출되는지 검증한다. hasNext == true일 때page + 1로 다음 페이지를 요청하는지 검증한다.- loading 중 중복 load-more 요청이 막히는지 검증한다.
- 정렬 변경 시 목록과 page가 초기화되는지 검증한다.
- 선택 중인 정렬을 다시 선택하면 API를 재호출하지 않는지 검증한다.
- 최초 로딩이
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLivePaginationTest"
- 기대 결과:
- ViewModel 미구현 상태에서 RED 실패한다.
- 생성:
-
Task 2.4:
CreatorChannelLiveViewModel구현- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModel.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
- 작업:
- initial loading, content, empty, error, pagination loading, pagination error 상태를 정의한다.
page=0,size기본값,sort=LATEST초기값을 적용한다.- 정렬 변경과 pagination 요청 중복 방지 로직을 구현한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLivePaginationTest"
- 기대 결과:
- ViewModel/pagination 테스트가 PASS한다.
- 생성:
Phase 3: UI model과 상태 표시 mapper 구현
-
Task 3.1: 라이브 다시듣기 표시 정책 RED 테스트 작성
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveMapperTest.kt
- 작업:
isOwned && isRented동시 true면소장중상태가 선택되는지 검증한다.price == 0이면 무료 tag와 play CTA 상태가 선택되는지 검증한다.isAdult == true이면ic_new_shield_small표시 상태가 선택되는지 검증한다.isPointAvailable == true이면 point tag 표시 상태가 선택되는지 검증한다.seriesName은 secondary text에 포함되지 않는지 검증한다.isFirstContent,isOriginalSeries는 기존 오디오 item 정책과 동일한 tag 상태로 매핑되는지 검증한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"
- 기대 결과:
- mapper 미구현 상태에서 RED 실패한다.
- 생성:
-
Task 3.2: UI model/mapper 구현
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveUiModels.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveMappers.kt
- 작업:
- sort label resource, replay item CTA/status, tag 상태, current live 상태를 UI model로 분리한다.
- 가격/포인트/소장중/대여중/play button 상태 우선순위를 순수 함수로 고정한다.
ContentSort와 문자열 리소스 매핑을 구현한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"
- 기대 결과:
- mapper 테스트가 PASS한다.
- 생성 후보:
Phase 4: 라이브 탭 Fragment와 목록 UI 구현
-
Task 4.1: Fragment layout과 replay item layout 추가
- 생성:
app/src/main/res/layout/fragment_creator_channel_live.xmlapp/src/main/res/layout/item_creator_channel_live_replay.xml
- 수정:
app/src/main/res/values/strings.xmlapp/src/main/res/values-en/strings.xmlapp/src/main/res/values-ja/strings.xml
- 작업:
- Figma 기준 sort-bar, current live card, replay list, owner CTA 영역을 배치한다.
- replay item은 88dp 썸네일, title 최대 2줄, duration 1줄, 우측 price/play/status 영역을 포함한다.
ic_new_shield_small,ic_new_player_play,ic_new_sort,ic_new_create_live를 layout 또는 binding에서 사용 가능하게 준비한다.
- 검증 명령:
./gradlew :app:mergeDebugResources
- 기대 결과:
- 신규 layout/string/drawable 참조가 resource merge에 성공한다.
- 생성:
-
Task 4.2: Adapter와 Fragment 구현
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveReplayAdapter.kt
- 작업:
- ViewModel 상태를 관찰해 sort-bar, current live card, replay list, loading/empty/error를 갱신한다.
- replay item click은 기존 오디오 컨텐츠 상세/재생 진입 정책을 확인해 연결한다.
- current live card click은 기존 홈 탭 라이브 진입 정책을 재사용한다.
- RecyclerView scroll listener로 하단 접근 시 ViewModel load-more를 호출한다.
- 검증 명령:
./gradlew :app:compileDebugKotlin
- 기대 결과:
- Fragment/adapter가 컴파일된다.
- 생성:
-
Task 4.3: Fragment layout 테스트 추가
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragmentLayoutTest.kt
- 작업:
fragment_creator_channel_live.xml에 sort-bar, RecyclerView, owner CTA가 존재하는지 검증한다.item_creator_channel_live_replay.xml에 19금 badge, point/free tag container, price/play/status 영역이 존재하는지 검증한다.ic_new_*리소스 참조가 layout 또는 코드 상수로 연결되는지 검증한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"
- 기대 결과:
- layout 테스트가 PASS한다.
- 생성:
Phase 5: 정렬 컨텍스트 메뉴 구현
-
Task 5.1: Sort popup 구현
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.ktapp/src/main/res/layout/view_creator_channel_live_sort_menu.xml
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt
- 작업:
- Sort-bar 정렬 영역 아래에 Figma
290:9041형태의 컨텍스트 메뉴를 표시한다. - 현재 선택 항목은 focused 배경으로 표시한다.
- 메뉴 외부 터치, 같은 정렬 재선택, 새 정렬 선택 시 메뉴를 닫는다.
- 새 정렬 선택 시 ViewModel에 정렬 변경을 전달한다.
- Sort-bar 정렬 영역 아래에 Figma
- 검증:
- 작은 화면에서 메뉴가 화면 밖으로 벗어나지 않도록 위치 보정 기준을 코드에 남긴다.
- 생성 후보:
-
Task 5.2: Sort 동작 테스트 보강
- 수정:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModelTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveMapperTest.kt
- 작업:
ContentSort별 label resource 매핑을 검증한다.- 정렬 변경 시 첫 페이지가 다시 로딩되는지 검증한다.
- 같은 정렬 재선택은 API 재호출을 하지 않는지 검증한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"
- 기대 결과:
- sort 관련 테스트가 PASS한다.
- 수정:
Phase 6: 본인 채널 하단 CTA와 라이브 시작 진입 연결
-
Task 6.1: 본인 CTA 노출과 inset 처리 구현
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.ktapp/src/main/res/layout/fragment_creator_channel_live.xml
- 작업:
- 본인 채널일 때만 하단 CTA를 표시한다.
- 타인 채널 또는 본인 여부 로딩 전에는 CTA를 숨긴다.
- CTA 표시 시 RecyclerView 하단 padding을 추가해 마지막 item이 CTA에 가려지지 않도록 한다.
- navigation bar bottom inset을 CTA 영역에 반영한다.
- 버튼 icon은
ic_new_create_live, label은라이브 시작하기문자열 리소스를 사용한다.
- 검증 명령:
./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin
- 기대 결과:
- CTA resource와 inset 코드가 컴파일된다.
- 수정:
-
Task 6.2: 기존 라이브 시작 플로우 연결
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/live/room/create/LiveRoomCreateActivity.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt- 필요 시
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt
- 작업:
CreatorChannelActivity의 기존 owner FAB live action과 같은 진입 경로를 재사용한다.- 중복 터치를 방지한다.
- 라이브 생성 완료 후 기존 홈 refresh/라이브룸 진입 정책과 충돌하지 않도록 처리한다.
- 검증:
- 라이브 시작 진입 대상 Activity/Fragment와 전달 extra를 계획 문서 해당 Task의
검증 기록에 남긴다.
- 라이브 시작 진입 대상 Activity/Fragment와 전달 extra를 계획 문서 해당 Task의
- 확인:
Phase 7: 탭 연결과 통합 동작
-
Task 7.1:
CreatorChannelTab.Live를 실제 Fragment로 연결- 수정:
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
- 작업:
- Live 탭 position에서
CreatorChannelLiveFragment.newInstance(creatorId)를 반환한다. - 나머지 탭은 기존 placeholder 정책을 유지한다.
- Live 탭 position에서
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelPagerAdapterTest"
- 기대 결과:
- Live 탭만 실제 Fragment로 연결되고 나머지 placeholder 정책은 유지된다.
- 수정:
-
Task 7.2: DI와 lifecycle 통합
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt
- 작업:
- 신규 ViewModel/API/Repository injection이 기존 홈 탭과 충돌하지 않는지 확인한다.
- Fragment 재생성 후 정렬, page, 목록 상태가 ViewModel에 유지되는지 확인한다.
- 탭 전환 시 중복 최초 API 호출이 발생하지 않도록 초기 로딩 조건을 정리한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"./gradlew :app:compileDebugKotlin
- 기대 결과:
- Live 탭 관련 테스트와 컴파일이 PASS한다.
- 수정:
Phase 8: 최종 검증과 문서 기록
-
Task 8.1: 자동 검증 실행
- 실행 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin./gradlew :app:ktlintCheck
- 기대 결과:
- 모든 명령이
BUILD SUCCESSFUL로 통과한다.
- 모든 명령이
- 검증 기록:
- 실행 일시, 명령, 결과, 기존 경고 여부를 이 Task 아래에 누적 기록한다.
- 실행 명령:
-
Task 8.2: 수동 확인
- 확인 항목:
라이브탭 진입 시page=0,sort=LATEST로 최초 조회된다.- Sort-bar에
전체 {count}와 현재 정렬 label,ic_new_sort가 표시된다. - 정렬 컨텍스트 메뉴가 Sort-bar 아래에 표시되고 선택/닫힘 동작이 정상이다.
currentLive != null일 때 현재 라이브 카드가 표시된다.- 라이브 다시듣기 item의 19금/포인트/무료/소장중/대여중/가격 상태가 DTO와 일치한다.
isOwned && isRented동시 true item은소장중으로 표시된다.seriesName은 표시되지 않는다.hasNext == true일 때 하단 스크롤로 다음 페이지가 append된다.- 본인 채널에서만 하단
라이브 시작하기CTA가 표시된다. - 타인 채널에서는 하단 CTA가 표시되지 않는다.
- CTA가 마지막 item을 가리지 않는다.
- 검증 기록:
- 실제 확인한 시나리오와 결과를 이 Task 아래에 한국어로 누적 기록한다.
- 확인 항목:
Verification Log
- 2026-06-17: Phase 1 진행.
CreatorChannelHomeApi/CreatorChannelHomeRepository를CreatorChannelApi/CreatorChannelRepository로 rename하고 기존 홈 endpoint/repository method 동작은 유지했다. - 2026-06-17:
./gradlew :app:compileDebugKotlinPASS. 최초 병렬 실행은 KSP incremental cache 손상으로 실패했으나app/build/kspCaches/debug생성물 캐시 삭제 후 순차 재실행에서 통과했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"PASS.