feat(widget): 콘텐츠 랭킹 위젯을 추가한다
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.contentranking
|
||||
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.v2.widget.ranking.RankingChangeType
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class ContentRankingDeltaPresentationTest {
|
||||
|
||||
@Test
|
||||
fun `increase shows amount and increase caret`() {
|
||||
val presentation = ContentRankingDeltaPresentation.from(RankingChangeType.Increase, amount = 4)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_increase, presentation.iconRes)
|
||||
assertEquals("4", presentation.amountText)
|
||||
assertTrue(presentation.showAmount)
|
||||
assertFalse(presentation.replaceWithNewIcon)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `decrease shows amount and decrease caret`() {
|
||||
val presentation = ContentRankingDeltaPresentation.from(RankingChangeType.Decrease, amount = 2)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_decrease, presentation.iconRes)
|
||||
assertEquals("2", presentation.amountText)
|
||||
assertTrue(presentation.showAmount)
|
||||
assertFalse(presentation.replaceWithNewIcon)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stay shows only stay icon`() {
|
||||
val presentation = ContentRankingDeltaPresentation.from(RankingChangeType.Stay, amount = 0)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_stay, presentation.iconRes)
|
||||
assertEquals("", presentation.amountText)
|
||||
assertFalse(presentation.showAmount)
|
||||
assertFalse(presentation.replaceWithNewIcon)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `new replaces rank num with new icon`() {
|
||||
val presentation = ContentRankingDeltaPresentation.from(RankingChangeType.New, amount = null)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_new, presentation.iconRes)
|
||||
assertEquals("", presentation.amountText)
|
||||
assertFalse(presentation.showAmount)
|
||||
assertTrue(presentation.replaceWithNewIcon)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.contentranking
|
||||
|
||||
import kr.co.vividnext.sodalive.v2.widget.ranking.RankingChangeType
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class ContentRankingItemTest {
|
||||
|
||||
@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 content and creator names`() {
|
||||
val item = sampleItem(rank = 10, isBlocked = true)
|
||||
|
||||
assertEquals("", item.displayContentName(inaccessibleMessage = "접근할 수 없는 정보입니다."))
|
||||
assertEquals("", item.displayCreatorName())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rank 11 blocked item shows inaccessible message as single line`() {
|
||||
val item = sampleItem(rank = 11, isBlocked = true)
|
||||
|
||||
assertEquals("접근할 수 없는 정보입니다.", item.displayContentName(inaccessibleMessage = "접근할 수 없는 정보입니다."))
|
||||
assertEquals("", item.displayCreatorName())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `accessible item shows original names`() {
|
||||
val item = sampleItem(contentName = "콘텐츠 이름", creatorName = "크리에이터 이름")
|
||||
|
||||
assertEquals("콘텐츠 이름", item.displayContentName(inaccessibleMessage = "접근할 수 없는 정보입니다."))
|
||||
assertEquals("크리에이터 이름", item.displayCreatorName())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `content title max length follows rank range`() {
|
||||
assertEquals(16, sampleItem(rank = 1).contentNameMaxLength)
|
||||
assertEquals(8, sampleItem(rank = 2).contentNameMaxLength)
|
||||
assertEquals(8, sampleItem(rank = 10).contentNameMaxLength)
|
||||
assertEquals(12, sampleItem(rank = 11).contentNameMaxLength)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `accessible content name is truncated by rank range`() {
|
||||
assertEquals(
|
||||
"1234567890123456...",
|
||||
sampleItem(rank = 1, contentName = "12345678901234567").displayContentName(inaccessibleMessage = "접근할 수 없는 정보입니다.")
|
||||
)
|
||||
assertEquals(
|
||||
"12345678...",
|
||||
sampleItem(rank = 2, contentName = "123456789").displayContentName(inaccessibleMessage = "접근할 수 없는 정보입니다.")
|
||||
)
|
||||
assertEquals(
|
||||
"123456789012...",
|
||||
sampleItem(rank = 11, contentName = "1234567890123").displayContentName(inaccessibleMessage = "접근할 수 없는 정보입니다.")
|
||||
)
|
||||
}
|
||||
|
||||
private fun sampleItem(
|
||||
rank: Int = 1,
|
||||
contentName: String = "콘텐츠 이름",
|
||||
creatorName: String = "크리에이터 이름",
|
||||
isBlocked: Boolean = false
|
||||
) = ContentRankingItem(
|
||||
contentId = "content-1",
|
||||
creatorId = "creator-1",
|
||||
rank = rank,
|
||||
previousRank = 5,
|
||||
rankChangeType = RankingChangeType.Increase,
|
||||
rankChangeAmount = 4,
|
||||
contentName = contentName,
|
||||
creatorName = creatorName,
|
||||
imageUrl = "https://example.com/image.png",
|
||||
isBlocked = isBlocked
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.contentranking
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class ContentRankingLayoutCalculatorTest {
|
||||
|
||||
@Test
|
||||
fun `large item keeps figma large ratio`() {
|
||||
val size = ContentRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = ContentRankingPlacement(ContentRankingCardVariant.Large, itemsPerRow = 1)
|
||||
)
|
||||
|
||||
assertEquals(374, size.widthPx)
|
||||
assertEquals(238, size.heightPx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `medium grid item width divides available width by items per row`() {
|
||||
val size = ContentRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = ContentRankingPlacement(ContentRankingCardVariant.MediumGrid, itemsPerRow = 2)
|
||||
)
|
||||
|
||||
assertEquals(185, size.widthPx)
|
||||
assertEquals(185, size.heightPx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `small grid item subtracts two gaps`() {
|
||||
val size = ContentRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = ContentRankingPlacement(ContentRankingCardVariant.SmallGrid, itemsPerRow = 3)
|
||||
)
|
||||
|
||||
assertEquals(122, size.widthPx)
|
||||
assertEquals(122, size.heightPx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `horizontal item keeps figma ratio`() {
|
||||
val size = ContentRankingLayoutCalculator.calculate(
|
||||
parentWidthPx = 374,
|
||||
horizontalGapPx = 4,
|
||||
placement = ContentRankingPlacement(ContentRankingCardVariant.Horizontal, itemsPerRow = 1)
|
||||
)
|
||||
|
||||
assertEquals(374, size.widthPx)
|
||||
assertEquals(100, size.heightPx)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.contentranking
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class ContentRankingPlacementTest {
|
||||
|
||||
@Test
|
||||
fun `rank 1 uses large variant and one item row`() {
|
||||
val placement = ContentRankingPlacement.fromRank(1)
|
||||
|
||||
assertEquals(ContentRankingCardVariant.Large, placement.variant)
|
||||
assertEquals(1, placement.itemsPerRow)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rank 2 to 7 uses medium grid variant and two item row`() {
|
||||
(2..7).forEach { rank ->
|
||||
val placement = ContentRankingPlacement.fromRank(rank)
|
||||
|
||||
assertEquals(ContentRankingCardVariant.MediumGrid, placement.variant)
|
||||
assertEquals(2, placement.itemsPerRow)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rank 8 to 10 uses small grid variant and three item row`() {
|
||||
(8..10).forEach { rank ->
|
||||
val placement = ContentRankingPlacement.fromRank(rank)
|
||||
|
||||
assertEquals(ContentRankingCardVariant.SmallGrid, 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 = ContentRankingPlacement.fromRank(rank)
|
||||
|
||||
assertEquals(ContentRankingCardVariant.Horizontal, placement.variant)
|
||||
assertEquals(1, placement.itemsPerRow)
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun `rank less than 1 is invalid`() {
|
||||
ContentRankingPlacement.fromRank(0)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.v2.widget.ranking.RankingChangeType
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNull
|
||||
@@ -11,7 +12,7 @@ class CreatorRankingDeltaPresentationTest {
|
||||
|
||||
@Test
|
||||
fun `increase shows caret and amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.Increase, amount = 4)
|
||||
val presentation = CreatorRankingDeltaPresentation.from(RankingChangeType.Increase, amount = 4)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_increase, presentation.iconRes)
|
||||
assertTrue(presentation.showAmount)
|
||||
@@ -23,7 +24,7 @@ class CreatorRankingDeltaPresentationTest {
|
||||
|
||||
@Test
|
||||
fun `decrease shows caret and amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.Decrease, amount = 4)
|
||||
val presentation = CreatorRankingDeltaPresentation.from(RankingChangeType.Decrease, amount = 4)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_decrease, presentation.iconRes)
|
||||
assertTrue(presentation.showAmount)
|
||||
@@ -32,7 +33,7 @@ class CreatorRankingDeltaPresentationTest {
|
||||
|
||||
@Test
|
||||
fun `stay shows stay icon without amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.Stay, amount = 0)
|
||||
val presentation = CreatorRankingDeltaPresentation.from(RankingChangeType.Stay, amount = 0)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_caret_stay, presentation.iconRes)
|
||||
assertFalse(presentation.showAmount)
|
||||
@@ -41,7 +42,7 @@ class CreatorRankingDeltaPresentationTest {
|
||||
|
||||
@Test
|
||||
fun `new shows new image without amount`() {
|
||||
val presentation = CreatorRankingDeltaPresentation.from(CreatorRankingChangeType.New, amount = 0)
|
||||
val presentation = CreatorRankingDeltaPresentation.from(RankingChangeType.New, amount = 0)
|
||||
|
||||
assertEquals(R.drawable.ic_rank_new, presentation.iconRes)
|
||||
assertFalse(presentation.showAmount)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
||||
|
||||
import kr.co.vividnext.sodalive.v2.widget.ranking.RankingChangeType
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
@@ -48,7 +49,7 @@ class CreatorRankingItemTest {
|
||||
creatorId: Long = 1L,
|
||||
rank: Int = 1,
|
||||
previousRank: Int? = 5,
|
||||
rankChangeType: CreatorRankingChangeType = CreatorRankingChangeType.Increase,
|
||||
rankChangeType: RankingChangeType = RankingChangeType.Increase,
|
||||
rankChangeAmount: Int = 4,
|
||||
creatorName: String = "크리에이터 이름",
|
||||
imageUrl: String = "https://example.com/image.png",
|
||||
|
||||
Reference in New Issue
Block a user