feat(banner): 배너 카운터와 상태 계약을 추가한다

This commit is contained in:
2026-05-27 22:27:40 +09:00
parent 91a7eb3f4c
commit 02f85f808d
4 changed files with 117 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
package kr.co.vividnext.sodalive.v2.widget.banner
object BannerCounterFormatter {
fun format(currentIndex: Int, count: Int): String {
return "%02d / %02d".format(currentIndex + 1, count)
}
}

View File

@@ -0,0 +1,33 @@
package kr.co.vividnext.sodalive.v2.widget.banner
data class BannerState(
val displayMode: BannerDisplayMode,
val currentIndex: Int,
private val count: Int
) {
fun nextIndex(): Int = (currentIndex + 1) % count
fun previousIndex(): Int = (currentIndex - 1 + count) % count
companion object {
fun from(count: Int, currentIndex: Int): BannerState {
val displayMode = when (count) {
0 -> BannerDisplayMode.Hidden
1 -> BannerDisplayMode.Single
else -> BannerDisplayMode.Carousel
}
val correctedIndex = if (currentIndex in 0 until count) currentIndex else 0
return BannerState(
displayMode = displayMode,
currentIndex = correctedIndex,
count = count
)
}
}
}
enum class BannerDisplayMode {
Hidden,
Single,
Carousel
}

View File

@@ -0,0 +1,28 @@
package kr.co.vividnext.sodalive.v2.widget.banner
import org.junit.Assert.assertEquals
import org.junit.Test
class BannerCounterFormatterTest {
@Test
fun `20개 배너의 첫 번째 아이템은 1부터 시작하는 카운터로 표시한다`() {
val text = BannerCounterFormatter.format(currentIndex = 0, count = 20)
assertEquals("01 / 20", text)
}
@Test
fun `20개 배너의 열 번째 아이템은 1부터 시작하는 카운터로 표시한다`() {
val text = BannerCounterFormatter.format(currentIndex = 9, count = 20)
assertEquals("10 / 20", text)
}
@Test
fun `1개 배너도 formatter는 양쪽을 두 자리로 표시한다`() {
val text = BannerCounterFormatter.format(currentIndex = 0, count = 1)
assertEquals("01 / 01", text)
}
}

View File

@@ -0,0 +1,49 @@
package kr.co.vividnext.sodalive.v2.widget.banner
import org.junit.Assert.assertEquals
import org.junit.Test
class BannerStateTest {
@Test
fun `배너 개수가 0이면 숨김 모드다`() {
val state = BannerState.from(count = 0, currentIndex = 0)
assertEquals(BannerDisplayMode.Hidden, state.displayMode)
}
@Test
fun `배너 개수가 1이면 단일 모드다`() {
val state = BannerState.from(count = 1, currentIndex = 0)
assertEquals(BannerDisplayMode.Single, state.displayMode)
}
@Test
fun `배너 개수가 2이면 캐러셀 모드다`() {
val state = BannerState.from(count = 2, currentIndex = 0)
assertEquals(BannerDisplayMode.Carousel, state.displayMode)
}
@Test
fun `마지막 배너의 다음 index는 첫 번째로 순환한다`() {
val state = BannerState.from(count = 3, currentIndex = 2)
assertEquals(0, state.nextIndex())
}
@Test
fun `첫 번째 배너의 이전 index는 마지막으로 순환한다`() {
val state = BannerState.from(count = 3, currentIndex = 0)
assertEquals(2, state.previousIndex())
}
@Test
fun `현재 index가 범위를 벗어나면 첫 번째로 보정한다`() {
val state = BannerState.from(count = 3, currentIndex = 3)
assertEquals(0, state.currentIndex)
}
}