feat(content): 추천 UI 모델 매핑을 추가한다

This commit is contained in:
2026-06-23 15:50:24 +09:00
parent 5746239873
commit c02437797c
4 changed files with 319 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
package kr.co.vividnext.sodalive.v2.main.content.model
import kr.co.vividnext.sodalive.v2.main.content.data.AudioBannerResponse
import kr.co.vividnext.sodalive.v2.main.content.data.AudioCardResponse
import kr.co.vividnext.sodalive.v2.main.content.data.AudioRecommendationsResponse
import kr.co.vividnext.sodalive.v2.main.content.data.CommentedAudioResponse
import kr.co.vividnext.sodalive.v2.main.content.data.OriginalSeriesResponse
import kr.co.vividnext.sodalive.v2.widget.AudioContentTag
fun AudioRecommendationsResponse.toContent(): AudioRecommendationsUiState.Content = AudioRecommendationsUiState.Content(
banners = ContentBannerSection(banners.map { it.toUiModel() }),
originalSeries = ContentOriginalSeriesSection(originalSeries.map { it.toUiModel() }),
latestAudios = ContentAudioCardSection(latestAudios.map { it.toUiModel() }),
newAndHotAudios = ContentAudioCardSection(newAndHotAudios.map { it.toUiModel() }),
freeAudios = ContentAudioCardSection(freeAudios.map { it.toUiModel() }),
pointAudios = ContentAudioCardSection(pointAudios.map { it.toUiModel() }),
mostCommentedAudios = ContentCommentedAudioSection(mostCommentedAudios.map { it.toUiModel() }),
recommendedAudios = ContentAudioCardSection(recommendedAudios.map { it.toUiModel() })
)
fun AudioBannerResponse.toUiModel(): ContentBannerUiModel = ContentBannerUiModel(
imageUrl = imageUrl,
eventItem = eventItem,
creatorId = creatorId,
seriesId = seriesId,
link = link
)
fun OriginalSeriesResponse.toUiModel(): ContentOriginalSeriesUiModel = ContentOriginalSeriesUiModel(
seriesId = seriesId,
coverImageUrl = coverImageUrl
)
fun AudioCardResponse.toUiModel(): ContentAudioCardUiModel = ContentAudioCardUiModel(
audioContentId = audioContentId,
title = title,
imageUrl = imageUrl,
price = price,
creatorNickname = creatorNickname,
tags = toAudioContentTags(),
showAdultBadge = isAdult
)
fun CommentedAudioResponse.toUiModel(): ContentCommentedAudioUiModel = ContentCommentedAudioUiModel(
audioContentId = audioContentId,
title = title,
imageUrl = imageUrl,
latestComment = latestComment,
latestCommentWriterProfileImageUrl = latestCommentWriterProfileImageUrl,
showLatestComment = latestComment.isNotBlank()
)
private fun AudioCardResponse.toAudioContentTags(): Set<AudioContentTag> = buildSet {
if (isOriginalSeries) add(AudioContentTag.Original)
if (isFirstContent) add(AudioContentTag.First)
if (isPointAvailable) add(AudioContentTag.Point)
if (price == 0) add(AudioContentTag.Free)
}

View File

@@ -0,0 +1,52 @@
package kr.co.vividnext.sodalive.v2.main.content.model
import kr.co.vividnext.sodalive.settings.event.EventItem
import kr.co.vividnext.sodalive.v2.widget.AudioContentTag
data class ContentBannerSection(
val items: List<ContentBannerUiModel>
)
data class ContentOriginalSeriesSection(
val items: List<ContentOriginalSeriesUiModel>
)
data class ContentAudioCardSection(
val items: List<ContentAudioCardUiModel>
)
data class ContentCommentedAudioSection(
val items: List<ContentCommentedAudioUiModel>
)
data class ContentBannerUiModel(
val imageUrl: String,
val eventItem: EventItem?,
val creatorId: Long?,
val seriesId: Long?,
val link: String?
)
data class ContentOriginalSeriesUiModel(
val seriesId: Long,
val coverImageUrl: String?
)
data class ContentAudioCardUiModel(
val audioContentId: Long,
val title: String,
val imageUrl: String?,
val price: Int,
val creatorNickname: String,
val tags: Set<AudioContentTag>,
val showAdultBadge: Boolean
)
data class ContentCommentedAudioUiModel(
val audioContentId: Long,
val title: String,
val imageUrl: String?,
val latestComment: String,
val latestCommentWriterProfileImageUrl: String,
val showLatestComment: Boolean
)

View File

@@ -0,0 +1,33 @@
package kr.co.vividnext.sodalive.v2.main.content.model
sealed interface AudioRecommendationsUiState {
data object Loading : AudioRecommendationsUiState
data class Content(
val banners: ContentBannerSection,
val originalSeries: ContentOriginalSeriesSection,
val latestAudios: ContentAudioCardSection,
val newAndHotAudios: ContentAudioCardSection,
val freeAudios: ContentAudioCardSection,
val pointAudios: ContentAudioCardSection,
val mostCommentedAudios: ContentCommentedAudioSection,
val recommendedAudios: ContentAudioCardSection
) : AudioRecommendationsUiState {
val isEmpty: Boolean = listOf(
banners.items,
originalSeries.items,
latestAudios.items,
newAndHotAudios.items,
freeAudios.items,
pointAudios.items,
mostCommentedAudios.items,
recommendedAudios.items
).all { it.isEmpty() }
}
data object Empty : AudioRecommendationsUiState
data class Error(
val message: String? = null
) : AudioRecommendationsUiState
}