diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt index a2286699..0828e1ac 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt @@ -39,6 +39,9 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.susu.core.designsystem.R import com.susu.core.designsystem.component.button.ClearIconButton +import com.susu.core.designsystem.component.button.FilledButtonColor +import com.susu.core.designsystem.component.button.LargeButtonStyle +import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.component.textfieldbutton.style.InnerButtonStyle import com.susu.core.designsystem.component.textfieldbutton.style.LargeTextFieldButtonStyle import com.susu.core.designsystem.component.textfieldbutton.style.SmallTextFieldButtonStyle @@ -60,6 +63,7 @@ fun SusuTextFieldFillMaxButton( style: @Composable () -> TextFieldButtonStyle, color: TextFieldButtonColor = TextFieldButtonColor.Black, isSaved: Boolean = false, + isFocused: Boolean = true, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, @@ -67,23 +71,25 @@ fun SusuTextFieldFillMaxButton( showClearIcon: Boolean = true, onClickClearIcon: () -> Unit = {}, onClickCloseIcon: () -> Unit = {}, - onClickButton: () -> Unit = {}, + onClickFilledButton: () -> Unit = {}, + onClickButton: (isFocused: Boolean) -> Unit = {}, ) { val (backgroundColor, textColor) = with(color) { - if (isSaved) { - (savedBackgroundColor to savedTextColor) - } else { - (editBackgroundColor to editTextColor) + when { + isFocused.not() -> (unFocusedBackgroundColor to unFocusedTextColor) + isSaved -> (savedBackgroundColor to savedTextColor) + else -> (editBackgroundColor to editTextColor) } } with(style()) { BasicTextField( modifier = modifier - .fillMaxWidth(), + .fillMaxWidth() + .susuClickable { onClickButton(isFocused) }, value = text, onValueChange = onTextChange, - enabled = isSaved.not(), + enabled = isSaved.not() && isFocused, singleLine = maxLines == 1, maxLines = if (minLines > maxLines) minLines else maxLines, minLines = minLines, @@ -142,13 +148,14 @@ fun SusuTextFieldFillMaxButton( showClearIcon = showClearIcon, isSaved = isSaved, isActive = text.isNotEmpty(), + isFocused = isFocused, color = color.buttonColor, buttonStyle = innerButtonStyle, clearIconSize = clearIconSize, closeIconSize = closeIconSize, onClickClearIcon = onClickClearIcon, onClickCloseIcon = onClickCloseIcon, - onClickButton = onClickButton, + onClickFilledButton = onClickFilledButton, ) } }, @@ -169,6 +176,7 @@ fun SusuTextFieldWrapContentButton( style: @Composable () -> TextFieldButtonStyle, color: TextFieldButtonColor = TextFieldButtonColor.Black, isSaved: Boolean = false, + isFocused: Boolean = true, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, @@ -176,13 +184,14 @@ fun SusuTextFieldWrapContentButton( showClearIcon: Boolean = true, onClickClearIcon: () -> Unit = {}, onClickCloseIcon: () -> Unit = {}, - onClickButton: () -> Unit = {}, + onClickFilledButton: () -> Unit = {}, + onClickButton: (isFocused: Boolean) -> Unit = {}, ) { val (backgroundColor, textColor) = with(color) { - if (isSaved) { - (savedBackgroundColor to savedTextColor) - } else { - (editBackgroundColor to editTextColor) + when { + isFocused.not() -> (unFocusedBackgroundColor to unFocusedTextColor) + isSaved -> (savedBackgroundColor to savedTextColor) + else -> (editBackgroundColor to editTextColor) } } @@ -191,6 +200,7 @@ fun SusuTextFieldWrapContentButton( modifier = modifier .clip(shape) .background(backgroundColor) + .susuClickable { onClickButton(isFocused) } .padding(paddingValues), horizontalArrangement = Arrangement.spacedBy(iconSpacing), verticalAlignment = Alignment.CenterVertically, @@ -206,9 +216,10 @@ fun SusuTextFieldWrapContentButton( * BasicTextField의 기본 width를 없애기 위해 IntrinsicSize.Min을 사용함. * see -> https://stackoverflow.com/questions/67719981/resizeable-basictextfield-in-jetpack-compose */ - .width(IntrinsicSize.Min), + .width(IntrinsicSize.Min) + .susuClickable(rippleEnabled = false, runIf = isFocused.not(), onClick = { onClickButton(isFocused) }), value = text, - enabled = isSaved.not(), + enabled = isSaved.not() && isFocused, onValueChange = onTextChange, singleLine = maxLines == 1, maxLines = if (minLines > maxLines) minLines else maxLines, @@ -256,13 +267,14 @@ fun SusuTextFieldWrapContentButton( showClearIcon = showClearIcon, isSaved = isSaved, isActive = text.isNotEmpty(), + isFocused = isFocused, color = color.buttonColor, buttonStyle = innerButtonStyle, clearIconSize = clearIconSize, closeIconSize = closeIconSize, onClickClearIcon = onClickClearIcon, onClickCloseIcon = onClickCloseIcon, - onClickButton = onClickButton, + onClickFilledButton = onClickFilledButton, ) } } @@ -274,6 +286,7 @@ private fun InnerButtons( shape: Shape = RoundedCornerShape(4.dp), isSaved: Boolean, isActive: Boolean, + isFocused: Boolean, showCloseIcon: Boolean = true, showClearIcon: Boolean = true, color: TextButtonInnerButtonColor, @@ -282,13 +295,13 @@ private fun InnerButtons( buttonStyle: @Composable () -> InnerButtonStyle, onClickClearIcon: () -> Unit = {}, onClickCloseIcon: () -> Unit = {}, - onClickButton: () -> Unit = {}, + onClickFilledButton: () -> Unit = {}, ) { val (innerButtonTextColor, innerButtonBackgroundColor) = with(color) { - if (isActive || isSaved) { - (activeContentColor to activeBackgroundColor) - } else { - (inactiveContentColor to inactiveBackgroundColor) + when { + isFocused.not() -> (unFocusedContentColor to unFocusedBackgroundColor) + isActive || isSaved -> (activeContentColor to activeBackgroundColor) + else -> (inactiveContentColor to inactiveBackgroundColor) } } @@ -315,7 +328,7 @@ private fun InnerButtons( .susuClickable( runIf = isActive || isSaved, rippleColor = color.rippleColor, - onClick = onClickButton, + onClick = onClickFilledButton, ) .padding(paddingValues), ) { @@ -351,6 +364,10 @@ fun TextFieldButtonPreview() { mutableStateOf(false) } + var isFocused by remember { + mutableStateOf(true) + } + Column( verticalArrangement = Arrangement.spacedBy(10.dp), ) { @@ -362,8 +379,10 @@ fun TextFieldButtonPreview() { maxLines = 1, minLines = 1, showClearIcon = true, + isFocused = isFocused, + onClickButton = { isFocused = !isFocused }, style = LargeTextFieldButtonStyle.height46, - onClickButton = { isSaved = isSaved.not() }, + onClickFilledButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, isSaved = isSaved, ) @@ -377,8 +396,10 @@ fun TextFieldButtonPreview() { placeholder = "Button", maxLines = 1, minLines = 1, + isFocused = !isFocused, + onClickButton = { isFocused = !isFocused }, style = LargeTextFieldButtonStyle.height46, - onClickButton = { isSaved = isSaved.not() }, + onClickFilledButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, isSaved = isSaved, ) @@ -392,11 +413,13 @@ fun TextFieldButtonPreview() { placeholder = "Button", maxLines = 1, minLines = 1, + isFocused = !isFocused, + onClickButton = { isFocused = !isFocused }, showClearIcon = false, showCloseIcon = false, color = TextFieldButtonColor.Orange, style = LargeTextFieldButtonStyle.height46, - onClickButton = { isSaved = isSaved.not() }, + onClickFilledButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, isSaved = isSaved, ) @@ -410,14 +433,91 @@ fun TextFieldButtonPreview() { overflow = TextOverflow.Ellipsis, onTextChange = { text = it }, placeholder = "Button", + isFocused = !isFocused, + onClickButton = { isFocused = !isFocused }, maxLines = 1, minLines = 1, color = TextFieldButtonColor.Orange, style = SmallTextFieldButtonStyle.height32, - onClickButton = { isSaved = isSaved.not() }, + onClickFilledButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, isSaved = isSaved, ) } } } + +@Preview(showBackground = true, backgroundColor = 0x000000) +@Composable +fun TextFieldButtonFocusedPreview() { + SusuTheme { + var text by remember { + mutableStateOf("Button") + } + + var isSaved by remember { + mutableStateOf(false) + } + + var isFocusedTextFieldButton by remember { + mutableStateOf(true) + } + + var isFocusedButton1 by remember { + mutableStateOf(false) + } + + var isFocusedButton2 by remember { + mutableStateOf(false) + } + + Column( + verticalArrangement = Arrangement.spacedBy(10.dp), + ) { + Text(text = "텍스트 길이에 딱 맞는 너비 (wrap)") + SusuTextFieldWrapContentButton( + color = TextFieldButtonColor.Orange, + text = text, + onTextChange = { text = it }, + placeholder = "", + maxLines = 1, + minLines = 1, + showClearIcon = true, + isFocused = isFocusedTextFieldButton, + onClickButton = { + isFocusedTextFieldButton = true + isFocusedButton1 = false + isFocusedButton2 = false + }, + style = LargeTextFieldButtonStyle.height46, + onClickFilledButton = { isSaved = isSaved.not() }, + onClickClearIcon = { text = "" }, + isSaved = isSaved, + ) + + SusuFilledButton( + color = FilledButtonColor.Orange, + style = LargeButtonStyle.height46, + text = "테스트1", + isActive = isFocusedButton1, + onClick = { + isFocusedTextFieldButton = false + isFocusedButton1 = true + isFocusedButton2 = false + }, + ) + + SusuFilledButton( + color = FilledButtonColor.Orange, + style = LargeButtonStyle.height46, + text = "테스트2", + isActive = isFocusedButton2, + onClick = { + isFocusedTextFieldButton = false + isFocusedButton1 = false + isFocusedButton2 = true + }, + ) + } + } +} diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt index 0426a23f..81a2f245 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt @@ -4,12 +4,16 @@ import androidx.compose.ui.graphics.Color import com.susu.core.designsystem.theme.Gray10 import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray30 +import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.Orange20 import com.susu.core.designsystem.theme.Orange60 enum class TextFieldButtonColor( val buttonColor: TextButtonInnerButtonColor, val savedBackgroundColor: Color, val editBackgroundColor: Color, + val unFocusedBackgroundColor: Color, + val unFocusedTextColor: Color, val editTextColor: Color, val savedTextColor: Color, val placeholderColor: Color, @@ -18,32 +22,40 @@ enum class TextFieldButtonColor( buttonColor = TextButtonInnerButtonColor.Black, savedBackgroundColor = Gray10, editBackgroundColor = Gray10, + unFocusedBackgroundColor = Gray10, editTextColor = Gray100, savedTextColor = Gray100, placeholderColor = Gray30, + unFocusedTextColor = Gray30, ), Orange( buttonColor = TextButtonInnerButtonColor.Black, savedBackgroundColor = Orange60, editBackgroundColor = Gray10, + unFocusedBackgroundColor = Orange20, editTextColor = Gray100, savedTextColor = Gray10, placeholderColor = Gray30, + unFocusedTextColor = Gray10, ), } enum class TextButtonInnerButtonColor( val activeContentColor: Color, val inactiveContentColor: Color, + val unFocusedContentColor: Color, val activeBackgroundColor: Color, val inactiveBackgroundColor: Color, + val unFocusedBackgroundColor: Color, val rippleColor: Color, ) { Black( activeContentColor = Gray10, inactiveContentColor = Gray10, + unFocusedContentColor = Gray10, activeBackgroundColor = Gray100, - inactiveBackgroundColor = Gray30, + inactiveBackgroundColor = Gray40, + unFocusedBackgroundColor = Gray40, rippleColor = Gray10, ), } diff --git a/core/ui/src/main/java/com/susu/core/ui/extension/AnimatedContentTransitionScope.kt b/core/ui/src/main/java/com/susu/core/ui/extension/AnimatedContentTransitionScope.kt new file mode 100644 index 00000000..5705a09a --- /dev/null +++ b/core/ui/src/main/java/com/susu/core/ui/extension/AnimatedContentTransitionScope.kt @@ -0,0 +1,21 @@ +package com.susu.core.ui.extension + +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.ContentTransform +import androidx.compose.animation.core.tween +import androidx.compose.animation.togetherWith + +fun AnimatedContentTransitionScope.susuDefaultAnimatedContentTransitionSpec(leftDirectionCondition: Boolean): ContentTransform { + val direction = if (leftDirectionCondition) { + AnimatedContentTransitionScope.SlideDirection.Left + } else { + AnimatedContentTransitionScope.SlideDirection.Right + } + return slideIntoContainer( + towards = direction, + animationSpec = tween(500), + ) togetherWith slideOutOfContainer( + towards = direction, + animationSpec = tween(500), + ) +} diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index e0ccb7b6..63459bbb 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -18,6 +18,7 @@ 카테고리 날짜 더하기 버튼 + 직접 입력 남성 여성 출생년도 diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt index 35daed42..d2f7a546 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt @@ -14,6 +14,7 @@ import com.susu.feature.community.navigation.navigateCommunity import com.susu.feature.loginsignup.navigation.LoginSignupRoute import com.susu.feature.mypage.navigation.navigateMyPage import com.susu.feature.received.navigation.ReceivedRoute +import com.susu.feature.received.navigation.navigateLedgerAdd import com.susu.feature.received.navigation.navigateLedgerDetail import com.susu.feature.received.navigation.navigateLedgerEdit import com.susu.feature.received.navigation.navigateLedgerSearch @@ -96,6 +97,10 @@ internal class MainNavigator( navController.navigateLedgerEdit() } + fun navigateLedgerAdd() { + navController.navigateLedgerAdd() + } + fun popBackStackIfNotHome() { if (!isSameCurrentDestination(SentRoute.route)) { navController.popBackStack() 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 029f0f59..30d8527c 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 @@ -70,6 +70,7 @@ internal fun MainScreen( navigateLedgerSearch = navigator::navigateLedgerSearch, navigateLedgerDetail = navigator::navigateLedgerDetail, navigateLedgerEdit = navigator::navigateLedgerEdit, + navigateLedgerAdd = navigator::navigateLedgerAdd, ) statisticsNavGraph( diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt new file mode 100644 index 00000000..0902138a --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -0,0 +1,116 @@ +package com.susu.feature.received.ledgeradd + +import androidx.compose.animation.AnimatedContent +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +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.Modifier +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.susu.core.designsystem.component.appbar.SusuProgressAppBar +import com.susu.core.designsystem.component.appbar.icon.BackIcon +import com.susu.core.designsystem.component.button.FilledButtonColor +import com.susu.core.designsystem.component.button.MediumButtonStyle +import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.R +import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec +import com.susu.feature.received.ledgeradd.content.CategoryContent +import com.susu.feature.received.ledgeradd.content.DateContent +import com.susu.feature.received.ledgeradd.content.NameContent + +enum class LedgerAddStep { + CATEGORY, + NAME, + DATE, +} + +@Composable +fun LedgerAddRoute( + popBackStack: () -> Unit, +) { + var currentStep by remember { + mutableStateOf(LedgerAddStep.CATEGORY) + } + + LedgerAddScreen( + currentStep = currentStep, + onClickBack = popBackStack, + onClickNextButton = { + // TODO 임시 코드 입니다. + currentStep = when (currentStep) { + LedgerAddStep.CATEGORY -> LedgerAddStep.NAME + LedgerAddStep.NAME -> LedgerAddStep.DATE + LedgerAddStep.DATE -> LedgerAddStep.DATE + } + }, + ) +} + +@Composable +fun LedgerAddScreen( + currentStep: LedgerAddStep = LedgerAddStep.CATEGORY, + onClickBack: () -> Unit = {}, + onClickNextButton: () -> Unit = {}, +) { + Box( + modifier = Modifier + .background(SusuTheme.colorScheme.background15) + .fillMaxSize(), + ) { + Column { + SusuProgressAppBar( + leftIcon = { + BackIcon(onClickBack) + }, + entireStep = LedgerAddStep.entries.size, + currentStep = currentStep.ordinal + 1, + ) + + AnimatedContent( + modifier = Modifier.weight(1f), + targetState = currentStep, + label = "LedgerAddScreen", + transitionSpec = { + susuDefaultAnimatedContentTransitionSpec( + leftDirectionCondition = targetState.ordinal > initialState.ordinal, + ) + }, + ) { targetState -> + when (targetState) { + LedgerAddStep.CATEGORY -> CategoryContent() + LedgerAddStep.NAME -> NameContent() + LedgerAddStep.DATE -> DateContent() + } + } + + SusuFilledButton( + modifier = Modifier + .fillMaxWidth() + .imePadding(), + shape = RectangleShape, + color = FilledButtonColor.Black, + style = MediumButtonStyle.height60, + text = stringResource(id = R.string.word_save), + onClick = onClickNextButton, + ) + } + } +} + +@Preview +@Composable +fun ReceivedScreenPreview() { + SusuTheme { + LedgerAddScreen() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/CategoryContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/CategoryContent.kt new file mode 100644 index 00000000..1fc7b0e1 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/CategoryContent.kt @@ -0,0 +1,91 @@ +package com.susu.feature.received.ledgeradd.content + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.susu.core.designsystem.component.button.GhostButtonColor +import com.susu.core.designsystem.component.button.MediumButtonStyle +import com.susu.core.designsystem.component.button.SusuGhostButton +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.received.R + +@Composable +fun CategoryContent() { + val scrollState = rememberScrollState() + + Column( + modifier = Modifier + .fillMaxSize() + .padding( + top = SusuTheme.spacing.spacing_xl, + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + ) + .verticalScroll(scrollState), + ) { + Text( + text = stringResource(R.string.select_category_screen_title), + style = SusuTheme.typography.title_m, + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxl)) + + Column( + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), + ) { + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = "결혼식", + ) + + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = "돌잔치", + ) + + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = "장례식", + ) + + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = "생일 기념일", + ) + + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = stringResource(com.susu.core.ui.R.string.word_input_yourself), + ) + } + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) +@Composable +fun CategoryContentPreview() { + SusuTheme { + CategoryContent() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/DateContent.kt new file mode 100644 index 00000000..8d999704 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/DateContent.kt @@ -0,0 +1,60 @@ +package com.susu.feature.received.ledgeradd.content + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuDatePickerBottomSheet +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.received.R +import com.susu.feature.received.ledgeradd.content.component.SelectDateRow + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DateContent() { + Column( + modifier = Modifier + .fillMaxSize() + .padding( + top = SusuTheme.spacing.spacing_xl, + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + ), + ) { + // TODO Annotated Text 사용 + Text( + text = "고모부의 장례식은 언제인가요", + style = SusuTheme.typography.title_m, + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_m)) + + SelectDateRow( + suffix = stringResource(R.string.ledger_add_screen_from), + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) + + SelectDateRow( + suffix = stringResource(R.string.ledger_add_screen_until), + ) + } + + SusuDatePickerBottomSheet(maximumContainerHeight = 346.dp) +} + +@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) +@Composable +fun DateContentPreview() { + SusuTheme { + DateContent() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/NameContent.kt new file mode 100644 index 00000000..9712b652 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/NameContent.kt @@ -0,0 +1,47 @@ +package com.susu.feature.received.ledgeradd.content + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.susu.core.designsystem.component.textfield.SusuBasicTextField +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.received.R + +@Composable +fun NameContent() { + Column( + modifier = Modifier + .fillMaxSize() + .padding( + top = SusuTheme.spacing.spacing_xl, + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + ), + ) { + Text( + text = stringResource(R.string.input_name_screen_title), + style = SusuTheme.typography.title_m, + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_m)) + + SusuBasicTextField( + placeholder = stringResource(R.string.input_name_screen_textfield_placeholder), + ) + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) +@Composable +fun NameContentPreview() { + SusuTheme { + NameContent() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/component/SelectDateRow.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/component/SelectDateRow.kt new file mode 100644 index 00000000..0bf71509 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/component/SelectDateRow.kt @@ -0,0 +1,69 @@ +package com.susu.feature.received.ledgeradd.content.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.susu.core.designsystem.theme.Gray30 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.util.AnnotatedText +import com.susu.feature.received.R +import java.time.LocalDateTime + +private val currentDate = LocalDateTime.now() + +@Composable +fun SelectDateRow( + year: Int? = null, + month: Int? = null, + day: Int? = null, + suffix: String? = null, +) { + Row( + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), + verticalAlignment = Alignment.Bottom, + ) { + if (year == null || month == null || day == null) { + AnnotatedText( + originalText = stringResource( + R.string.ledger_add_screen_date, + currentDate.year, + currentDate.month.value, + currentDate.dayOfMonth, + ), + targetTextList = listOf( + currentDate.year.toString(), + currentDate.month.value.toString(), + currentDate.dayOfMonth.toString(), + ), + originalTextStyle = SusuTheme.typography.title_xl, + spanStyle = SusuTheme.typography.title_xl.copy(Gray30).toSpanStyle(), + ) + } else { + Text( + text = stringResource( + R.string.ledger_add_screen_date, + year, + month, + day, + ), + style = SusuTheme.typography.title_xl, + ) + } + + if (suffix != null) { + Text(text = suffix, style = SusuTheme.typography.title_l) + } + } +} + +@Preview +@Composable +fun SelectDateRowPreview() { + SusuTheme { + SelectDateRow() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt b/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt index d0e20e5c..f61724b8 100644 --- a/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt +++ b/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt @@ -7,6 +7,7 @@ import androidx.navigation.NavOptions import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument +import com.susu.feature.received.ledgeradd.LedgerAddRoute import com.susu.feature.received.ledgerdetail.LedgerDetailRoute import com.susu.feature.received.ledgeredit.LedgerEditRoute import com.susu.feature.received.received.ReceivedRoute @@ -28,18 +29,24 @@ fun NavController.navigateLedgerEdit() { navigate(ReceivedRoute.ledgerEditRoute) } +fun NavController.navigateLedgerAdd() { + navigate(ReceivedRoute.ledgerAddRoute) +} + fun NavGraphBuilder.receivedNavGraph( padding: PaddingValues, navigateLedgerDetail: (Int) -> Unit, popBackStack: () -> Unit, navigateLedgerSearch: () -> Unit, navigateLedgerEdit: () -> Unit, + navigateLedgerAdd: () -> Unit, ) { composable(route = ReceivedRoute.route) { ReceivedRoute( padding = padding, navigateLedgerDetail = navigateLedgerDetail, navigateLedgerSearch = navigateLedgerSearch, + navigateLedgerAdd = navigateLedgerAdd, ) } @@ -67,6 +74,14 @@ fun NavGraphBuilder.receivedNavGraph( ) { LedgerEditRoute(popBackStack = popBackStack) } + + composable( + route = ReceivedRoute.ledgerAddRoute, + ) { + LedgerAddRoute( + popBackStack = popBackStack, + ) + } } object ReceivedRoute { @@ -76,4 +91,5 @@ object ReceivedRoute { const val ledgerSearchRoute = "ledger-search" const val ledgerEditRoute = "ledger-edit" // TODO 파라미터 넘기는 방식으로 수정해야함. + const val ledgerAddRoute = "ledger-add" // TODO 파라미터 넘기는 방식으로 수정해야함. } diff --git a/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt b/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt index 9950e11f..0bc084b0 100644 --- a/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt @@ -47,11 +47,14 @@ fun ReceivedRoute( padding: PaddingValues, navigateLedgerDetail: (Int) -> Unit, navigateLedgerSearch: () -> Unit, + navigateLedgerAdd: () -> Unit, ) { ReceiveScreen( padding = padding, onClickLedgerCard = navigateLedgerDetail, + onClickLedgerAddCard = navigateLedgerAdd, onClickSearchIcon = navigateLedgerSearch, // TODO SideEffect로 변경 + onClickFloatingAddButton = navigateLedgerAdd, ) } diff --git a/feature/received/src/main/res/values/strings.xml b/feature/received/src/main/res/values/strings.xml index 40d44585..8138a771 100644 --- a/feature/received/src/main/res/values/strings.xml +++ b/feature/received/src/main/res/values/strings.xml @@ -15,4 +15,10 @@ 일 부터 일 까지 + 경조사명을 알려주세요 + 경조사명을 입력해주세요 + 어떤 경조사였나요 + %d년 %d월 %d일 + 까지 + 부터