feat(creator): 라이브 다시듣기 mapper를 추가한다

This commit is contained in:
2026-06-17 19:13:58 +09:00
parent f015aea062
commit 1f0adb21a7
3 changed files with 167 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
package kr.co.vividnext.sodalive.v2.creator.channel.live.model
import androidx.annotation.StringRes
import kr.co.vividnext.sodalive.R
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.widget.AudioContentTag
fun CreatorChannelAudioContentResponse.toReplayUiModel(): CreatorChannelLiveReplayUiModel =
CreatorChannelLiveReplayUiModel(
audioContentId = audioContentId,
title = title,
secondaryText = duration,
imageUrl = imageUrl,
price = price,
showAdultBadge = isAdult,
tags = toAudioContentTags(),
status = toReplayStatus()
)
@StringRes
fun ContentSort.toLabelResId(): Int = when (this) {
ContentSort.LATEST -> R.string.screen_audio_content_sort_newest
ContentSort.POPULAR -> R.string.screen_audio_content_sort_popularity
ContentSort.OWNED -> R.string.creator_channel_live_sort_owned
ContentSort.PRICE_HIGH -> R.string.screen_audio_content_sort_price_high
ContentSort.PRICE_LOW -> R.string.screen_audio_content_sort_price_low
}
fun ContentSort.toSortOptionUiModel(selectedSort: ContentSort): CreatorChannelLiveSortOptionUiModel =
CreatorChannelLiveSortOptionUiModel(
sort = this,
labelResId = toLabelResId(),
isSelected = this == selectedSort
)
private fun CreatorChannelAudioContentResponse.toAudioContentTags(): Set<AudioContentTag> = buildSet {
if (isOriginalSeries == true) add(AudioContentTag.Original)
if (isFirstContent) add(AudioContentTag.First)
if (isPointAvailable) add(AudioContentTag.Point)
if (price == 0) add(AudioContentTag.Free)
}
private fun CreatorChannelAudioContentResponse.toReplayStatus(): CreatorChannelLiveReplayStatus = when {
isOwned -> CreatorChannelLiveReplayStatus.Owned
isRented -> CreatorChannelLiveReplayStatus.Rented
price == 0 -> CreatorChannelLiveReplayStatus.Play
else -> CreatorChannelLiveReplayStatus.Price(price)
}

View File

@@ -0,0 +1,29 @@
package kr.co.vividnext.sodalive.v2.creator.channel.live.model
import androidx.annotation.StringRes
import kr.co.vividnext.sodalive.v2.common.data.ContentSort
import kr.co.vividnext.sodalive.v2.widget.AudioContentTag
data class CreatorChannelLiveReplayUiModel(
val audioContentId: Long,
val title: String,
val secondaryText: String?,
val imageUrl: String?,
val price: Int,
val showAdultBadge: Boolean,
val tags: Set<AudioContentTag>,
val status: CreatorChannelLiveReplayStatus
)
sealed interface CreatorChannelLiveReplayStatus {
data object Play : CreatorChannelLiveReplayStatus
data object Owned : CreatorChannelLiveReplayStatus
data object Rented : CreatorChannelLiveReplayStatus
data class Price(val price: Int) : CreatorChannelLiveReplayStatus
}
data class CreatorChannelLiveSortOptionUiModel(
val sort: ContentSort,
@param:StringRes val labelResId: Int,
val isSelected: Boolean
)

View File

@@ -0,0 +1,89 @@
package kr.co.vividnext.sodalive.v2.creator.channel.live
import kr.co.vividnext.sodalive.R
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.live.model.CreatorChannelLiveReplayStatus
import kr.co.vividnext.sodalive.v2.creator.channel.live.model.toLabelResId
import kr.co.vividnext.sodalive.v2.creator.channel.live.model.toReplayUiModel
import kr.co.vividnext.sodalive.v2.widget.AudioContentTag
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class CreatorChannelLiveMapperTest {
@Test
fun `소장과 대여가 동시에 true이면 소장중 상태를 우선 매핑한다`() {
val item = audioContent(isOwned = true, isRented = true).toReplayUiModel()
assertEquals(CreatorChannelLiveReplayStatus.Owned, item.status)
}
@Test
fun `무료 콘텐츠는 무료 tag와 play CTA 상태로 매핑한다`() {
val item = audioContent(price = 0).toReplayUiModel()
assertEquals(CreatorChannelLiveReplayStatus.Play, item.status)
assertTrue(AudioContentTag.Free in item.tags)
}
@Test
fun `성인 콘텐츠와 포인트 가능 콘텐츠는 shield와 point tag를 표시한다`() {
val item = audioContent(isAdult = true, isPointAvailable = true).toReplayUiModel()
assertTrue(item.showAdultBadge)
assertTrue(AudioContentTag.Point in item.tags)
}
@Test
fun `seriesName은 secondary text에 포함하지 않는다`() {
val item = audioContent(duration = "10:00", seriesName = "시리즈명").toReplayUiModel()
assertEquals("10:00", item.secondaryText)
assertFalse(item.secondaryText.orEmpty().contains("시리즈명"))
}
@Test
fun `첫 콘텐츠와 오리지널 시리즈는 기존 오디오 tag 정책과 동일하게 매핑한다`() {
val item = audioContent(isFirstContent = true, isOriginalSeries = true).toReplayUiModel()
assertTrue(AudioContentTag.First in item.tags)
assertTrue(AudioContentTag.Original in item.tags)
}
@Test
fun `정렬 값은 label resource로 매핑한다`() {
assertEquals(R.string.screen_audio_content_sort_newest, ContentSort.LATEST.toLabelResId())
assertEquals(R.string.screen_audio_content_sort_popularity, ContentSort.POPULAR.toLabelResId())
assertEquals(R.string.creator_channel_live_sort_owned, ContentSort.OWNED.toLabelResId())
assertEquals(R.string.screen_audio_content_sort_price_high, ContentSort.PRICE_HIGH.toLabelResId())
assertEquals(R.string.screen_audio_content_sort_price_low, ContentSort.PRICE_LOW.toLabelResId())
}
private fun audioContent(
price: Int = 10,
isPointAvailable: Boolean = false,
isFirstContent: Boolean = false,
seriesName: String? = null,
isOriginalSeries: Boolean? = false,
isAdult: Boolean = false,
isOwned: Boolean = false,
isRented: Boolean = false,
duration: String? = null
) = CreatorChannelAudioContentResponse(
audioContentId = 1L,
title = "다시듣기",
duration = duration,
imageUrl = "https://example.com/audio.png",
price = price,
isPointAvailable = isPointAvailable,
isFirstContent = isFirstContent,
seriesName = seriesName,
isOriginalSeries = isOriginalSeries,
isAdult = isAdult,
isOwned = isOwned,
isRented = isRented
)
}