feat(widget): 크리에이터 랭킹 위젯을 추가한다
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorRankingAdapterLayoutTest {
|
||||
|
||||
@Test
|
||||
fun `span count supports full two and three column ranking rows`() {
|
||||
assertEquals(6, CreatorRankingAdapter.GRID_SPAN_COUNT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `span lookup maps rank groups to expected row widths`() {
|
||||
val spanLookup = CreatorRankingAdapter.createSpanSizeLookup()
|
||||
|
||||
assertEquals(6, spanLookup.getSpanSize(0))
|
||||
(1..6).forEach { position ->
|
||||
assertEquals(3, spanLookup.getSpanSize(position))
|
||||
}
|
||||
(7..9).forEach { position ->
|
||||
assertEquals(2, spanLookup.getSpanSize(position))
|
||||
}
|
||||
listOf(10, 11, 20).forEach { position ->
|
||||
assertEquals(6, spanLookup.getSpanSize(position))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import android.os.Build
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorRankingBlurTest {
|
||||
|
||||
@Test
|
||||
fun `blocked image uses coil blur fallback before Android 12`() {
|
||||
assertTrue(CreatorRankingBlur.shouldUseCoilBlur(enabled = true, sdkInt = Build.VERSION_CODES.R))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blocked image keeps render effect path on Android 12 or later`() {
|
||||
assertFalse(CreatorRankingBlur.shouldUseCoilBlur(enabled = true, sdkInt = Build.VERSION_CODES.S))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `accessible image does not use coil blur fallback`() {
|
||||
assertFalse(CreatorRankingBlur.shouldUseCoilBlur(enabled = false, sdkInt = Build.VERSION_CODES.R))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorRankingDeltaPresentationTest {
|
||||
|
||||
@Test
|
||||
fun `increase shows caret and amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.Increase, amount = 4)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_increase, presentation.iconRes)
|
||||
assertTrue(presentation.showAmount)
|
||||
assertEquals("4", presentation.amountText)
|
||||
assertTrue(presentation.showPillBackground)
|
||||
assertEquals(14, presentation.iconWidthDp)
|
||||
assertEquals(14, presentation.iconHeightDp)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `decrease shows caret and amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.Decrease, amount = 4)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_decrease, presentation.iconRes)
|
||||
assertTrue(presentation.showAmount)
|
||||
assertEquals("4", presentation.amountText)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stay shows stay icon without amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.Stay, amount = 0)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_stay, presentation.iconRes)
|
||||
assertFalse(presentation.showAmount)
|
||||
assertNull(presentation.amountText)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `new shows new image without amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.New, amount = 0)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_new, presentation.iconRes)
|
||||
assertFalse(presentation.showAmount)
|
||||
assertNull(presentation.amountText)
|
||||
assertFalse(presentation.showPillBackground)
|
||||
assertEquals(36, presentation.iconWidthDp)
|
||||
assertEquals(23, presentation.iconHeightDp)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorRankingItemTest {
|
||||
|
||||
@Test
|
||||
fun `blocked item is inaccessible`() {
|
||||
val item = sampleItem(isBlocked = true)
|
||||
|
||||
assertTrue(item.isInaccessible)
|
||||
assertFalse(item.isTouchable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `accessible item is touchable`() {
|
||||
val item = sampleItem()
|
||||
|
||||
assertFalse(item.isInaccessible)
|
||||
assertTrue(item.isTouchable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `top ten blocked item hides creator name`() {
|
||||
val item = sampleItem(rank = 10, isBlocked = true)
|
||||
|
||||
assertEquals("", item.displayName(inaccessibleMessage = "접근할 수 없는 정보입니다."))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rank 11 blocked item shows inaccessible message`() {
|
||||
val item = sampleItem(rank = 11, isBlocked = true)
|
||||
|
||||
assertEquals("접근할 수 없는 정보입니다.", item.displayName(inaccessibleMessage = "접근할 수 없는 정보입니다."))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `accessible item shows creator name`() {
|
||||
val item = sampleItem(creatorName = "크리에이터 이름")
|
||||
|
||||
assertEquals("크리에이터 이름", item.displayName(inaccessibleMessage = "접근할 수 없는 정보입니다."))
|
||||
}
|
||||
|
||||
private fun sampleItem(
|
||||
creatorId: Long = 1L,
|
||||
rank: Int = 1,
|
||||
previousRank: Int? = 5,
|
||||
rankChangeType: CreatorRankingChangeType = CreatorRankingChangeType.Increase,
|
||||
rankChangeAmount: Int = 4,
|
||||
creatorName: String = "크리에이터 이름",
|
||||
imageUrl: String = "https://example.com/image.png",
|
||||
isBlocked: Boolean = false
|
||||
) = CreatorRankingItem(
|
||||
creatorId = creatorId,
|
||||
rank = rank,
|
||||
previousRank = previousRank,
|
||||
rankChangeType = rankChangeType,
|
||||
rankChangeAmount = rankChangeAmount,
|
||||
creatorName = creatorName,
|
||||
imageUrl = imageUrl,
|
||||
isBlocked = isBlocked
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorRankingLayoutCalculatorTest {
|
||||
|
||||
@Test
|
||||
fun `large card fills available width as square`() {
|
||||
val size = CreatorRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Large, itemsPerRow = 1)
|
||||
)
|
||||
|
||||
assertEquals(374, size.widthPx)
|
||||
assertEquals(374, size.heightPx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `large card excludes parent horizontal padding from available width`() {
|
||||
val size = CreatorRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
parentHorizontalPaddingPx = 40,
|
||||
horizontalGapPx = 4,
|
||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Large, itemsPerRow = 1)
|
||||
)
|
||||
|
||||
assertEquals(334, size.widthPx)
|
||||
assertEquals(334, size.heightPx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `compact card can use two columns`() {
|
||||
val size = CreatorRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Compact, itemsPerRow = 2)
|
||||
)
|
||||
|
||||
assertEquals(185, size.widthPx)
|
||||
assertEquals(185, size.heightPx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `compact card can use three columns`() {
|
||||
val size = CreatorRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Compact, itemsPerRow = 3)
|
||||
)
|
||||
|
||||
assertEquals(122, size.widthPx)
|
||||
assertEquals(122, size.heightPx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `horizontal card keeps figma aspect ratio`() {
|
||||
val size = CreatorRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Horizontal, itemsPerRow = 1)
|
||||
)
|
||||
|
||||
assertEquals(374, size.widthPx)
|
||||
assertEquals(100, size.heightPx)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class CreatorRankingPlacementTest {
|
||||
|
||||
@Test
|
||||
fun `rank 1 uses large variant and one item row`() {
|
||||
val placement = CreatorRankingPlacement.fromRank(1)
|
||||
|
||||
assertEquals(CreatorRankingCardVariant.Large, placement.variant)
|
||||
assertEquals(1, placement.itemsPerRow)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rank 2 to 7 uses compact variant and two item row`() {
|
||||
(2..7).forEach { rank ->
|
||||
val placement = CreatorRankingPlacement.fromRank(rank)
|
||||
|
||||
assertEquals(CreatorRankingCardVariant.Compact, placement.variant)
|
||||
assertEquals(2, placement.itemsPerRow)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rank 8 to 10 uses compact variant and three item row`() {
|
||||
(8..10).forEach { rank ->
|
||||
val placement = CreatorRankingPlacement.fromRank(rank)
|
||||
|
||||
assertEquals(CreatorRankingCardVariant.Compact, placement.variant)
|
||||
assertEquals(3, placement.itemsPerRow)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rank 11 or greater uses horizontal variant and one item row`() {
|
||||
listOf(11, 12, 100).forEach { rank ->
|
||||
val placement = CreatorRankingPlacement.fromRank(rank)
|
||||
|
||||
assertEquals(CreatorRankingCardVariant.Horizontal, placement.variant)
|
||||
assertEquals(1, placement.itemsPerRow)
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun `rank less than 1 is invalid`() {
|
||||
CreatorRankingPlacement.fromRank(0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user