From a2f3910e27f55ff7fa1ecb800ff33939981c02ff Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 21 May 2026 15:53:39 +0900 Subject: [PATCH] =?UTF-8?q?feat(feed):=20=ED=94=BC=EB=93=9C=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=ED=85=9C=20=EA=B3=84=EC=95=BD=EC=9D=84=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v2/widget/feed/FeedContentCategory.kt | 14 +++ .../sodalive/v2/widget/feed/FeedItem.kt | 47 ++++++++ .../sodalive/v2/widget/feed/FeedVariant.kt | 8 ++ .../sodalive/v2/widget/feed/FeedItemTest.kt | 105 ++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedContentCategory.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedVariant.kt create mode 100644 app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.kt diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedContentCategory.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedContentCategory.kt new file mode 100644 index 00000000..de3e6b15 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedContentCategory.kt @@ -0,0 +1,14 @@ +package kr.co.vividnext.sodalive.v2.widget.feed + +import androidx.annotation.StringRes +import kr.co.vividnext.sodalive.R + +enum class FeedContentCategory( + @StringRes val labelResId: Int, + val ratioWidth: Int, + val ratioHeight: Int +) { + Content(labelResId = R.string.feed_content_category_content, ratioWidth = 1, ratioHeight = 1), + Series(labelResId = R.string.feed_content_category_series, ratioWidth = 163, ratioHeight = 230), + Magazine(labelResId = R.string.feed_content_category_magazine, ratioWidth = 163, ratioHeight = 218) +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.kt new file mode 100644 index 00000000..f836e3fe --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.kt @@ -0,0 +1,47 @@ +package kr.co.vividnext.sodalive.v2.widget.feed + +sealed class FeedItem(open val feedId: String, val variant: FeedVariant) { + data class Rank( + override val feedId: String, + val imageUrl: String, + val rankText: String, + val message: String, + val highlightRanges: List + ) : FeedItem(feedId, FeedVariant.Rank) + + data class Live( + override val feedId: String, + val creatorId: String, + val creatorName: String, + val creatorImageUrl: String, + val liveId: String, + val liveTitle: String, + val createdAtText: String, + val endedMessage: String + ) : FeedItem(feedId, FeedVariant.Live) + + data class Content( + override val feedId: String, + val creatorId: String, + val creatorName: String, + val creatorImageUrl: String, + val contentId: String, + val contentTitle: String, + val contentImageUrl: String, + val createdAtText: String, + val category: FeedContentCategory = FeedContentCategory.Content + ) : FeedItem(feedId, FeedVariant.Content) + + data class Community( + override val feedId: String, + val creatorId: String, + val creatorName: String, + val creatorImageUrl: String, + val postId: String, + val bodyText: String, + val keywordText: String, + val createdAtText: String, + val commentCount: Int, + val likeCount: Int + ) : FeedItem(feedId, FeedVariant.Community) +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedVariant.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedVariant.kt new file mode 100644 index 00000000..3d588630 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedVariant.kt @@ -0,0 +1,8 @@ +package kr.co.vividnext.sodalive.v2.widget.feed + +enum class FeedVariant { + Rank, + Live, + Content, + Community +} diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.kt new file mode 100644 index 00000000..8ace5c0d --- /dev/null +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.kt @@ -0,0 +1,105 @@ +package kr.co.vividnext.sodalive.v2.widget.feed + +import org.junit.Assert.assertEquals +import kr.co.vividnext.sodalive.R +import org.junit.Test + +class FeedItemTest { + + @Test + fun `rank item exposes rank variant and message`() { + val item = FeedItem.Rank( + feedId = "feed-rank-1", + imageUrl = "https://example.com/rank.png", + rankText = "12위", + message = "크리에이터님이 5월 2주차 크리에이터 12위를 차지하였어요!", + highlightRanges = listOf(FeedRankHighlight(start = 22, endExclusive = 25)) + ) + + assertEquals(FeedVariant.Rank, item.variant) + assertEquals("12위", item.rankText) + assertEquals(1, item.highlightRanges.size) + } + + @Test + fun `live item exposes title and created time`() { + val item = FeedItem.Live( + feedId = "feed-live-1", + creatorId = "creator-1", + creatorName = "크리에이터이름", + creatorImageUrl = "https://example.com/profile.png", + liveId = "live-1", + liveTitle = "라이브 방송 이름", + createdAtText = "2분 전", + endedMessage = "서버에서 내려온 종료 문구" + ) + + assertEquals(FeedVariant.Live, item.variant) + assertEquals("라이브 방송 이름", item.liveTitle) + assertEquals("2분 전", item.createdAtText) + assertEquals("서버에서 내려온 종료 문구", item.endedMessage) + } + + @Test + fun `content item uses default category label`() { + val item = FeedItem.Content( + feedId = "feed-content-1", + creatorId = "creator-1", + creatorName = "크리에이터이름", + creatorImageUrl = "https://example.com/profile.png", + contentId = "content-1", + contentTitle = "콘텐츠 이름", + contentImageUrl = "https://example.com/content.png", + createdAtText = "2분 전" + ) + + assertEquals(FeedVariant.Content, item.variant) + assertEquals(FeedContentCategory.Content, item.category) + assertEquals(R.string.feed_content_category_content, item.category.labelResId) + } + + @Test + fun `content item accepts series and magazine category`() { + val series = FeedItem.Content( + feedId = "feed-content-series", + creatorId = "creator-1", + creatorName = "크리에이터이름", + creatorImageUrl = "https://example.com/profile.png", + contentId = "series-1", + contentTitle = "시리즈 이름", + contentImageUrl = "https://example.com/series.png", + createdAtText = "2분 전", + category = FeedContentCategory.Series + ) + val magazine = series.copy( + feedId = "feed-content-magazine", + contentId = "magazine-1", + contentTitle = "매거진 이름", + contentImageUrl = "https://example.com/magazine.png", + category = FeedContentCategory.Magazine + ) + + assertEquals(R.string.feed_content_category_series, series.category.labelResId) + assertEquals(R.string.feed_content_category_magazine, magazine.category.labelResId) + } + + @Test + fun `community item exposes reaction counts`() { + val item = FeedItem.Community( + feedId = "feed-community-1", + creatorId = "creator-1", + creatorName = "크리에이터 이름", + creatorImageUrl = "https://example.com/profile.png", + postId = "post-1", + bodyText = "커뮤니티 본문", + keywordText = "#키워드 #키워드", + createdAtText = "2분 전", + commentCount = 5, + likeCount = 6 + ) + + assertEquals(FeedVariant.Community, item.variant) + assertEquals(5, item.commentCount) + assertEquals(6, item.likeCount) + } +}