From 02f85f808db8bc74923fb147ab569587fb7f3f45 Mon Sep 17 00:00:00 2001 From: klaus Date: Wed, 27 May 2026 22:27:40 +0900 Subject: [PATCH] =?UTF-8?q?feat(banner):=20=EB=B0=B0=EB=84=88=20=EC=B9=B4?= =?UTF-8?q?=EC=9A=B4=ED=84=B0=EC=99=80=20=EC=83=81=ED=83=9C=20=EA=B3=84?= =?UTF-8?q?=EC=95=BD=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widget/banner/BannerCounterFormatter.kt | 7 +++ .../sodalive/v2/widget/banner/BannerState.kt | 33 +++++++++++++ .../banner/BannerCounterFormatterTest.kt | 28 +++++++++++ .../v2/widget/banner/BannerStateTest.kt | 49 +++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatter.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerState.kt create mode 100644 app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatterTest.kt create mode 100644 app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerStateTest.kt diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatter.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatter.kt new file mode 100644 index 00000000..fa943267 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatter.kt @@ -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) + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerState.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerState.kt new file mode 100644 index 00000000..f11a1706 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerState.kt @@ -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 +} diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatterTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatterTest.kt new file mode 100644 index 00000000..c9f8929e --- /dev/null +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerCounterFormatterTest.kt @@ -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) + } +} diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerStateTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerStateTest.kt new file mode 100644 index 00000000..8ea50457 --- /dev/null +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerStateTest.kt @@ -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) + } +}