From 6d980e319be7dd335cd22d4c8e65c5e6d87e607e Mon Sep 17 00:00:00 2001 From: klaus Date: Mon, 8 Jun 2026 15:22:10 +0900 Subject: [PATCH] =?UTF-8?q?feat(widget):=20=EB=9E=AD=ED=82=B9=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=88=9C=EC=9C=84=20=EB=B3=80=EB=8F=99=20=EC=88=A8?= =?UTF-8?q?=EA=B9=80=EC=9D=84=20=EC=A0=81=EC=9A=A9=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreatorRankingCompactCardView.kt | 18 +++- .../CreatorRankingHorizontalCardView.kt | 14 ++- .../CreatorRankingLargeCardView.kt | 8 +- .../CreatorRankingAdapterLayoutTest.kt | 85 +++++++++++++++++++ 4 files changed, 119 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt index cb43ff0b..088a317b 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt @@ -77,6 +77,9 @@ class CreatorRankingCompactCardView @JvmOverloads constructor( } private fun bindDelta(item: CreatorRankingItem) { + requireNotNull(deltaGroup).visibility = if (item.showRankChange) View.VISIBLE else View.GONE + if (!item.showRankChange) return + val presentation = CreatorRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount) applyDeltaContainer(presentation) requireNotNull(deltaIcon).apply { @@ -130,7 +133,10 @@ class CreatorRankingCompactCardView @JvmOverloads constructor( leftMargin = (10 * scale).roundToInt() topMargin = (70 * scale).roundToInt() } - requireNotNull(nameText).layoutParams = LayoutParams((165 * scale).roundToInt(), ViewGroup.LayoutParams.WRAP_CONTENT).apply { + requireNotNull(nameText).layoutParams = LayoutParams( + (165 * scale).roundToInt(), + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { leftMargin = ((size.widthPx - (165 * scale)) / 2f).roundToInt() topMargin = (145 * scale).roundToInt() } @@ -138,7 +144,10 @@ class CreatorRankingCompactCardView @JvmOverloads constructor( private fun positionSmall(size: CreatorRankingCardSize) { val scale = size.widthPx / 122f - requireNotNull(rankText).layoutParams = LayoutParams((42 * scale).roundToInt(), (56 * scale).roundToInt()).apply { + requireNotNull(rankText).layoutParams = LayoutParams( + (42 * scale).roundToInt(), + (56 * scale).roundToInt() + ).apply { leftMargin = (8 * scale).roundToInt() } findViewById(R.id.ll_creator_ranking_delta).layoutParams = LayoutParams( @@ -148,7 +157,10 @@ class CreatorRankingCompactCardView @JvmOverloads constructor( leftMargin = (10 * scale).roundToInt() topMargin = (49 * scale).roundToInt() } - requireNotNull(nameText).layoutParams = LayoutParams((102 * scale).roundToInt(), ViewGroup.LayoutParams.WRAP_CONTENT).apply { + requireNotNull(nameText).layoutParams = LayoutParams( + (102 * scale).roundToInt(), + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { leftMargin = ((size.widthPx - (102 * scale)) / 2f).roundToInt() topMargin = (98 * scale).roundToInt() } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt index a573ed67..717a2371 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt @@ -69,6 +69,10 @@ class CreatorRankingHorizontalCardView @JvmOverloads constructor( } private fun bindDelta(item: CreatorRankingItem) { + val deltaGroup = findViewById(R.id.ll_creator_ranking_delta) + deltaGroup.visibility = if (item.showRankChange) View.VISIBLE else View.GONE + if (!item.showRankChange) return + val presentation = CreatorRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount) applyDeltaContainer(presentation) requireNotNull(deltaIcon).apply { @@ -101,7 +105,10 @@ class CreatorRankingHorizontalCardView @JvmOverloads constructor( private fun positionViews(size: CreatorRankingCardSize) { val scale = size.widthPx / 374f - requireNotNull(rankGroup).layoutParams = LayoutParams((49 * scale).roundToInt(), ViewGroup.LayoutParams.WRAP_CONTENT).apply { + requireNotNull(rankGroup).layoutParams = LayoutParams( + (49 * scale).roundToInt(), + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { leftMargin = (14 * scale).roundToInt() topMargin = (14 * scale).roundToInt() } @@ -110,7 +117,10 @@ class CreatorRankingHorizontalCardView @JvmOverloads constructor( leftMargin = (77 * scale).roundToInt() topMargin = (10 * scale).roundToInt() } - requireNotNull(nameText).layoutParams = LayoutParams((189 * scale).roundToInt(), ViewGroup.LayoutParams.WRAP_CONTENT).apply { + requireNotNull(nameText).layoutParams = LayoutParams( + (189 * scale).roundToInt(), + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { leftMargin = (171 * scale).roundToInt() topMargin = (39 * scale).roundToInt() } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt index 59854a03..76135bba 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt @@ -77,6 +77,9 @@ class CreatorRankingLargeCardView @JvmOverloads constructor( } private fun bindDelta(item: CreatorRankingItem) { + requireNotNull(deltaGroup).visibility = if (item.showRankChange) View.VISIBLE else View.GONE + if (!item.showRankChange) return + val presentation = CreatorRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount) applyDeltaContainer(presentation) requireNotNull(deltaIcon).apply { @@ -114,7 +117,10 @@ class CreatorRankingLargeCardView @JvmOverloads constructor( topMargin = 0 } requireNotNull(rankText).applyCreatorRankingRankGradient() - requireNotNull(nameText).layoutParams = LayoutParams((334 * scale).roundToInt(), ViewGroup.LayoutParams.WRAP_CONTENT).apply { + requireNotNull(nameText).layoutParams = LayoutParams( + (334 * scale).roundToInt(), + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { leftMargin = ((size.widthPx - (334 * scale)) / 2f).roundToInt() topMargin = (305 * scale).roundToInt() } diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt index 4135d88e..b8afb1b2 100644 --- a/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt @@ -1,8 +1,20 @@ package kr.co.vividnext.sodalive.v2.widget.creatorranking +import android.app.Application +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import androidx.test.core.app.ApplicationProvider +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.v2.widget.ranking.RankingChangeType.Increase import org.junit.Assert.assertEquals import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [28], application = Application::class) class CreatorRankingAdapterLayoutTest { @Test @@ -25,4 +37,77 @@ class CreatorRankingAdapterLayoutTest { assertEquals(6, spanLookup.getSpanSize(position)) } } + + @Test + fun `large card는 순위 변동 숨김이면 delta를 숨긴다`() { + val view = inflateView(R.layout.view_creator_ranking_large_card) + + view.bind(sampleItem(showRankChange = false)) + + assertEquals(View.GONE, view.findViewById(R.id.ll_creator_ranking_delta).visibility) + } + + @Test + fun `large card는 순위 변동 표시이면 delta를 보여준다`() { + val view = inflateView(R.layout.view_creator_ranking_large_card) + + view.bind(sampleItem(showRankChange = true)) + + assertEquals(View.VISIBLE, view.findViewById(R.id.ll_creator_ranking_delta).visibility) + } + + @Test + fun `compact card는 순위 변동 숨김이면 delta를 숨긴다`() { + val view = inflateView(R.layout.view_creator_ranking_compact_card) + + view.bind(sampleItem(showRankChange = false)) + + assertEquals(View.GONE, view.findViewById(R.id.ll_creator_ranking_delta).visibility) + } + + @Test + fun `compact card는 순위 변동 표시이면 delta를 보여준다`() { + val view = inflateView(R.layout.view_creator_ranking_compact_card) + + view.bind(sampleItem(showRankChange = true)) + + assertEquals(View.VISIBLE, view.findViewById(R.id.ll_creator_ranking_delta).visibility) + } + + @Test + fun `horizontal card는 순위 변동 숨김이면 delta를 숨긴다`() { + val view = inflateView(R.layout.view_creator_ranking_horizontal_card) + + view.bind(sampleItem(rank = 11, showRankChange = false)) + + assertEquals(View.GONE, view.findViewById(R.id.ll_creator_ranking_delta).visibility) + } + + @Test + fun `horizontal card는 순위 변동 표시이면 delta를 보여준다`() { + val view = inflateView(R.layout.view_creator_ranking_horizontal_card) + + view.bind(sampleItem(rank = 11, showRankChange = true)) + + assertEquals(View.VISIBLE, view.findViewById(R.id.ll_creator_ranking_delta).visibility) + } + + private inline fun inflateView(layoutResId: Int): T { + val context = ApplicationProvider.getApplicationContext() + return LayoutInflater.from(context).inflate(layoutResId, null, false) as T + } + + private fun sampleItem( + rank: Int = 1, + showRankChange: Boolean = true + ) = CreatorRankingItem( + creatorId = 1L, + rank = rank, + rankChangeType = Increase, + rankChangeAmount = 4, + creatorName = "크리에이터 이름", + imageUrl = "https://example.com/image.png", + isBlocked = false, + showRankChange = showRankChange + ) }