feat(creator): 채널 홈 UI 상태를 추가한다

This commit is contained in:
2026-06-13 17:19:58 +09:00
parent 0ae6596816
commit a355838039
5 changed files with 417 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
package kr.co.vividnext.sodalive.v2.creator.channel.model
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelHomeResponse
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelSnsResponse
fun CreatorChannelHomeResponse.toUiContent(): CreatorChannelHomeUiState.Content {
val sections = buildList {
currentLive?.let { add(CreatorChannelHomeSection.CurrentLive(it)) }
latestAudioContent?.let { add(CreatorChannelHomeSection.LatestAudioContent(it)) }
channelDonations.takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Donations(it)) }
notices.takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Notices(it)) }
schedules.takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Schedules(it)) }
audioContents.takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.AudioContents(it)) }
series.takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Series(it)) }
communities.takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Communities(it)) }
fanTalk.takeIf { it.totalCount > 0 || it.latestFanTalk != null }?.let { add(CreatorChannelHomeSection.FanTalk(it)) }
introduce.takeIf { it.isNotBlank() }?.let { add(CreatorChannelHomeSection.Introduce(it)) }
add(CreatorChannelHomeSection.Activity(activity))
sns.toUiItems().takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Sns(it)) }
}
return CreatorChannelHomeUiState.Content(
header = CreatorChannelHeaderUiModel(
creatorId = creator.creatorId,
characterId = creator.characterId,
nickname = creator.nickname,
profileImageUrl = creator.profileImageUrl,
followerCount = creator.followerCount,
isFollow = creator.isFollow,
isNotify = creator.isNotify,
isAiChatAvailable = creator.isAiChatAvailable,
isDmAvailable = creator.isDmAvailable
),
tabs = CreatorChannelTab.entries,
sections = sections
)
}
private fun CreatorChannelSnsResponse.toUiItems(): List<CreatorChannelSnsUiItem> = buildList {
instagramUrl.toSnsItem("Instagram")?.let(::add)
fancimmUrl.toSnsItem("Fancimm")?.let(::add)
xUrl.toSnsItem("X")?.let(::add)
youtubeUrl.toSnsItem("YouTube")?.let(::add)
kakaoOpenChatUrl.toSnsItem("Kakao Open Chat")?.let(::add)
}
private fun String.toSnsItem(label: String): CreatorChannelSnsUiItem? = takeIf { it.isNotBlank() }?.let {
CreatorChannelSnsUiItem(label = label, url = it)
}

View File

@@ -0,0 +1,63 @@
package kr.co.vividnext.sodalive.v2.creator.channel.model
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.CreatorChannelDonationResponse
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelFanTalkSummaryResponse
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
sealed interface CreatorChannelHomeUiState {
data object Loading : CreatorChannelHomeUiState
data object Empty : CreatorChannelHomeUiState
data class Error(val message: String?) : CreatorChannelHomeUiState
data class Content(
val header: CreatorChannelHeaderUiModel,
val tabs: List<CreatorChannelTab>,
val sections: List<CreatorChannelHomeSection>
) : CreatorChannelHomeUiState
}
enum class CreatorChannelTab(val label: String) {
Home(""),
Live("라이브"),
Audio("오디오"),
Series("시리즈"),
Community("커뮤니티"),
FanTalk("팬Talk"),
Donation("후원")
}
data class CreatorChannelHeaderUiModel(
val creatorId: Long,
val characterId: Long?,
val nickname: String,
val profileImageUrl: String,
val followerCount: Int,
val isFollow: Boolean,
val isNotify: Boolean,
val isAiChatAvailable: Boolean,
val isDmAvailable: Boolean
)
sealed interface CreatorChannelHomeSection {
data class CurrentLive(val live: CreatorChannelLiveResponse) : CreatorChannelHomeSection
data class LatestAudioContent(val audioContent: CreatorChannelAudioContentResponse) : CreatorChannelHomeSection
data class Donations(val donations: List<CreatorChannelDonationResponse>) : CreatorChannelHomeSection
data class Notices(val notices: List<CreatorChannelCommunityPostResponse>) : CreatorChannelHomeSection
data class Schedules(val schedules: List<CreatorChannelScheduleResponse>) : CreatorChannelHomeSection
data class AudioContents(val audioContents: List<CreatorChannelAudioContentResponse>) : CreatorChannelHomeSection
data class Series(val series: List<CreatorChannelSeriesResponse>) : CreatorChannelHomeSection
data class Communities(val communities: List<CreatorChannelCommunityPostResponse>) : CreatorChannelHomeSection
data class FanTalk(val fanTalk: CreatorChannelFanTalkSummaryResponse) : CreatorChannelHomeSection
data class Introduce(val introduce: String) : CreatorChannelHomeSection
data class Activity(val activity: CreatorChannelActivityResponse) : CreatorChannelHomeSection
data class Sns(val items: List<CreatorChannelSnsUiItem>) : CreatorChannelHomeSection
}
data class CreatorChannelSnsUiItem(
val label: String,
val url: String
)

View File

@@ -0,0 +1,26 @@
package kr.co.vividnext.sodalive.v2.creator.channel.model
import androidx.annotation.DrawableRes
import kr.co.vividnext.sodalive.R
data class CreatorChannelTitleBarState(
@DrawableRes val followIconResId: Int,
@DrawableRes val bellIconResId: Int?,
val isActionEnabled: Boolean
) {
companion object {
fun from(
isFollow: Boolean,
isNotify: Boolean,
isInProgress: Boolean
): CreatorChannelTitleBarState = CreatorChannelTitleBarState(
followIconResId = if (isFollow) R.drawable.ic_new_following else R.drawable.ic_new_follow,
bellIconResId = when {
!isFollow -> null
isNotify -> R.drawable.ic_bar_bell_colored
else -> R.drawable.ic_bar_bell
},
isActionEnabled = !isInProgress
)
}
}