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..c46b7e4 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelRadio.kt @@ -0,0 +1,157 @@ +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.layout.width +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.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, +) { + PrezelRadioIcon( + checked = checked, + size = size, + modifier = modifier + .toggleable( + value = checked, + onValueChange = onCheckedChange, + role = Role.RadioButton, + indication = null, + interactionSource = null, + ), + ) +} + +/** + * 텍스트와 함께 표시되는 라디오 버튼. + * + * @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, + ), + ) { + PrezelRadioIcon(checked = checked, size = size) + Spacer(modifier = Modifier.width(PrezelTheme.spacing.V4)) + 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() { + 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) + } + } +} 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() + } } } 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