fix(creator): 라이브 더보기 상태 보존을 보정한다

This commit is contained in:
2026-06-17 23:24:39 +09:00
parent e90fb04de9
commit 10004652e4
2 changed files with 94 additions and 4 deletions

View File

@@ -58,8 +58,11 @@ class CreatorChannelLiveViewModel(
val data = response.data val data = response.data
val current = _liveStateLiveData.value as? CreatorChannelLiveUiState.Content ?: content val current = _liveStateLiveData.value as? CreatorChannelLiveUiState.Content ?: content
if (response.success && data != null) { if (response.success && data != null) {
_liveStateLiveData.value = data.toContentState( _liveStateLiveData.value = current.copy(
liveReplayContents = current.liveReplayContents + data.liveReplayContents, liveReplayContents = current.liveReplayContents + data.liveReplayContents,
page = data.page,
size = data.size,
hasNext = data.hasNext,
isLoadingMore = false isLoadingMore = false
) )
} else { } else {
@@ -71,6 +74,13 @@ class CreatorChannelLiveViewModel(
} }
} }
fun consumePaginationErrorMessage() {
val content = _liveStateLiveData.value as? CreatorChannelLiveUiState.Content ?: return
if (content.paginationErrorMessage == null) return
_liveStateLiveData.value = content.copy(paginationErrorMessage = null)
}
private fun loadFirstPage(sort: ContentSort) { private fun loadFirstPage(sort: ContentSort) {
val generation = ++requestGeneration val generation = ++requestGeneration
_liveStateLiveData.value = CreatorChannelLiveUiState.Loading _liveStateLiveData.value = CreatorChannelLiveUiState.Loading

View File

@@ -15,6 +15,7 @@ import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.v2.common.data.ContentSort import kr.co.vividnext.sodalive.v2.common.data.ContentSort
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelAudioContentResponse import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelAudioContentResponse
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelLiveResponse
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
import kr.co.vividnext.sodalive.v2.creator.channel.live.data.CreatorChannelLiveTabResponse import kr.co.vividnext.sodalive.v2.creator.channel.live.data.CreatorChannelLiveTabResponse
import org.junit.After import org.junit.After
@@ -76,6 +77,62 @@ class CreatorChannelLivePaginationTest {
verifyGetLive(page = 1) verifyGetLive(page = 1)
} }
@Test
fun `다음 페이지 성공은 첫 페이지 현재 라이브 count sort를 보존하고 page와 hasNext만 갱신한다`() {
val currentLive = CreatorChannelLiveResponse(
liveId = 10L,
title = "현재 라이브",
coverImageUrl = null,
beginDateTimeUtc = "2026-06-17T01:00:00Z",
price = 100,
isAdult = false
)
stubGetLive(
page = 0,
response = Single.just(
ApiResponse(
true,
liveResponse(
page = 0,
ids = listOf(1L),
hasNext = true,
liveReplayContentCount = 99,
currentLive = currentLive
),
null
)
)
)
stubGetLive(
page = 1,
response = Single.just(
ApiResponse(
true,
liveResponse(
page = 1,
sort = ContentSort.POPULAR,
ids = listOf(2L),
hasNext = false,
liveReplayContentCount = 1,
currentLive = null
),
null
)
)
)
viewModel.loadLive(100L)
viewModel.loadMore()
val state = viewModel.liveStateLiveData.requireValue() as CreatorChannelLiveUiState.Content
assertEquals(currentLive, state.currentLive)
assertEquals(99, state.liveReplayContentCount)
assertEquals(ContentSort.LATEST, state.selectedSort)
assertEquals(1, state.page)
assertEquals(listOf(1L, 2L), state.liveReplayContents.map { it.audioContentId })
assertFalse(state.hasNext)
}
@Test @Test
fun `다음 페이지 로딩 중 중복 load-more 요청은 막는다`() { fun `다음 페이지 로딩 중 중복 load-more 요청은 막는다`() {
val pending = SingleSubject.create<ApiResponse<CreatorChannelLiveTabResponse>>() val pending = SingleSubject.create<ApiResponse<CreatorChannelLiveTabResponse>>()
@@ -114,6 +171,27 @@ class CreatorChannelLivePaginationTest {
assertEquals("failed", state.paginationErrorMessage) assertEquals("failed", state.paginationErrorMessage)
} }
@Test
fun `pagination error message는 표시 후 clear되어 다시 표시되지 않는다`() {
stubGetLive(
page = 0,
response = Single.just(ApiResponse(true, liveResponse(page = 0, ids = listOf(1L), hasNext = true), null))
)
stubGetLive(page = 1, response = Single.just(ApiResponse(false, null, "failed")))
viewModel.loadLive(100L)
viewModel.loadMore()
val state = viewModel.liveStateLiveData.requireValue() as CreatorChannelLiveUiState.Content
assertEquals("failed", state.paginationErrorMessage)
viewModel.consumePaginationErrorMessage()
val consumedState = viewModel.liveStateLiveData.requireValue() as CreatorChannelLiveUiState.Content
assertEquals(null, consumedState.paginationErrorMessage)
assertEquals(listOf(1L), consumedState.liveReplayContents.map { it.audioContentId })
}
@Test @Test
fun `이전 load-more 응답은 이후 정렬 변경 목록에 append되지 않는다`() { fun `이전 load-more 응답은 이후 정렬 변경 목록에 append되지 않는다`() {
val nextPagePending = SingleSubject.create<ApiResponse<CreatorChannelLiveTabResponse>>() val nextPagePending = SingleSubject.create<ApiResponse<CreatorChannelLiveTabResponse>>()
@@ -186,10 +264,12 @@ class CreatorChannelLivePaginationTest {
page: Int, page: Int,
sort: ContentSort = ContentSort.LATEST, sort: ContentSort = ContentSort.LATEST,
ids: List<Long>, ids: List<Long>,
hasNext: Boolean hasNext: Boolean,
liveReplayContentCount: Int = ids.size,
currentLive: CreatorChannelLiveResponse? = null
) = CreatorChannelLiveTabResponse( ) = CreatorChannelLiveTabResponse(
liveReplayContentCount = ids.size, liveReplayContentCount = liveReplayContentCount,
currentLive = null, currentLive = currentLive,
liveReplayContents = ids.map { audioContent(it) }, liveReplayContents = ids.map { audioContent(it) },
sort = sort, sort = sort,
page = page, page = page,