fix(home): 팔로잉 최근 소식 nested payload를 반영한다

This commit is contained in:
2026-06-30 23:54:10 +09:00
parent 2041036530
commit 3f3bacebd9
7 changed files with 178 additions and 81 deletions

View File

@@ -48,15 +48,49 @@ data class FollowingScheduleResponse(
data class FollowingNewsResponse( data class FollowingNewsResponse(
@SerializedName("newsId") val newsId: String, @SerializedName("newsId") val newsId: String,
@SerializedName("type") val type: FollowingNewsType, @SerializedName("type") val type: FollowingNewsType,
@SerializedName("creatorProfileImageUrl") val creatorProfileImageUrl: String,
@SerializedName("creatorNickname") val creatorNickname: String,
@SerializedName("title") val title: String,
@SerializedName("body") val body: String,
@SerializedName("thumbnailImageUrl") val thumbnailImageUrl: String?,
@SerializedName("targetId") val targetId: Long,
@SerializedName("occurredAtUtc") val occurredAtUtc: String,
@SerializedName("visibleFromAtUtc") val visibleFromAtUtc: String, @SerializedName("visibleFromAtUtc") val visibleFromAtUtc: String,
@SerializedName("rank") val rank: Int? @SerializedName("creatorRanking") val creatorRanking: FollowingCreatorRankingNewsResponse? = null,
@SerializedName("audioContent") val audioContent: FollowingContentNewsResponse? = null,
@SerializedName("photoContent") val photoContent: FollowingContentNewsResponse? = null,
@SerializedName("contentRanking") val contentRanking: FollowingContentRankingNewsResponse? = null,
@SerializedName("communityPost") val communityPost: FollowingCommunityPostNewsResponse? = null
)
@Keep
data class FollowingCreatorRankingNewsResponse(
@SerializedName("rank") val rank: Int,
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImageUrl") val profileImageUrl: String
)
@Keep
data class FollowingContentNewsResponse(
@SerializedName("contentId") val contentId: Long,
@SerializedName("contentImageUrl") val contentImageUrl: String?,
@SerializedName("title") val title: String,
@SerializedName("creatorProfileImageUrl") val creatorProfileImageUrl: String,
@SerializedName("creatorNickname") val creatorNickname: String
)
@Keep
data class FollowingContentRankingNewsResponse(
@SerializedName("rank") val rank: Int,
@SerializedName("contentId") val contentId: Long,
@SerializedName("contentImageUrl") val contentImageUrl: String?,
@SerializedName("title") val title: String
)
@Keep
data class FollowingCommunityPostNewsResponse(
@SerializedName("postId") val postId: Long,
@SerializedName("creatorProfileImage") val creatorProfileImage: String,
@SerializedName("creatorNickname") val creatorNickname: String,
@SerializedName("imageUrl") val imageUrl: String?,
@SerializedName("content") val content: String,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("likeCount") val likeCount: Int,
@SerializedName("commentCount") val commentCount: Int
) )
enum class FollowingNewsType { enum class FollowingNewsType {

View File

@@ -4,7 +4,11 @@ import androidx.annotation.StringRes
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
import kr.co.vividnext.sodalive.v2.main.chat.model.toUiItems import kr.co.vividnext.sodalive.v2.main.chat.model.toUiItems
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingCommunityPostNewsResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingContentNewsResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingContentRankingNewsResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingCreatorResponse import kr.co.vividnext.sodalive.v2.main.home.data.FollowingCreatorResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingCreatorRankingNewsResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingLiveResponse 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.FollowingNewsResponse
import kr.co.vividnext.sodalive.v2.main.home.data.FollowingNewsType import kr.co.vividnext.sodalive.v2.main.home.data.FollowingNewsType
@@ -62,42 +66,88 @@ private fun FollowingNewsResponse.toUiItem(
): HomeFollowingNewsUiItem? { ): HomeFollowingNewsUiItem? {
val visibleFromText = relativeTimeTextFormatter.format(visibleFromAtUtc) val visibleFromText = relativeTimeTextFormatter.format(visibleFromAtUtc)
return when (type) { return when (type) {
FollowingNewsType.CREATOR_RANKING, FollowingNewsType.CREATOR_RANKING -> creatorRanking?.toUiItem(newsId, type, visibleFromAtUtc, visibleFromText)
FollowingNewsType.CONTENT_RANKING -> rank?.let { FollowingNewsType.CONTENT_RANKING -> contentRanking?.toUiItem(newsId, type, visibleFromAtUtc, visibleFromText)
HomeFollowingNewsUiItem.Ranking( FollowingNewsType.COMMUNITY_POST -> communityPost?.toUiItem(newsId, type, visibleFromAtUtc, visibleFromText)
newsId = newsId, FollowingNewsType.AUDIO_CONTENT -> audioContent?.toUiItem(newsId, type, visibleFromAtUtc, visibleFromText)
type = type, FollowingNewsType.PHOTO_CONTENT -> photoContent?.toUiItem(newsId, type, visibleFromAtUtc, visibleFromText)
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()
)
} }
} }
private fun FollowingCreatorRankingNewsResponse.toUiItem(
newsId: String,
type: FollowingNewsType,
visibleFromAtUtc: String,
visibleFromText: String
) = HomeFollowingNewsUiItem.Ranking(
newsId = newsId,
type = type,
targetId = creatorId,
visibleFromAtUtc = visibleFromAtUtc,
visibleFromText = visibleFromText,
rank = rank,
imageUrl = profileImageUrl,
title = nickname,
creatorNickname = nickname
)
private fun FollowingContentRankingNewsResponse.toUiItem(
newsId: String,
type: FollowingNewsType,
visibleFromAtUtc: String,
visibleFromText: String
) = HomeFollowingNewsUiItem.Ranking(
newsId = newsId,
type = type,
targetId = contentId,
visibleFromAtUtc = visibleFromAtUtc,
visibleFromText = visibleFromText,
rank = rank,
imageUrl = contentImageUrl,
title = title,
creatorNickname = ""
)
private fun FollowingContentNewsResponse.toUiItem(
newsId: String,
type: FollowingNewsType,
visibleFromAtUtc: String,
visibleFromText: String
) = HomeFollowingNewsUiItem.Content(
newsId = newsId,
type = type,
targetId = contentId,
visibleFromAtUtc = visibleFromAtUtc,
visibleFromText = visibleFromText,
contentId = contentId,
contentImageUrl = contentImageUrl,
title = title,
creatorProfileImageUrl = creatorProfileImageUrl,
creatorNickname = creatorNickname,
labelResId = type.toLabelResId()
)
private fun FollowingCommunityPostNewsResponse.toUiItem(
newsId: String,
type: FollowingNewsType,
visibleFromAtUtc: String,
visibleFromText: String
) = HomeFollowingNewsUiItem.Community(
newsId = newsId,
type = type,
targetId = postId,
visibleFromAtUtc = visibleFromAtUtc,
visibleFromText = visibleFromText,
postId = postId,
creatorProfileImageUrl = creatorProfileImage,
creatorNickname = creatorNickname,
imageUrl = imageUrl,
content = content,
createdAt = createdAt,
likeCount = likeCount,
commentCount = commentCount
)
@StringRes @StringRes
private fun FollowingNewsType.toLabelResId(): Int = when (this) { private fun FollowingNewsType.toLabelResId(): Int = when (this) {
FollowingNewsType.PHOTO_CONTENT -> R.string.screen_home_following_photo_content FollowingNewsType.PHOTO_CONTENT -> R.string.screen_home_following_photo_content

View File

@@ -55,43 +55,49 @@ data class HomeFollowingScheduleUiItem(
sealed interface HomeFollowingNewsUiItem { sealed interface HomeFollowingNewsUiItem {
val newsId: String val newsId: String
val type: FollowingNewsType val type: FollowingNewsType
val creatorProfileImageUrl: String
val creatorNickname: String
val title: String
val body: String
val thumbnailImageUrl: String?
val targetId: Long val targetId: Long
val occurredAtUtc: String
val visibleFromAtUtc: String val visibleFromAtUtc: String
val visibleFromText: String val visibleFromText: String
data class Ranking( data class Ranking(
override val newsId: String, override val newsId: String,
override val type: FollowingNewsType, 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 targetId: Long,
override val occurredAtUtc: String,
override val visibleFromAtUtc: String, override val visibleFromAtUtc: String,
override val visibleFromText: String, override val visibleFromText: String,
val rank: Int val rank: Int,
val imageUrl: String?,
val title: String,
val creatorNickname: String
) : HomeFollowingNewsUiItem ) : HomeFollowingNewsUiItem
data class Content( data class Content(
override val newsId: String, override val newsId: String,
override val type: FollowingNewsType, 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 targetId: Long,
override val occurredAtUtc: String,
override val visibleFromAtUtc: String, override val visibleFromAtUtc: String,
override val visibleFromText: String, override val visibleFromText: String,
val contentId: Long,
val contentImageUrl: String?,
val title: String,
val creatorProfileImageUrl: String,
val creatorNickname: String,
@param:StringRes val labelResId: Int @param:StringRes val labelResId: Int
) : HomeFollowingNewsUiItem ) : HomeFollowingNewsUiItem
data class Community(
override val newsId: String,
override val type: FollowingNewsType,
override val targetId: Long,
override val visibleFromAtUtc: String,
override val visibleFromText: String,
val postId: Long,
val creatorProfileImageUrl: String,
val creatorNickname: String,
val imageUrl: String?,
val content: String,
val createdAt: String,
val likeCount: Int,
val commentCount: Int
) : HomeFollowingNewsUiItem
} }

View File

@@ -31,13 +31,8 @@ class HomeFollowingNewsAdapter(
override fun getItemViewType(position: Int): Int = when (val item = items[position]) { override fun getItemViewType(position: Int): Int = when (val item = items[position]) {
is HomeFollowingNewsUiItem.Ranking -> VIEW_TYPE_RANKING is HomeFollowingNewsUiItem.Ranking -> VIEW_TYPE_RANKING
is HomeFollowingNewsUiItem.Content -> when (item.type) { is HomeFollowingNewsUiItem.Content -> VIEW_TYPE_CONTENT
FollowingNewsType.COMMUNITY_POST -> VIEW_TYPE_COMMUNITY is HomeFollowingNewsUiItem.Community -> VIEW_TYPE_COMMUNITY
FollowingNewsType.AUDIO_CONTENT,
FollowingNewsType.PHOTO_CONTENT -> VIEW_TYPE_CONTENT
FollowingNewsType.CREATOR_RANKING,
FollowingNewsType.CONTENT_RANKING -> VIEW_TYPE_CONTENT
}
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
@@ -80,14 +75,10 @@ class HomeFollowingNewsAdapter(
val ranking = item as HomeFollowingNewsUiItem.Ranking val ranking = item as HomeFollowingNewsUiItem.Ranking
val context = view.context val context = view.context
val rankText = "${ranking.rank}" val rankText = "${ranking.rank}"
val message = context.getString( val message = ranking.toRankingMessage(rankText)
R.string.screen_home_following_creator_ranking_news_message,
ranking.creatorNickname,
rankText
)
val feedItem = FeedItem.Rank( val feedItem = FeedItem.Rank(
feedId = ranking.newsId, feedId = ranking.newsId,
imageUrl = ranking.thumbnailImageUrl.orEmpty(), imageUrl = ranking.imageUrl.orEmpty(),
rankText = ranking.rank.toString(), rankText = ranking.rank.toString(),
message = message, message = message,
highlightRanges = listOf( highlightRanges = listOf(
@@ -102,6 +93,19 @@ class HomeFollowingNewsAdapter(
bindImage(view.imageView(), feedItem.imageUrl) bindImage(view.imageView(), feedItem.imageUrl)
view.setOnFeedClick { onClickItem(ranking) } view.setOnFeedClick { onClickItem(ranking) }
} }
private fun HomeFollowingNewsUiItem.Ranking.toRankingMessage(rankText: String): String {
val messageResId = when (type) {
FollowingNewsType.CREATOR_RANKING -> R.string.screen_home_following_creator_ranking_news_message
FollowingNewsType.CONTENT_RANKING -> R.string.screen_home_following_content_ranking_news_message
FollowingNewsType.COMMUNITY_POST,
FollowingNewsType.AUDIO_CONTENT,
FollowingNewsType.PHOTO_CONTENT -> R.string.screen_home_following_content_ranking_news_message
}
val subject = if (type == FollowingNewsType.CREATOR_RANKING) creatorNickname else title
val context = view.context
return context.getString(messageResId, subject, rankText)
}
} }
class CommunityViewHolder( class CommunityViewHolder(
@@ -111,19 +115,19 @@ class HomeFollowingNewsAdapter(
) : NewsViewHolder(view) { ) : NewsViewHolder(view) {
override fun bind(item: HomeFollowingNewsUiItem) { override fun bind(item: HomeFollowingNewsUiItem) {
val community = item as HomeFollowingNewsUiItem.Content val community = item as HomeFollowingNewsUiItem.Community
val feedItem = FeedItem.Community( val feedItem = FeedItem.Community(
feedId = community.newsId, feedId = community.newsId,
creatorId = community.targetId.toString(), creatorId = community.targetId.toString(),
creatorName = community.creatorNickname, creatorName = community.creatorNickname,
creatorImageUrl = community.creatorProfileImageUrl, creatorImageUrl = community.creatorProfileImageUrl,
postId = community.targetId.toString(), postId = community.postId.toString(),
bodyText = community.body.ifBlank { community.title }, bodyText = community.content,
keywordText = "", keywordText = "",
createdAtText = community.visibleFromText, createdAtText = community.visibleFromText,
commentCount = 0, commentCount = community.commentCount,
likeCount = 0, likeCount = community.likeCount,
imageUrl = community.thumbnailImageUrl imageUrl = community.imageUrl
) )
view.setFeedSize(feedSize(FeedVariant.Community, parent)) view.setFeedSize(feedSize(FeedVariant.Community, parent))
view.bind(feedItem) view.bind(feedItem)
@@ -146,9 +150,9 @@ class HomeFollowingNewsAdapter(
creatorId = content.targetId.toString(), creatorId = content.targetId.toString(),
creatorName = content.creatorNickname, creatorName = content.creatorNickname,
creatorImageUrl = content.creatorProfileImageUrl, creatorImageUrl = content.creatorProfileImageUrl,
contentId = content.targetId.toString(), contentId = content.contentId.toString(),
contentTitle = content.title, contentTitle = content.title,
contentImageUrl = content.thumbnailImageUrl.orEmpty(), contentImageUrl = content.contentImageUrl.orEmpty(),
createdAtText = content.visibleFromText, createdAtText = content.visibleFromText,
category = content.type.toFeedContentCategory() category = content.type.toFeedContentCategory()
) )

View File

@@ -313,6 +313,7 @@
<string name="screen_home_following_on_air">On Air</string> <string name="screen_home_following_on_air">On Air</string>
<string name="screen_home_following_photo_content">Photo</string> <string name="screen_home_following_photo_content">Photo</string>
<string name="screen_home_following_creator_ranking_news_message">%1$s reached %2$s in this week\'s ranking!</string> <string name="screen_home_following_creator_ranking_news_message">%1$s reached %2$s in this week\'s ranking!</string>
<string name="screen_home_following_content_ranking_news_message">%1$s reached %2$s in this week\'s ranking!</string>
<string name="screen_home_following_empty">No following news to show.</string> <string name="screen_home_following_empty">No following news to show.</string>
<string name="screen_home_following_error">Could not load following news.</string> <string name="screen_home_following_error">Could not load following news.</string>
<string name="home_recommendation_activity_live">Live</string> <string name="home_recommendation_activity_live">Live</string>

View File

@@ -313,6 +313,7 @@
<string name="screen_home_following_on_air">On Air</string> <string name="screen_home_following_on_air">On Air</string>
<string name="screen_home_following_photo_content">グラビア</string> <string name="screen_home_following_photo_content">グラビア</string>
<string name="screen_home_following_creator_ranking_news_message">%1$sさんが今週のランキング%2$sに入りました</string> <string name="screen_home_following_creator_ranking_news_message">%1$sさんが今週のランキング%2$sに入りました</string>
<string name="screen_home_following_content_ranking_news_message">%1$sが今週のランキング%2$sに入りました</string>
<string name="screen_home_following_empty">表示できるフォロー中のお知らせがありません。</string> <string name="screen_home_following_empty">表示できるフォロー中のお知らせがありません。</string>
<string name="screen_home_following_error">フォロー中のお知らせを読み込めませんでした。</string> <string name="screen_home_following_error">フォロー中のお知らせを読み込めませんでした。</string>
<string name="home_recommendation_activity_live">ライブ</string> <string name="home_recommendation_activity_live">ライブ</string>

View File

@@ -312,6 +312,7 @@
<string name="screen_home_following_on_air">On Air</string> <string name="screen_home_following_on_air">On Air</string>
<string name="screen_home_following_photo_content">화보</string> <string name="screen_home_following_photo_content">화보</string>
<string name="screen_home_following_creator_ranking_news_message">%1$s님이 이번 주 랭킹 %2$s에 올랐어요!</string> <string name="screen_home_following_creator_ranking_news_message">%1$s님이 이번 주 랭킹 %2$s에 올랐어요!</string>
<string name="screen_home_following_content_ranking_news_message">%1$s 콘텐츠가 이번 주 랭킹 %2$s에 올랐어요!</string>
<string name="screen_home_following_empty">표시할 팔로잉 소식이 없습니다.</string> <string name="screen_home_following_empty">표시할 팔로잉 소식이 없습니다.</string>
<string name="screen_home_following_error">팔로잉 소식을 불러오지 못했습니다.</string> <string name="screen_home_following_error">팔로잉 소식을 불러오지 못했습니다.</string>
<string name="home_recommendation_activity_live">라이브</string> <string name="home_recommendation_activity_live">라이브</string>