From 4bb727388d6098f4520c339ed1a8deaba5d2a8a5 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Mon, 26 Jan 2026 04:00:25 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20PrezelRadio=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인 시스템에 사용될 `PrezelRadio` 컴포넌트를 추가했습니다. 이 컴포넌트는 선택 상태에 따라 채워진 아이콘과 외곽선 아이콘으로 구분되며, 아이콘만 표시하거나 텍스트 라벨과 함께 사용할 수 있습니다. * **컴포넌트 추가**: `PrezelRadio` 컴포저블 함수를 추가했습니다. * 아이콘만 있는 버전과 텍스트 라벨을 포함한 버전을 오버로딩하여 제공합니다. * `checked` 상태에 따라 `RadioCircleFilled`와 `RadioCircleOutlined` 아이콘을 사용합니다. * **크기 옵션 추가**: `PrezelRadioSize` enum (`REGULAR`, `LARGE`)을 추가하여 라디오 버튼의 크기를 조절할 수 있도록 했습니다. * **미리보기 추가**: `PrezelRadioPreview`를 통해 다양한 상태와 크기의 라디오 버튼을 시각적으로 확인할 수 있도록 구현했습니다. --- .../designsystem/component/PrezelRadio.kt | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt new file mode 100644 index 0000000..3df6c20 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt @@ -0,0 +1,153 @@ +package com.team.prezel.core.designsystem.component + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.selection.toggleable +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.material3.ripple +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.icon.PrezelIcons +import com.team.prezel.core.designsystem.preview.PreviewScaffold +import com.team.prezel.core.designsystem.preview.SectionTitle +import com.team.prezel.core.designsystem.preview.ThemePreview +import com.team.prezel.core.designsystem.theme.PrezelTheme + +/** + * 라디오 버튼의 크기 정의. + * + * @property value 라디오 버튼의 터치 영역 크기 + */ +enum class PrezelRadioSize( + val value: Dp, +) { + REGULAR(40.dp), + LARGE(48.dp), +} + +/** + * 아이콘만 표시되는 라디오 버튼. + * + * @param checked 현재 선택 여부 + * @param onCheckedChange 선택 상태 변경 콜백 + * @param size 라디오 버튼 크기 + */ +@Composable +fun PrezelRadio( + checked: Boolean, + onCheckedChange: (checked: Boolean) -> Unit, + modifier: Modifier = Modifier, + size: PrezelRadioSize = PrezelRadioSize.REGULAR, +) { + val tintColor = if (checked) PrezelTheme.colors.interactiveRegular else PrezelTheme.colors.iconDisabled + val icon = if (checked) PrezelIcons.RadioCircleFilled else PrezelIcons.RadioCircleOutlined + + Icon( + painter = painterResource(icon), + contentDescription = null, + tint = tintColor, + modifier = modifier + .size(size.value) + .toggleable( + value = checked, + onValueChange = onCheckedChange, + role = Role.RadioButton, + indication = null, + interactionSource = null, + ).padding(PrezelTheme.spacing.V8), + ) +} + +/** + * 텍스트와 함께 표시되는 라디오 버튼. + * + * @param text 라디오 버튼 라벨 텍스트 + * @param checked 현재 선택 여부 + * @param onCheckedChange 선택 상태 변경 콜백 + * @param size 라디오 버튼 크기 + */ +@Composable +fun PrezelRadio( + text: String, + checked: Boolean, + onCheckedChange: (checked: Boolean) -> Unit, + modifier: Modifier = Modifier, + size: PrezelRadioSize = PrezelRadioSize.REGULAR, + textStyle: TextStyle = PrezelTheme.typography.body2Medium, + textColor: Color = PrezelTheme.colors.textLarge, +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .fillMaxWidth() + .clip(PrezelTheme.shapes.V6) + .toggleable( + value = checked, + onValueChange = onCheckedChange, + role = Role.RadioButton, + indication = ripple(), + interactionSource = null, + ), + ) { + PrezelRadio( + checked = checked, + onCheckedChange = {}, + size = size, + modifier = Modifier.clearAndSetSemantics { }, + ) + + Spacer(modifier = Modifier.padding(PrezelTheme.spacing.V4)) + + Text( + text = text, + style = textStyle, + color = textColor, + ) + } +} + +@ThemePreview +@Composable +private fun PrezelRadioPreview() { + var checked by remember { mutableStateOf(false) } + + PrezelTheme { + PreviewScaffold { + SectionTitle("PrezelRadioSize.REGULAR") + Text("Checked: true") + PrezelRadio(checked = true, onCheckedChange = {}, size = PrezelRadioSize.REGULAR) + Text("Checked: false") + PrezelRadio(checked = false, onCheckedChange = {}, size = PrezelRadioSize.REGULAR) + Text("PrezelRadio with text") + PrezelRadio(checked = checked, onCheckedChange = { checked = it }, text = "텍스트", size = PrezelRadioSize.REGULAR) + + Spacer(modifier = Modifier.height(20.dp)) + + SectionTitle(" PrezelRadioSize.LARGE") + Text("Checked: true") + PrezelRadio(checked = true, onCheckedChange = {}, size = PrezelRadioSize.LARGE) + Text("Checked: false") + PrezelRadio(checked = false, onCheckedChange = {}, size = PrezelRadioSize.LARGE) + Text("PrezelRadio with text") + PrezelRadio(checked = checked, onCheckedChange = { checked = it }, text = "텍스트", size = PrezelRadioSize.LARGE) + } + } +} From 029a29ec9e798321d1dc22cf48f387b5fc926975 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Mon, 26 Jan 2026 04:02:34 +0900 Subject: [PATCH 2/6] =?UTF-8?q?style:=20Detekt=20`LongParameterList`=20?= =?UTF-8?q?=EA=B7=9C=EC=B9=99=20=EC=9E=84=EA=B3=84=EA=B0=92=20=EC=A1=B0?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detekt의 정적 분석 규칙 중 `LongParameterList`의 함수 파라미터 최대 개수(`functionThreshold`)를 7에서 8로 상향 조정했습니다. --- Prezel/detekt-config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Prezel/detekt-config.yml b/Prezel/detekt-config.yml index 4829866..9660790 100644 --- a/Prezel/detekt-config.yml +++ b/Prezel/detekt-config.yml @@ -36,7 +36,7 @@ complexity: threshold: 40 LongParameterList: active: true - functionThreshold: 7 + functionThreshold: 8 constructorThreshold: 8 CyclomaticComplexMethod: active: true From c2ded485e4325f0e983338b9de67b72b73e8b939 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Mon, 26 Jan 2026 04:09:03 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20`PreviewScaffold`=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=EB=A5=BC=20Material3=20Scaffold=20=EA=B8=B0=EB=B0=98?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인 시스템 프리뷰의 공통 레이아웃을 담당하는 `PreviewScaffold` 컴포저블의 구현 방식을 `Column`에서 Material3의 `Scaffold`로 변경했습니다. * `Column`과 수동으로 설정하던 배경색(`background`)을 `Scaffold`의 `containerColor`로 대체했습니다. * `Scaffold`의 `contentColor`를 지정하여 하위 컴포넌트의 기본 텍스트 색상을 설정했습니다. * `Scaffold`가 제공하는 `innerPadding`을 `Column`에 적용하여 콘텐츠가 시스템 UI와 겹치지 않도록 개선했습니다. --- .../designsystem/preview/PreviewComponent.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt index 50cb559..fd5cb79 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -25,15 +26,20 @@ import kotlinx.collections.immutable.ImmutableList @Composable internal fun PreviewScaffold(content: @Composable () -> Unit) { - Column( - modifier = Modifier - .fillMaxSize() - .background(PrezelTheme.colors.bgRegular) - .verticalScroll(rememberScrollState()) - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp), - ) { - content() + Scaffold( + containerColor = PrezelTheme.colors.bgRegular, + contentColor = PrezelTheme.colors.textLarge, + ) { innerPadding -> + Column( + modifier = Modifier + .padding(innerPadding) + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + content() + } } } From 7e8b71825ab228033647ba92e671fb361b8b33e8 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Mon, 26 Jan 2026 04:36:18 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20`PrezelRadio`=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=82=B4=EB=B6=80=20=ED=8C=A8?= =?UTF-8?q?=EB=94=A9=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelRadio` 컴포넌트의 가독성과 명확성을 개선하기 위해 `Spacer`와 패딩 관련 코드를 수정했습니다. * `Row`의 `toggleable` Modifier 체이닝에서 `padding`을 다음 줄로 이동하여 가독성을 높였습니다. * 수평 간격을 명시적으로 나타내기 위해 `Spacer(modifier = Modifier.padding(V4))`를 `Spacer(modifier = Modifier.width(V4))`로 변경했습니다. --- .../com/team/prezel/core/designsystem/component/PrezelRadio.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt index 3df6c20..435746d 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.toggleable import androidx.compose.material3.Icon import androidx.compose.material3.Text @@ -114,7 +115,7 @@ fun PrezelRadio( modifier = Modifier.clearAndSetSemantics { }, ) - Spacer(modifier = Modifier.padding(PrezelTheme.spacing.V4)) + Spacer(modifier = Modifier.width(PrezelTheme.spacing.V4)) Text( text = text, From 8b76eb6a26bc92689ba056872d34965f576d8427 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Mon, 26 Jan 2026 04:41:54 +0900 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20PrezelRadio=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelRadio`와 `PrezelRadioWithText` 컴포저블의 내부 구현을 개선하여 코드 중복을 줄이고 구조를 명확하게 변경했습니다. * **기능 분리**: 아이콘을 그리는 로직을 `PrezelRadioIcon`이라는 별도의 private 컴포저블로 추출했습니다. * **코드 개선**: * `PrezelRadio`와 `PrezelRadioWithText`가 `PrezelRadioIcon`을 재사용하도록 하여 중복 코드를 제거했습니다. * 불필요한 `clearAndSetSemantics` 수식어 호출을 삭제했습니다. * 수식어(Modifier) 체이닝 순서를 `size` 다음에 `toggleable`이 오도록 조정하여 일관성을 높였습니다. --- .../designsystem/component/PrezelRadio.kt | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt index 435746d..4334c71 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt @@ -22,7 +22,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.Role -import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -58,22 +57,17 @@ fun PrezelRadio( modifier: Modifier = Modifier, size: PrezelRadioSize = PrezelRadioSize.REGULAR, ) { - val tintColor = if (checked) PrezelTheme.colors.interactiveRegular else PrezelTheme.colors.iconDisabled - val icon = if (checked) PrezelIcons.RadioCircleFilled else PrezelIcons.RadioCircleOutlined - - Icon( - painter = painterResource(icon), - contentDescription = null, - tint = tintColor, + PrezelRadioIcon( + checked = checked, + size = size, modifier = modifier - .size(size.value) .toggleable( value = checked, onValueChange = onCheckedChange, role = Role.RadioButton, indication = null, interactionSource = null, - ).padding(PrezelTheme.spacing.V8), + ), ) } @@ -108,23 +102,32 @@ fun PrezelRadio( interactionSource = null, ), ) { - PrezelRadio( - checked = checked, - onCheckedChange = {}, - size = size, - modifier = Modifier.clearAndSetSemantics { }, - ) - + PrezelRadioIcon(checked = checked, size = size) Spacer(modifier = Modifier.width(PrezelTheme.spacing.V4)) - - Text( - text = text, - style = textStyle, - color = textColor, - ) + Text(text = text, style = textStyle, color = textColor) } } +@Composable +private fun PrezelRadioIcon( + checked: Boolean, + modifier: Modifier = Modifier, + size: PrezelRadioSize = PrezelRadioSize.REGULAR, +) { + val tintColor = if (checked) PrezelTheme.colors.interactiveRegular else PrezelTheme.colors.iconDisabled + val icon = if (checked) PrezelIcons.RadioCircleFilled else PrezelIcons.RadioCircleOutlined + + Icon( + painter = painterResource(icon), + contentDescription = null, + tint = tintColor, + modifier = Modifier + .size(size.value) + .then(modifier) + .padding(PrezelTheme.spacing.V8), + ) +} + @ThemePreview @Composable private fun PrezelRadioPreview() { From 6f274eb7b73bd2441b0e68f9dd1ac55032394dd5 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Mon, 26 Jan 2026 04:42:25 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20PrezelRadio=20=EB=AF=B8=EB=A6=AC?= =?UTF-8?q?=EB=B3=B4=EA=B8=B0=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelRadio` 컴포넌트의 미리보기(`@Preview`) 코드에서 `SectionTitle`에 포함된 불필요한 앞쪽 공백을 제거했습니다. --- .../com/team/prezel/core/designsystem/component/PrezelRadio.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt index 4334c71..c46b7e4 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt @@ -145,7 +145,7 @@ private fun PrezelRadioPreview() { Spacer(modifier = Modifier.height(20.dp)) - SectionTitle(" PrezelRadioSize.LARGE") + SectionTitle("PrezelRadioSize.LARGE") Text("Checked: true") PrezelRadio(checked = true, onCheckedChange = {}, size = PrezelRadioSize.LARGE) Text("Checked: false")