feat(creator): 채널 홈 UI 상태를 추가한다
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel
|
||||
|
||||
import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelActivityResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelAudioContentResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelCommunityPostResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelCreatorResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelDonationResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelFanTalkResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelFanTalkSummaryResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelHomeResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelLiveResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelScheduleResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelSeriesResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelSnsResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelHomeSection
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelTab
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.toUiContent
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorChannelHomeMapperTest {
|
||||
|
||||
@Test
|
||||
fun `크리에이터 정보와 탭 순서를 UI content에 그대로 매핑한다`() {
|
||||
val content = response().toUiContent()
|
||||
|
||||
assertEquals(100L, content.header.creatorId)
|
||||
assertEquals(200L, content.header.characterId)
|
||||
assertEquals("소다", content.header.nickname)
|
||||
assertEquals("https://example.com/profile.png", content.header.profileImageUrl)
|
||||
assertEquals(1234, content.header.followerCount)
|
||||
assertTrue(content.header.isFollow)
|
||||
assertFalse(content.header.isNotify)
|
||||
assertTrue(content.header.isAiChatAvailable)
|
||||
assertTrue(content.header.isDmAvailable)
|
||||
assertEquals(
|
||||
listOf("홈", "라이브", "오디오", "시리즈", "커뮤니티", "팬Talk", "후원"),
|
||||
content.tabs.map(CreatorChannelTab::label)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `null 단건 콘텐츠와 빈 리스트와 blank SNS는 section을 생성하지 않는다`() {
|
||||
val content = response(
|
||||
currentLive = null,
|
||||
latestAudioContent = null,
|
||||
channelDonations = emptyList(),
|
||||
notices = emptyList(),
|
||||
schedules = emptyList(),
|
||||
audioContents = emptyList(),
|
||||
series = emptyList(),
|
||||
communities = emptyList(),
|
||||
fanTalk = CreatorChannelFanTalkSummaryResponse(totalCount = 0, latestFanTalk = null),
|
||||
introduce = "",
|
||||
sns = CreatorChannelSnsResponse(
|
||||
instagramUrl = " ",
|
||||
fancimmUrl = "",
|
||||
xUrl = "",
|
||||
youtubeUrl = "",
|
||||
kakaoOpenChatUrl = ""
|
||||
)
|
||||
).toUiContent()
|
||||
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.CurrentLive })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.LatestAudioContent })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Donations })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Notices })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Schedules })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.AudioContents })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Series })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Communities })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.FanTalk })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Introduce })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Sns })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `값이 있는 홈 필드는 section으로 생성하고 blank SNS URL만 제외한다`() {
|
||||
val content = response().toUiContent()
|
||||
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.CurrentLive })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.LatestAudioContent })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.Donations })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.Notices })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.Schedules })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.AudioContents })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.Series })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.Communities })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.FanTalk })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.Introduce })
|
||||
val sns = content.sections.filterIsInstance<CreatorChannelHomeSection.Sns>().single()
|
||||
|
||||
assertEquals(listOf("Instagram", "YouTube"), sns.items.map { it.label })
|
||||
assertEquals(listOf("https://instagram.example", "https://youtube.example"), sns.items.map { it.url })
|
||||
}
|
||||
|
||||
private fun response(
|
||||
currentLive: CreatorChannelLiveResponse? = live(),
|
||||
latestAudioContent: CreatorChannelAudioContentResponse? = audioContent(10L),
|
||||
channelDonations: List<CreatorChannelDonationResponse> = listOf(donation()),
|
||||
notices: List<CreatorChannelCommunityPostResponse> = listOf(post(20L)),
|
||||
schedules: List<CreatorChannelScheduleResponse> = listOf(schedule()),
|
||||
audioContents: List<CreatorChannelAudioContentResponse> = listOf(audioContent(11L)),
|
||||
series: List<CreatorChannelSeriesResponse> = listOf(series()),
|
||||
communities: List<CreatorChannelCommunityPostResponse> = listOf(post(21L)),
|
||||
fanTalk: CreatorChannelFanTalkSummaryResponse = fanTalk(),
|
||||
introduce: String = "소개입니다",
|
||||
activity: CreatorChannelActivityResponse = activity(),
|
||||
sns: CreatorChannelSnsResponse = CreatorChannelSnsResponse(
|
||||
instagramUrl = "https://instagram.example",
|
||||
fancimmUrl = "",
|
||||
xUrl = " ",
|
||||
youtubeUrl = "https://youtube.example",
|
||||
kakaoOpenChatUrl = ""
|
||||
)
|
||||
) = CreatorChannelHomeResponse(
|
||||
creator = CreatorChannelCreatorResponse(
|
||||
creatorId = 100L,
|
||||
characterId = 200L,
|
||||
nickname = "소다",
|
||||
profileImageUrl = "https://example.com/profile.png",
|
||||
followerCount = 1234,
|
||||
isAiChatAvailable = true,
|
||||
isDmAvailable = true,
|
||||
isFollow = true,
|
||||
isNotify = false
|
||||
),
|
||||
currentLive = currentLive,
|
||||
latestAudioContent = latestAudioContent,
|
||||
channelDonations = channelDonations,
|
||||
notices = notices,
|
||||
schedules = schedules,
|
||||
audioContents = audioContents,
|
||||
series = series,
|
||||
communities = communities,
|
||||
fanTalk = fanTalk,
|
||||
introduce = introduce,
|
||||
activity = activity,
|
||||
sns = sns
|
||||
)
|
||||
|
||||
private fun live() = CreatorChannelLiveResponse(
|
||||
liveId = 1L,
|
||||
title = "라이브",
|
||||
coverImageUrl = "https://example.com/live.png",
|
||||
beginDateTimeUtc = "2026-06-11T12:00:00Z",
|
||||
price = 10,
|
||||
isAdult = false
|
||||
)
|
||||
|
||||
private fun audioContent(id: Long) = CreatorChannelAudioContentResponse(
|
||||
audioContentId = id,
|
||||
title = "오디오 $id",
|
||||
duration = "10:00",
|
||||
imageUrl = "https://example.com/audio.png",
|
||||
price = 10,
|
||||
isPointAvailable = true,
|
||||
isFirstContent = false,
|
||||
seriesName = "시리즈",
|
||||
isOriginalSeries = true
|
||||
)
|
||||
|
||||
private fun donation() = CreatorChannelDonationResponse(
|
||||
donationId = 1L,
|
||||
memberId = 2L,
|
||||
nickname = "후원자",
|
||||
profileImageUrl = "https://example.com/member.png",
|
||||
can = 100,
|
||||
isSecret = false,
|
||||
message = "응원합니다",
|
||||
createdAtUtc = "2026-06-11T12:00:00Z"
|
||||
)
|
||||
|
||||
private fun schedule() = CreatorChannelScheduleResponse(
|
||||
scheduledAtUtc = "2026-06-12T12:00:00Z",
|
||||
title = "일정",
|
||||
type = CreatorActivityType.Live,
|
||||
targetId = 1L
|
||||
)
|
||||
|
||||
private fun series() = CreatorChannelSeriesResponse(
|
||||
seriesId = 1L,
|
||||
title = "시리즈",
|
||||
coverImageUrl = "https://example.com/series.png",
|
||||
publishedDaysOfWeek = "MON",
|
||||
isComplete = false,
|
||||
numberOfContent = 3,
|
||||
isNew = true,
|
||||
isPopular = false,
|
||||
isOriginal = true
|
||||
)
|
||||
|
||||
private fun post(id: Long) = CreatorChannelCommunityPostResponse(
|
||||
postId = id,
|
||||
creatorId = 100L,
|
||||
creatorNickname = "소다",
|
||||
creatorProfileUrl = "https://example.com/profile.png",
|
||||
imageUrl = null,
|
||||
audioUrl = null,
|
||||
content = "게시글",
|
||||
price = 0,
|
||||
dateUtc = "2026-06-11T12:00:00Z",
|
||||
existOrdered = false,
|
||||
likeCount = 1,
|
||||
commentCount = 2
|
||||
)
|
||||
|
||||
private fun fanTalk() = CreatorChannelFanTalkSummaryResponse(
|
||||
totalCount = 1,
|
||||
latestFanTalk = CreatorChannelFanTalkResponse(
|
||||
fanTalkId = 1L,
|
||||
memberId = 2L,
|
||||
nickname = "팬",
|
||||
profileImageUrl = "https://example.com/fan.png",
|
||||
content = "팬톡",
|
||||
languageCode = "ko",
|
||||
createdAtUtc = "2026-06-11T12:00:00Z"
|
||||
)
|
||||
)
|
||||
|
||||
private fun activity() = CreatorChannelActivityResponse(
|
||||
debutDateUtc = "2026-01-01T00:00:00Z",
|
||||
dDay = "D+1",
|
||||
liveCount = 1,
|
||||
liveDurationHours = 2,
|
||||
liveContributorCount = 3,
|
||||
audioContentCount = 4,
|
||||
seriesCount = 5
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel
|
||||
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelTitleBarState
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorChannelTitleBarStateTest {
|
||||
|
||||
@Test
|
||||
fun `팔로우하지 않은 상태는 follow 아이콘만 표시한다`() {
|
||||
val state = CreatorChannelTitleBarState.from(isFollow = false, isNotify = false, isInProgress = false)
|
||||
|
||||
assertEquals(R.drawable.ic_new_follow, state.followIconResId)
|
||||
assertNull(state.bellIconResId)
|
||||
assertTrue(state.isActionEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `팔로우와 알림이 모두 켜진 상태는 following과 colored bell 아이콘을 표시한다`() {
|
||||
val state = CreatorChannelTitleBarState.from(isFollow = true, isNotify = true, isInProgress = false)
|
||||
|
||||
assertEquals(R.drawable.ic_new_following, state.followIconResId)
|
||||
assertEquals(R.drawable.ic_bar_bell_colored, state.bellIconResId)
|
||||
assertTrue(state.isActionEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `팔로우만 켜진 상태는 following과 기본 bell 아이콘을 표시한다`() {
|
||||
val state = CreatorChannelTitleBarState.from(isFollow = true, isNotify = false, isInProgress = false)
|
||||
|
||||
assertEquals(R.drawable.ic_new_following, state.followIconResId)
|
||||
assertEquals(R.drawable.ic_bar_bell, state.bellIconResId)
|
||||
assertTrue(state.isActionEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `요청 진행 중에는 액션을 비활성화한다`() {
|
||||
val state = CreatorChannelTitleBarState.from(isFollow = true, isNotify = true, isInProgress = true)
|
||||
|
||||
assertFalse(state.isActionEnabled)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user