From 252613f36c3eb3914b24859fef01bc89c0dd6952 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Tue, 30 Jan 2024 15:06:12 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20CheckCircle=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 약관에서 사용하던 체크 컴포넌트를 수정하고 분리 --- .../component/util/CheckCircle.kt | 62 +++++++++++++++++++ .../drawable/ic_check_circle_background.xml | 9 +++ .../signup/content/TermsContent.kt | 44 ++----------- 3 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 core/designsystem/src/main/java/com/susu/core/designsystem/component/util/CheckCircle.kt create mode 100644 core/designsystem/src/main/res/drawable/ic_check_circle_background.xml diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/util/CheckCircle.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/util/CheckCircle.kt new file mode 100644 index 00000000..95e1480a --- /dev/null +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/util/CheckCircle.kt @@ -0,0 +1,62 @@ +package com.susu.core.designsystem.component.util + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.R +import com.susu.core.designsystem.theme.Gray100 +import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable + +@Composable +fun CheckCircle( + modifier: Modifier = Modifier, + isChecked: Boolean, + onCheckedChange: (Boolean) -> Unit = {}, +) { + Box( + modifier = modifier + .size(20.dp) + .drawBehind { + if (isChecked.not()) { + drawCircle( + color = Gray40, + radius = 8.dp.toPx(), + style = Stroke(width = 1.dp.toPx()), + ) + } + } + .susuClickable( + rippleEnabled = false, + onClick = { onCheckedChange(isChecked.not()) }, + ), + ) { + if (isChecked) { + Icon( + painter = painterResource(id = R.drawable.ic_check_circle_background), + contentDescription = null, + tint = Gray100, + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun CheckCirclePreview() { + SusuTheme { + Row { + CheckCircle(isChecked = true) + CheckCircle(isChecked = false) + } + } +} diff --git a/core/designsystem/src/main/res/drawable/ic_check_circle_background.xml b/core/designsystem/src/main/res/drawable/ic_check_circle_background.xml new file mode 100644 index 00000000..23e3b908 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_check_circle_background.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt index 87050445..575fc323 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.unit.dp import com.susu.core.designsystem.component.badge.BadgeColor import com.susu.core.designsystem.component.badge.BadgeStyle import com.susu.core.designsystem.component.badge.SusuBadge +import com.susu.core.designsystem.component.util.CheckCircle import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray15 import com.susu.core.designsystem.theme.Gray30 @@ -93,7 +94,7 @@ fun TermListItem( modifier = modifier.padding(vertical = SusuTheme.spacing.spacing_m), verticalAlignment = Alignment.CenterVertically, ) { - TermCheckCircle(isChecked = checked, onCheckedChange = onCheckClick) + CheckCircle(isChecked = checked, onCheckedChange = onCheckClick) Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_m)) if (isEssential) { SusuBadge( @@ -121,44 +122,7 @@ fun TermListItem( } } -@Composable -fun TermCheckCircle( - modifier: Modifier = Modifier, - isChecked: Boolean, - onCheckedChange: (Boolean) -> Unit = {}, -) { - Box( - modifier = modifier - .size(20.dp) - .drawBehind { - if (isChecked) { - drawCircle( - color = Gray100, - radius = 8.dp.toPx(), - ) - } else { - drawCircle( - color = Gray40, - radius = 8.dp.toPx(), - style = Stroke(width = 1.dp.toPx()), - ) - } - } - .susuClickable( - rippleEnabled = false, - onClick = { onCheckedChange(isChecked.not()) }, - ), - ) { - if (isChecked) { - Icon( - modifier = Modifier.padding(2.dp), - imageVector = Icons.Rounded.Check, - contentDescription = null, - tint = Gray15, - ) - } - } -} + @Preview(showSystemUi = true) @Composable @@ -176,6 +140,6 @@ fun TermsContentPreview() { @Composable fun TermCheckCirclePreview() { SusuTheme { - TermCheckCircle(isChecked = true) + CheckCircle(isChecked = true) } } From 71a33416f58eacb3b4245851323598c0a09c4a31 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Tue, 30 Jan 2024 15:30:19 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20SusuCheckedDialog=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=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 --- .../component/dialog/SusuCheckedDialog.kt | 154 ++++++++++++++++++ .../main/java/com/susu/core/ui/DialogToken.kt | 10 ++ .../com/susu/feature/navigator/MainScreen.kt | 57 +++++-- 3 files changed, 205 insertions(+), 16 deletions(-) create mode 100644 core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt new file mode 100644 index 00000000..cd7e831a --- /dev/null +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt @@ -0,0 +1,154 @@ +package com.susu.core.designsystem.component.dialog + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +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.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.component.button.FilledButtonColor +import com.susu.core.designsystem.component.button.GhostButtonColor +import com.susu.core.designsystem.component.button.SmallButtonStyle +import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.component.button.SusuGhostButton +import com.susu.core.designsystem.component.util.CheckCircle +import com.susu.core.designsystem.theme.Gray10 +import com.susu.core.designsystem.theme.Gray100 +import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.Gray80 +import com.susu.core.designsystem.theme.SusuTheme + +@Composable +fun SusuCheckedDialog( + modifier: Modifier = Modifier, + title: String? = null, + text: String? = null, + defaultChecked: Boolean = false, // dialog 노출 시 기본 체크 상태 + checkboxText: String = "", + confirmText: String = "", + dismissText: String? = null, + isDimmed: Boolean = true, + textAlign: TextAlign = TextAlign.Center, + onConfirmRequest: (isChecked: Boolean) -> Unit = {}, + onDismissRequest: () -> Unit = {}, +) { + val rootModifier = modifier + .fillMaxSize() + .background(color = if (isDimmed) Color.Black.copy(alpha = 0.16f) else Color.Transparent) + .padding(horizontal = SusuTheme.spacing.spacing_xl) + var isChecked by remember { mutableStateOf(defaultChecked) } + + Box( + modifier = rootModifier, + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + .background(color = Gray10, shape = RoundedCornerShape(8.dp)) + .padding(SusuTheme.spacing.spacing_xl), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + title?.let { + Text( + text = it, + style = SusuTheme.typography.title_xs, + color = Gray100, + maxLines = 2, + ) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxs)) + } + text?.let { + Text( + text = it, + style = SusuTheme.typography.text_xxs, + color = Gray80, + maxLines = 4, + textAlign = textAlign, + ) + } + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xl)) + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + CheckCircle( + isChecked = isChecked, + onCheckedChange = { isChecked = it }, + ) + Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_xxxxs)) + Text( + text = checkboxText, + style = SusuTheme.typography.title_xxs, + color = if (isChecked) Gray100 else Gray40, + ) + } + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xl)) + Row( + modifier = Modifier.fillMaxWidth(), + ) { + dismissText?.let { + SusuGhostButton( + modifier = Modifier.weight(1f), + color = GhostButtonColor.Black, + style = SmallButtonStyle.height40, + text = it, + onClick = onDismissRequest, + ) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxs)) + } + SusuFilledButton( + modifier = Modifier.weight(1f), + color = FilledButtonColor.Orange, + style = SmallButtonStyle.height40, + text = confirmText, + onClick = { onConfirmRequest(isChecked) }, + ) + } + } + } +} + +@Preview +@Composable +fun SusuCheckedDialogPreview() { + SusuTheme { + SusuCheckedDialog( + title = "제목", + text = "본문", + defaultChecked = true, + checkboxText = "체크박스 메세지", + confirmText = "확인했어요", + ) + } +} + +@Preview +@Composable +fun SusuCheckedDialogFalsePreview() { + SusuTheme { + SusuCheckedDialog( + title = "제목", + text = "본문", + checkboxText = "체크박스 메세지", + confirmText = "확인", + dismissText = "닫기", + ) + } +} diff --git a/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt b/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt index 705ff8fd..293f67d8 100644 --- a/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt +++ b/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt @@ -2,13 +2,23 @@ package com.susu.core.ui import androidx.compose.ui.text.style.TextAlign +/** + * checkboxText: 체크박스 메세지. null 일 경우 SusuDialog, null이 아닐 경우 SusuCheckedDialog 가 노출 + * + * defaultChecked: Dialog 노출 시 기본 체크 상태 + * + * onCheckedAction: 체크박스 선택 시 추가로 실행하는 로직 + * */ data class DialogToken( val title: String? = null, val text: String? = null, val confirmText: String = "", val dismissText: String? = null, + val checkboxText: String? = null, + val defaultChecked: Boolean = false, val isDimmed: Boolean = true, val textAlign: TextAlign = TextAlign.Center, val onConfirmRequest: () -> Unit = {}, + val onCheckedAction: () -> Unit = {}, val onDismissRequest: () -> Unit = {}, ) diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt index ac5971a8..f3def908 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.unit.IntOffset import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.NavHost import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.susu.core.designsystem.component.dialog.SusuCheckedDialog import com.susu.core.designsystem.component.dialog.SusuDialog import com.susu.core.designsystem.component.navigation.SusuNavigationBar import com.susu.core.designsystem.component.navigation.SusuNavigationItem @@ -179,22 +180,46 @@ internal fun MainScreen( if (uiState.dialogVisible) { with(uiState.dialogToken) { - SusuDialog( - title = title, - text = text, - confirmText = confirmText, - dismissText = dismissText, - isDimmed = isDimmed, - textAlign = textAlign, - onConfirmRequest = { - onConfirmRequest() - viewModel.dismissDialog() - }, - onDismissRequest = { - onDismissRequest() - viewModel.dismissDialog() - }, - ) + if (checkboxText == null) { + SusuDialog( + title = title, + text = text, + confirmText = confirmText, + dismissText = dismissText, + isDimmed = isDimmed, + textAlign = textAlign, + onConfirmRequest = { + onConfirmRequest() + viewModel.dismissDialog() + }, + onDismissRequest = { + onDismissRequest() + viewModel.dismissDialog() + }, + ) + } else { + SusuCheckedDialog( + title = title, + text = text, + confirmText = confirmText, + dismissText = dismissText, + checkboxText = checkboxText!!, + isDimmed = isDimmed, + defaultChecked = defaultChecked, + textAlign = textAlign, + onConfirmRequest = { checked -> + if (checked) { + onCheckedAction() + } + onConfirmRequest() + viewModel.dismissDialog() + }, + onDismissRequest = { + onDismissRequest() + viewModel.dismissDialog() + }, + ) + } } } }, From 26a1829c3898c02c79776573d3b5a87edfd608d3 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Tue, 30 Jan 2024 15:35:53 +0900 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20SusuCheckDialog=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=A3=BC=EC=84=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designsystem/component/dialog/SusuCheckedDialog.kt | 2 +- core/ui/src/main/java/com/susu/core/ui/DialogToken.kt | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt index cd7e831a..06f36607 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/dialog/SusuCheckedDialog.kt @@ -40,7 +40,7 @@ fun SusuCheckedDialog( modifier: Modifier = Modifier, title: String? = null, text: String? = null, - defaultChecked: Boolean = false, // dialog 노출 시 기본 체크 상태 + defaultChecked: Boolean = false, checkboxText: String = "", confirmText: String = "", dismissText: String? = null, diff --git a/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt b/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt index 293f67d8..39ba8af1 100644 --- a/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt +++ b/core/ui/src/main/java/com/susu/core/ui/DialogToken.kt @@ -3,11 +3,9 @@ package com.susu.core.ui import androidx.compose.ui.text.style.TextAlign /** - * checkboxText: 체크박스 메세지. null 일 경우 SusuDialog, null이 아닐 경우 SusuCheckedDialog 가 노출 - * - * defaultChecked: Dialog 노출 시 기본 체크 상태 - * - * onCheckedAction: 체크박스 선택 시 추가로 실행하는 로직 + * @param checkboxText 체크박스 메세지. null 일 경우 SusuDialog, null이 아닐 경우 SusuCheckedDialog 가 노출 + * @param defaultChecked Dialog 노출 시 기본 체크 상태 + * @param onCheckedAction 체크박스 선택 시 추가로 실행하는 로직 * */ data class DialogToken( val title: String? = null, From 42d9594a359dd1d2c8247e87578ff5a938529d93 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Tue, 30 Jan 2024 15:56:19 +0900 Subject: [PATCH 4/4] chore: ktlint check --- .../loginsignup/signup/content/TermsContent.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt index 575fc323..b578e4c9 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt @@ -1,7 +1,6 @@ package com.susu.feature.loginsignup.signup.content import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -10,16 +9,11 @@ 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.material.icons.Icons -import androidx.compose.material.icons.rounded.Check import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawBehind -import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -28,10 +22,7 @@ import com.susu.core.designsystem.component.badge.BadgeColor import com.susu.core.designsystem.component.badge.BadgeStyle import com.susu.core.designsystem.component.badge.SusuBadge import com.susu.core.designsystem.component.util.CheckCircle -import com.susu.core.designsystem.theme.Gray100 -import com.susu.core.designsystem.theme.Gray15 import com.susu.core.designsystem.theme.Gray30 -import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Term import com.susu.core.ui.R @@ -122,8 +113,6 @@ fun TermListItem( } } - - @Preview(showSystemUi = true) @Composable fun TermsContentPreview() {