From 6e92538366b0a43e1e72850b87b496c6f92eab2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=BC=ED=98=81?= Date: Thu, 4 Jun 2026 15:41:48 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20AfternoteFieldContainer=20=EB=B9=84?= =?UTF-8?q?=ED=99=9C=EC=84=B1=20=EC=83=81=ED=83=9C=20=EC=8B=9C=EA=B0=81?= =?UTF-8?q?=EC=A0=81=20=EB=8C=80=EC=9D=91=20=EB=B0=8F=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=B0=EC=83=B7=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `AfternoteFieldContainer`의 `enabled` 상태에 따라 배경색과 보더 색상이 변경되도록 로직 수정 - 비활성 상태 시 배경(`white` -> `gray2`) 및 보더(`gray2` -> `gray3`) 색상을 전환하여 시각적 피드백 강화 - 컴포넌트 KDoc에 상태별 색상 변경 규칙 및 디자인 의도 설명 추가 - `AfternoteFieldContainerScreenshotTest`를 작성하여 활성/비활성 상태에 대한 시각적 회귀 테스트 자동화 및 레퍼런스 이미지 추가 --- .../core/ui/AfternoteFieldContainer.kt | 10 ++- .../AfternoteFieldContainerScreenshotTest.kt | 60 ++++++++++++++++++ ...ContainerDisabledScreenshot_748aa731_0.png | Bin 0 -> 5332 bytes ...dContainerEnabledScreenshot_748aa731_0.png | Bin 0 -> 5317 bytes 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 core/ui/src/screenshotTest/kotlin/com/afternote/core/ui/AfternoteFieldContainerScreenshotTest.kt create mode 100644 core/ui/src/screenshotTestDebug/reference/com/afternote/core/ui/AfternoteFieldContainerScreenshotTestKt/afternoteFieldContainerDisabledScreenshot_748aa731_0.png create mode 100644 core/ui/src/screenshotTestDebug/reference/com/afternote/core/ui/AfternoteFieldContainerScreenshotTestKt/afternoteFieldContainerEnabledScreenshot_748aa731_0.png diff --git a/core/ui/src/main/kotlin/com/afternote/core/ui/AfternoteFieldContainer.kt b/core/ui/src/main/kotlin/com/afternote/core/ui/AfternoteFieldContainer.kt index b148abfe..ae50994e 100644 --- a/core/ui/src/main/kotlin/com/afternote/core/ui/AfternoteFieldContainer.kt +++ b/core/ui/src/main/kotlin/com/afternote/core/ui/AfternoteFieldContainer.kt @@ -27,6 +27,10 @@ import com.afternote.core.ui.theme.AfternoteTheme * * [onClick] 을 주면 ripple 이 둥근 코너 안쪽으로 잘리도록 `clip` 뒤에 `clickable` 이 걸린다. * + * [enabled] 가 false 면 클릭이 차단될 뿐 아니라 배경이 흰색→gray2, 보더가 gray2→gray3 로 바뀌어 + * 비활성 상태가 시각적으로 드러난다 (비활성 버튼 `AfternoteButtonType.Un` 과 동일 팔레트). 내부 [content] + * 의 색은 슬롯 주입이라 호출부가 상태에 맞춰 결정한다. + * * 폭 / 크기 정책은 호출부가 [modifier] 로 결정 (Compose API 가이드라인: element function 의 modifier * default 는 빈 `Modifier`). 부모 폭 차지가 필요하면 `Modifier.fillMaxWidth()`, Row 안에서 * 가변 비율이면 `Modifier.weight(...)` 등을 명시적으로 넘긴다. @@ -39,12 +43,14 @@ fun AfternoteFieldContainer( enabled: Boolean = true, content: @Composable RowScope.() -> Unit, ) { + val backgroundColor = if (enabled) AfternoteDesign.colors.white else AfternoteDesign.colors.gray2 + val borderColor = if (enabled) AfternoteDesign.colors.gray2 else AfternoteDesign.colors.gray3 Row( modifier = modifier .clip(RoundedCornerShape(8.dp)) - .background(AfternoteDesign.colors.white) - .border(1.dp, AfternoteDesign.colors.gray2, RoundedCornerShape(8.dp)) + .background(backgroundColor) + .border(1.dp, borderColor, RoundedCornerShape(8.dp)) .then( if (onClick != null) { Modifier.clickable(enabled = enabled, onClick = onClick) diff --git a/core/ui/src/screenshotTest/kotlin/com/afternote/core/ui/AfternoteFieldContainerScreenshotTest.kt b/core/ui/src/screenshotTest/kotlin/com/afternote/core/ui/AfternoteFieldContainerScreenshotTest.kt new file mode 100644 index 00000000..8217a982 --- /dev/null +++ b/core/ui/src/screenshotTest/kotlin/com/afternote/core/ui/AfternoteFieldContainerScreenshotTest.kt @@ -0,0 +1,60 @@ +package com.afternote.core.ui + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.afternote.core.ui.theme.AfternoteDesign +import com.afternote.core.ui.theme.AfternoteTheme +import com.android.tools.screenshot.PreviewTest + +/** + * [AfternoteFieldContainer] 의 시각 회귀 baseline — enabled / disabled 두 상태 (이슈 #342). + * + * disabled 일 때 배경(흰색→gray2)·보더(gray2→gray3) 가 비활성 색으로 전환되는지 고정한다. + * 의도된 시각 변경 시 `./gradlew :core:ui:updateScreenshotTest` 로 baseline 갱신. + */ +@PreviewTest +@Preview(showBackground = true) +@Composable +internal fun afternoteFieldContainerEnabledScreenshot() { + AfternoteTheme { + AfternoteFieldContainer( + onClick = {}, + enabled = true, + modifier = + Modifier + .padding(16.dp) + .fillMaxWidth(), + ) { + Text( + text = "활성 필드", + style = AfternoteDesign.typography.bodyLargeR, + ) + } + } +} + +@PreviewTest +@Preview(showBackground = true) +@Composable +internal fun afternoteFieldContainerDisabledScreenshot() { + AfternoteTheme { + AfternoteFieldContainer( + onClick = {}, + enabled = false, + modifier = + Modifier + .padding(16.dp) + .fillMaxWidth(), + ) { + Text( + text = "비활성 필드", + style = AfternoteDesign.typography.bodyLargeR, + ) + } + } +} diff --git a/core/ui/src/screenshotTestDebug/reference/com/afternote/core/ui/AfternoteFieldContainerScreenshotTestKt/afternoteFieldContainerDisabledScreenshot_748aa731_0.png b/core/ui/src/screenshotTestDebug/reference/com/afternote/core/ui/AfternoteFieldContainerScreenshotTestKt/afternoteFieldContainerDisabledScreenshot_748aa731_0.png new file mode 100644 index 0000000000000000000000000000000000000000..ae6a24c4445105aa43e6085451955132e01796bc GIT binary patch literal 5332 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 Ww$UkDs)`^_x&G+oRQ*H9#s3D^?{Bk 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