feat(home): 팔로잉 응답 UI 매핑을 추가한다

This commit is contained in:
2026-06-25 22:22:22 +09:00
parent 21d3ed4603
commit 502bbd4f35
4 changed files with 404 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
package kr.co.vividnext.sodalive.v2.main.home.model
import androidx.annotation.StringRes
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
import kr.co.vividnext.sodalive.v2.main.chat.model.toUiItems
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingCreatorResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingLiveResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingNewsResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingNewsType
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingScheduleResponse
import kr.co.vividnext.sodalive.v2.main.home.data.HomeFollowingTabResponse
fun HomeFollowingTabResponse.toUiState(
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
): HomeFollowingUiState {
if (isLoginRequired) return HomeFollowingUiState.LoginRequired
val content = toContent(relativeTimeTextFormatter)
return if (content.isEmpty) HomeFollowingUiState.Empty else content
}
private fun HomeFollowingTabResponse.toContent(
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
) = HomeFollowingUiState.Content(
followingCreators = HomeFollowingCreatorSection(followingCreators.map { it.toUiItem() }),
onAirLives = HomeFollowingLiveSection(onAirLives.map { it.toUiItem() }),
recentChats = HomeFollowingChatSection(recentChats.toUiItems()),
monthlySchedules = HomeFollowingScheduleSection(monthlySchedules.map { it.toUiItem() }),
recentNews = HomeFollowingNewsSection(recentNews.mapNotNull { it.toUiItem(relativeTimeTextFormatter) })
)
private fun FollowingCreatorResponse.toUiItem() = HomeFollowingCreatorUiItem(
creatorId = creatorId,
creatorNickname = creatorNickname,
creatorProfileImageUrl = creatorProfileImageUrl
)
private fun FollowingLiveResponse.toUiItem() = HomeFollowingLiveUiItem(
liveId = liveId,
creatorProfileImageUrl = creatorProfileImageUrl,
creatorNickname = creatorNickname,
title = title,
startedAtUtc = startedAtUtc
)
private fun FollowingScheduleResponse.toUiItem() = HomeFollowingScheduleUiItem(
scheduleId = scheduleId,
creatorId = creatorId,
creatorProfileImageUrl = creatorProfileImageUrl,
creatorNickname = creatorNickname,
title = title,
type = type,
typeLabelResId = type.labelResId,
targetId = targetId,
scheduledAtUtc = scheduledAtUtc,
isOnAir = isOnAir
)
private fun FollowingNewsResponse.toUiItem(
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
): HomeFollowingNewsUiItem? {
val visibleFromText = relativeTimeTextFormatter.format(visibleFromAtUtc)
return when (type) {
FollowingNewsType.CREATOR_RANKING,
FollowingNewsType.CONTENT_RANKING -> rank?.let {
HomeFollowingNewsUiItem.Ranking(
newsId = newsId,
type = type,
creatorProfileImageUrl = creatorProfileImageUrl,
creatorNickname = creatorNickname,
title = title,
body = body,
thumbnailImageUrl = thumbnailImageUrl,
targetId = targetId,
occurredAtUtc = occurredAtUtc,
visibleFromAtUtc = visibleFromAtUtc,
visibleFromText = visibleFromText,
rank = it
)
}
FollowingNewsType.COMMUNITY_POST,
FollowingNewsType.AUDIO_CONTENT,
FollowingNewsType.PHOTO_CONTENT -> HomeFollowingNewsUiItem.Content(
newsId = newsId,
type = type,
creatorProfileImageUrl = creatorProfileImageUrl,
creatorNickname = creatorNickname,
title = title,
body = body,
thumbnailImageUrl = thumbnailImageUrl,
targetId = targetId,
occurredAtUtc = occurredAtUtc,
visibleFromAtUtc = visibleFromAtUtc,
visibleFromText = visibleFromText,
labelResId = type.toLabelResId()
)
}
}
@StringRes
private fun FollowingNewsType.toLabelResId(): Int = when (this) {
FollowingNewsType.PHOTO_CONTENT -> R.string.screen_home_following_photo_content
FollowingNewsType.AUDIO_CONTENT -> R.string.home_recommendation_activity_audio
FollowingNewsType.COMMUNITY_POST -> R.string.home_recommendation_activity_community
FollowingNewsType.CREATOR_RANKING,
FollowingNewsType.CONTENT_RANKING -> R.string.weekly_chart
}

View File

@@ -0,0 +1,97 @@
package kr.co.vividnext.sodalive.v2.main.home.model
import androidx.annotation.StringRes
import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomListUiItem
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingNewsType
data class HomeFollowingCreatorSection(
val items: List<HomeFollowingCreatorUiItem>
)
data class HomeFollowingLiveSection(
val items: List<HomeFollowingLiveUiItem>
)
data class HomeFollowingChatSection(
val items: List<ChatRoomListUiItem>
)
data class HomeFollowingScheduleSection(
val items: List<HomeFollowingScheduleUiItem>
)
data class HomeFollowingNewsSection(
val items: List<HomeFollowingNewsUiItem>
)
data class HomeFollowingCreatorUiItem(
val creatorId: Long,
val creatorNickname: String,
val creatorProfileImageUrl: String
)
data class HomeFollowingLiveUiItem(
val liveId: Long,
val creatorProfileImageUrl: String,
val creatorNickname: String,
val title: String,
val startedAtUtc: String
)
data class HomeFollowingScheduleUiItem(
val scheduleId: String,
val creatorId: Long,
val creatorProfileImageUrl: String,
val creatorNickname: String,
val title: String,
val type: CreatorActivityType,
@param:StringRes val typeLabelResId: Int,
val targetId: Long,
val scheduledAtUtc: String,
val isOnAir: Boolean
)
sealed interface HomeFollowingNewsUiItem {
val newsId: String
val type: FollowingNewsType
val creatorProfileImageUrl: String
val creatorNickname: String
val title: String
val body: String
val thumbnailImageUrl: String?
val targetId: Long
val occurredAtUtc: String
val visibleFromAtUtc: String
val visibleFromText: String
data class Ranking(
override val newsId: String,
override val type: FollowingNewsType,
override val creatorProfileImageUrl: String,
override val creatorNickname: String,
override val title: String,
override val body: String,
override val thumbnailImageUrl: String?,
override val targetId: Long,
override val occurredAtUtc: String,
override val visibleFromAtUtc: String,
override val visibleFromText: String,
val rank: Int
) : HomeFollowingNewsUiItem
data class Content(
override val newsId: String,
override val type: FollowingNewsType,
override val creatorProfileImageUrl: String,
override val creatorNickname: String,
override val title: String,
override val body: String,
override val thumbnailImageUrl: String?,
override val targetId: Long,
override val occurredAtUtc: String,
override val visibleFromAtUtc: String,
override val visibleFromText: String,
@param:StringRes val labelResId: Int
) : HomeFollowingNewsUiItem
}

View File

@@ -0,0 +1,26 @@
package kr.co.vividnext.sodalive.v2.main.home.model
sealed interface HomeFollowingUiState {
data object Loading : HomeFollowingUiState
data object LoginRequired : HomeFollowingUiState
data class Content(
val followingCreators: HomeFollowingCreatorSection,
val onAirLives: HomeFollowingLiveSection,
val recentChats: HomeFollowingChatSection,
val monthlySchedules: HomeFollowingScheduleSection,
val recentNews: HomeFollowingNewsSection
) : HomeFollowingUiState {
val isEmpty: Boolean
get() = followingCreators.items.isEmpty() &&
onAirLives.items.isEmpty() &&
recentChats.items.isEmpty() &&
monthlySchedules.items.isEmpty() &&
recentNews.items.isEmpty()
}
data object Empty : HomeFollowingUiState
data class Error(val message: String?) : HomeFollowingUiState
}