diff --git a/Prezel/app/src/main/java/com/team/prezel/ui/DoubleBackToExitHandler.kt b/Prezel/app/src/main/java/com/team/prezel/ui/DoubleBackToExitHandler.kt index df9b3764..3aadb420 100644 --- a/Prezel/app/src/main/java/com/team/prezel/ui/DoubleBackToExitHandler.kt +++ b/Prezel/app/src/main/java/com/team/prezel/ui/DoubleBackToExitHandler.kt @@ -13,7 +13,7 @@ import com.team.prezel.R import com.team.prezel.core.designsystem.component.feedback.snackbar.dismissById import com.team.prezel.core.designsystem.component.feedback.snackbar.showPrezelSnackbar import com.team.prezel.core.navigation.NavigationState -import com.team.prezel.core.ui.LocalSnackbarHostState +import com.team.prezel.core.ui.state.LocalSnackbarHostState private const val SNACKBAR_IDENTIFIER = "DoubleBackToExitHandler" diff --git a/Prezel/app/src/main/java/com/team/prezel/ui/PrezelApp.kt b/Prezel/app/src/main/java/com/team/prezel/ui/PrezelApp.kt index 9b19be98..f4330a9b 100644 --- a/Prezel/app/src/main/java/com/team/prezel/ui/PrezelApp.kt +++ b/Prezel/app/src/main/java/com/team/prezel/ui/PrezelApp.kt @@ -21,7 +21,7 @@ import com.team.prezel.core.navigation.LocalNavigator import com.team.prezel.core.navigation.Navigator import com.team.prezel.core.navigation.ProvideSharedTransitionScope import com.team.prezel.core.navigation.toEntries -import com.team.prezel.core.ui.LocalSnackbarHostState +import com.team.prezel.core.ui.state.LocalSnackbarHostState import com.team.prezel.navigation.MAIN_NAV_ITEMS import kotlinx.collections.immutable.ImmutableSet diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextArea.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextArea.kt index afeadca3..06af1699 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextArea.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextArea.kt @@ -21,10 +21,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.team.prezel.core.designsystem.component.actions.button.PrezelButton import com.team.prezel.core.designsystem.component.textfield.component.PrezelTextFieldLabel import com.team.prezel.core.designsystem.component.textfield.component.PrezelTextFieldPlaceholder import com.team.prezel.core.designsystem.component.textfield.component.PrezelTextFieldSupportingText @@ -41,7 +39,7 @@ fun PrezelTextArea( maxLength: Int, modifier: Modifier = Modifier, label: String? = null, - feedback: PrezelTextFieldFeedback = PrezelTextFieldFeedback.NO_MESSAGE, + status: PrezelTextFieldStatus = PrezelTextFieldStatus.DEFAULT, enabled: Boolean = true, showCount: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, @@ -49,21 +47,22 @@ fun PrezelTextArea( ) { var focused by remember { mutableStateOf(false) } - val state = rememberPrezelTextFieldInteraction( + val style = rememberPrezelTextFieldState( value = value, enabled = enabled, focused = focused, - ).let { interaction -> PrezelTextFieldState(interaction = interaction, feedback = feedback) } + ).let { state -> PrezelTextFieldStyle(state = state, status = status) } PrezelTextArea( value = value, onValueChange = { newValue -> - val applied = applyTextAreaPolicy(newValue, maxLength) + val applied = applyPrezelTextInputPolicy(newValue, maxLength) if (applied != value) onValueChange(applied) }, - placeholder = if (focused) "" else placeholder, - state = state, + placeholder = placeholder, + style = style, maxLength = maxLength, + focused = focused, onFocusChange = { isFocused -> focused = isFocused }, modifier = modifier, label = label, @@ -74,23 +73,14 @@ fun PrezelTextArea( ) } -private fun applyTextAreaPolicy( - value: String, - maxLength: Int, -): String { - require(maxLength >= 0) { "maxLength must be >= 0" } - return value - .replace("\n", "") - .take(maxLength) -} - @Composable private fun PrezelTextArea( value: String, onValueChange: (String) -> Unit, placeholder: String, maxLength: Int, - state: PrezelTextFieldState, + style: PrezelTextFieldStyle, + focused: Boolean, onFocusChange: (Boolean) -> Unit, label: String?, enabled: Boolean, @@ -113,20 +103,20 @@ private fun PrezelTextArea( .fillMaxWidth() .heightIn(min = 72.dp) .onFocusChanged { focusState -> onFocusChange(focusState.isFocused) }, - textStyle = PrezelTheme.typography.body2Regular.copy(color = state.textColor()), + textStyle = PrezelTheme.typography.body2Regular.copy(color = style.textColor()), cursorBrush = SolidColor(PrezelTheme.colors.interactiveRegular), keyboardOptions = keyboardOptions, keyboardActions = keyboardActions, decorationBox = { innerTextField -> PrezelTextAreaDecorationBox( innerTextField = innerTextField, - showPlaceholder = value.isEmpty(), + showPlaceholder = !focused && value.isEmpty(), placeholder = placeholder, - state = state, + state = style, counter = { if (showCount) { Spacer(modifier = Modifier.height(PrezelTheme.spacing.V16)) - Counter(currentLength = value.length, maxLength = maxLength, state = state) + Counter(currentLength = value.length, maxLength = maxLength, state = style) } }, modifier = Modifier.heightIn(min = 72.dp), @@ -134,9 +124,9 @@ private fun PrezelTextArea( }, ) - if (state.supportingText.isNotEmpty()) { + if (style.supportingText.isNotEmpty()) { Spacer(modifier = Modifier.height(PrezelTheme.spacing.V8)) - PrezelTextFieldSupportingText(state = state) + PrezelTextFieldSupportingText(text = style.supportingText, textColor = style.supportingTextColor()) } } } @@ -145,7 +135,7 @@ private fun PrezelTextArea( private fun Counter( currentLength: Int, maxLength: Int, - state: PrezelTextFieldState, + state: PrezelTextFieldStyle, modifier: Modifier = Modifier, ) { Text( @@ -163,7 +153,7 @@ private fun PrezelTextAreaDecorationBox( innerTextField: @Composable () -> Unit, counter: @Composable () -> Unit, placeholder: String, - state: PrezelTextFieldState, + state: PrezelTextFieldStyle, modifier: Modifier = Modifier, ) { Surface( @@ -181,7 +171,9 @@ private fun PrezelTextAreaDecorationBox( ) { Box { innerTextField() - if (showPlaceholder) PrezelTextFieldPlaceholder(placeholder = placeholder) + if (showPlaceholder) { + PrezelTextFieldPlaceholder(placeholder = placeholder) + } } counter() @@ -191,88 +183,113 @@ private fun PrezelTextAreaDecorationBox( @BasicPreview @Composable -private fun PrezelTextAreaPrezelPreview() { - PreviewSurface { - PreviewColumn( - scrollable = true, - verticalArrangement = Arrangement.spacedBy(4.dp), - ) { - PrezelTextAreaPreviewItem( - label = "Interaction - Default / Feedback - Default", - value = "", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.DEFAULT, - ), - ) - - PrezelTextAreaPreviewItem( - label = "Interaction - Disabled / Feedback - Default", - value = "", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.DISABLED, - ), - ) - - PrezelTextAreaPreviewItem( - label = "Interaction - Typing / Feedback - Default", - value = "typing...", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPING, - ), - ) +private fun PrezelTextAreaDefaultStatePreview() { + PreviewTextAreaState(title = "State - Default") { + PrezelTextAreaPreviewItem( + label = "Status - Default", + value = "", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.DEFAULT, + ), + ) + } +} - PrezelTextAreaPreviewItem( - label = "Interaction - Typed / Feedback - Default", - value = "typed", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - ), - ) - PrezelTextAreaPreviewItem( - label = "Interaction - Typed / Feedback - Good", - value = "typed", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Good("헬퍼 메시지"), - ), - ) +@BasicPreview +@Composable +private fun PrezelTextAreaDisabledStatePreview() { + PreviewTextAreaState(title = "State - Disabled") { + PrezelTextAreaPreviewItem( + label = "Status - Default", + value = "", + enabled = false, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.DISABLED, + ), + ) + } +} - PrezelTextAreaPreviewItem( - label = "Interaction - Typed / Feedback - Bad", - value = "typed", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Bad("헬퍼 메시지"), - ), - ) - } +@BasicPreview +@Composable +private fun PrezelTextAreaTypingStatePreview() { + PreviewTextAreaState(title = "State - Typing") { + PrezelTextAreaPreviewItem( + label = "Status - Default", + value = "", + focused = true, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPING, + ), + ) + PrezelTextAreaPreviewItem( + label = "Status - Good", + value = "", + focused = true, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPING, + status = PrezelTextFieldStatus.Good("헬퍼 메시지"), + ), + ) + PrezelTextAreaPreviewItem( + label = "Status - Bad", + value = "", + focused = true, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPING, + status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), + ), + ) } } @BasicPreview @Composable -private fun MainPrezelTextAreaPreview() { - var value by remember { mutableStateOf("") } - val focusManager = LocalFocusManager.current +private fun PrezelTextAreaTypedStatePreview() { + PreviewTextAreaState(title = "State - Typed") { + PrezelTextAreaPreviewItem( + label = "Status - Default", + value = "typed", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Default("헬퍼 메시지"), + ), + ) + PrezelTextAreaPreviewItem( + label = "Status - Good", + value = "typed", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Good("헬퍼 메시지"), + ), + ) + PrezelTextAreaPreviewItem( + label = "Status - Bad", + value = "typed", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), + ), + ) + } +} +@Composable +private fun PreviewTextAreaState( + title: String, + content: @Composable () -> Unit, +) { PreviewSurface { - PreviewColumn(scrollable = true) { - PrezelTextArea( - value = value, - onValueChange = { newValue -> value = newValue }, - maxLength = 100, - placeholder = "플레이스홀더", - label = "레이블", - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - showCount = true, - ) - - Spacer(modifier = Modifier.height(20.dp)) - PrezelButton( - text = "포커스 제거", - onClick = { focusManager.clearFocus() }, + PreviewColumn( + scrollable = true, + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + Text( + text = title, + style = PrezelTheme.typography.body2Bold, + color = PrezelTheme.colors.textLarge, ) + content() } } } @@ -281,19 +298,22 @@ private fun MainPrezelTextAreaPreview() { private fun PrezelTextAreaPreviewItem( label: String, value: String, - state: PrezelTextFieldState, + state: PrezelTextFieldStyle, modifier: Modifier = Modifier, + enabled: Boolean = true, + focused: Boolean = false, ) { PrezelTextArea( value = value, onValueChange = {}, placeholder = "Placeholder", label = label, - state = state, + style = state, maxLength = 100, + focused = focused, modifier = modifier, onFocusChange = {}, - enabled = true, + enabled = enabled, showCount = true, keyboardOptions = KeyboardOptions.Default, keyboardActions = KeyboardActions.Default, diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextField.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextField.kt index 5b3f8dad..942f23d9 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextField.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextField.kt @@ -1,6 +1,5 @@ package com.team.prezel.core.designsystem.component.textfield -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -16,7 +15,7 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.material3.Surface -import androidx.compose.material3.ripple +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue @@ -25,13 +24,10 @@ 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.focus.onFocusChanged import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.team.prezel.core.designsystem.component.actions.button.PrezelButton import com.team.prezel.core.designsystem.component.textfield.component.PrezelTextFieldLabel import com.team.prezel.core.designsystem.component.textfield.component.PrezelTextFieldPlaceholder import com.team.prezel.core.designsystem.component.textfield.component.PrezelTextFieldSupportingText @@ -49,7 +45,7 @@ fun PrezelTextField( modifier: Modifier = Modifier, label: String? = null, trailingIcon: @Composable (() -> Unit)? = null, - feedback: PrezelTextFieldFeedback = PrezelTextFieldFeedback.NO_MESSAGE, + status: PrezelTextFieldStatus = PrezelTextFieldStatus.DEFAULT, enabled: Boolean = true, maxLength: Int = Int.MAX_VALUE, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, @@ -57,20 +53,21 @@ fun PrezelTextField( ) { var focused by remember { mutableStateOf(false) } - val state = rememberPrezelTextFieldInteraction( + val state = rememberPrezelTextFieldState( value = value, enabled = enabled, focused = focused, - ).let { interaction -> PrezelTextFieldState(interaction = interaction, feedback = feedback) } + ).let { state -> PrezelTextFieldStyle(state = state, status = status) } PrezelTextField( value = value, onValueChange = { newValue -> - val applied = applyTextFieldPolicy(newValue, maxLength) + val applied = applyPrezelTextInputPolicy(newValue, maxLength) if (applied != value) onValueChange(applied) }, - placeholder = if (focused) "" else placeholder, - state = state, + placeholder = placeholder, + style = state, + focused = focused, onFocusChange = { isFocused -> focused = isFocused }, modifier = modifier, label = label, @@ -81,22 +78,13 @@ fun PrezelTextField( ) } -private fun applyTextFieldPolicy( - value: String, - maxLength: Int, -): String { - require(maxLength >= 0) { "maxLength must be >= 0" } - return value - .replace("\n", "") - .take(maxLength) -} - @Composable private fun PrezelTextField( value: String, onValueChange: (String) -> Unit, placeholder: String, - state: PrezelTextFieldState, + style: PrezelTextFieldStyle, + focused: Boolean, onFocusChange: (Boolean) -> Unit, modifier: Modifier = Modifier, label: String? = null, @@ -120,24 +108,24 @@ private fun PrezelTextField( .height(48.dp) .onFocusChanged { focusState -> onFocusChange(focusState.isFocused) }, singleLine = true, - textStyle = PrezelTheme.typography.body2Regular.copy(color = state.textColor()), + textStyle = PrezelTheme.typography.body2Regular.copy(color = style.textColor()), cursorBrush = SolidColor(PrezelTheme.colors.interactiveRegular), keyboardOptions = keyboardOptions, keyboardActions = keyboardActions, decorationBox = { innerTextField -> PrezelTextFieldDecorationBox( innerTextField = innerTextField, - showPlaceholder = value.isEmpty(), + showPlaceholder = !focused && value.isEmpty(), placeholder = placeholder, trailingIcon = trailingIcon, - state = state, + state = style, ) }, ) - if (state.supportingText.isNotEmpty()) { + if (style.supportingText.isNotEmpty()) { Spacer(modifier = Modifier.height(PrezelTheme.spacing.V8)) - PrezelTextFieldSupportingText(state = state) + PrezelTextFieldSupportingText(text = style.supportingText, textColor = style.supportingTextColor()) } } } @@ -148,7 +136,7 @@ private fun PrezelTextFieldDecorationBox( innerTextField: @Composable () -> Unit, placeholder: String, trailingIcon: @Composable (() -> Unit)?, - state: PrezelTextFieldState, + state: PrezelTextFieldStyle, modifier: Modifier = Modifier, ) { Surface( @@ -169,7 +157,9 @@ private fun PrezelTextFieldDecorationBox( contentAlignment = Alignment.CenterStart, ) { innerTextField() - if (showPlaceholder) PrezelTextFieldPlaceholder(placeholder = placeholder) + if (showPlaceholder) { + PrezelTextFieldPlaceholder(placeholder = placeholder) + } } trailingIcon?.let { content -> @@ -185,100 +175,113 @@ private fun PrezelTextFieldDecorationBox( @BasicPreview @Composable -private fun PrezelTextFieldPreview() { - PreviewSurface { - PreviewColumn( - scrollable = true, - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - PreviewTextFieldItem( - label = "Interaction - Default / Feedback - Default", - value = "", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.DEFAULT, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - ), - ) +private fun PrezelTextFieldDefaultStatePreview() { + PreviewTextFieldState(title = "State - Default") { + PreviewTextFieldItem( + label = "Status - Default", + value = "", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.DEFAULT, + status = PrezelTextFieldStatus.Default("헬퍼 메시지"), + ), + ) + } +} - PreviewTextFieldItem( - label = "Interaction - Disabled / Feedback - Default", - value = "", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.DISABLED, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - ), - ) - PreviewTextFieldItem( - label = "Interaction - Typing / Feedback - Default", - value = "typing...", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPING, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - ), - ) - PreviewTextFieldItem( - label = "Interaction - Typed / Feedback - Default", - value = "typed", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - ), - ) - PreviewTextFieldItem( - label = "Interaction - Typed / Feedback - Good", - value = "typed", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Good("헬퍼 메시지"), - ), - ) +@BasicPreview +@Composable +private fun PrezelTextFieldDisabledStatePreview() { + PreviewTextFieldState(title = "State - Disabled") { + PreviewTextFieldItem( + label = "Status - Default", + value = "", + enabled = false, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.DISABLED, + status = PrezelTextFieldStatus.Default("헬퍼 메시지"), + ), + ) + } +} - PreviewTextFieldItem( - label = "Interaction - Typed / Feedback - Bad", - value = "typed", - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Bad("헬퍼 메시지"), - ), - ) - } +@BasicPreview +@Composable +private fun PrezelTextFieldTypingStatePreview() { + PreviewTextFieldState(title = "State - Typing") { + PreviewTextFieldItem( + label = "Status - Default", + value = "", + focused = true, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPING, + status = PrezelTextFieldStatus.Default("헬퍼 메시지"), + ), + ) + PreviewTextFieldItem( + label = "Status - Good", + value = "", + focused = true, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPING, + status = PrezelTextFieldStatus.Good("헬퍼 메시지"), + ), + ) + PreviewTextFieldItem( + label = "Status - Bad", + value = "", + focused = true, + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPING, + status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), + ), + ) } } @BasicPreview @Composable -private fun MainPrezelTextFieldPreview() { - var value by remember { mutableStateOf("") } - val focusManager = LocalFocusManager.current +private fun PrezelTextFieldTypedStatePreview() { + PreviewTextFieldState(title = "State - Typed") { + PreviewTextFieldItem( + label = "Status - Default", + value = "typed", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Default("헬퍼 메시지"), + ), + ) + PreviewTextFieldItem( + label = "Status - Good", + value = "typed", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Good("헬퍼 메시지"), + ), + ) + PreviewTextFieldItem( + label = "Status - Bad", + value = "typed", + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), + ), + ) + } +} +@Composable +private fun PreviewTextFieldState( + title: String, + content: @Composable () -> Unit, +) { PreviewSurface { - PreviewColumn(scrollable = true) { - PrezelTextField( - value = value, - onValueChange = { newValue -> value = newValue }, - placeholder = "플레이스홀더", - label = "레이블", - trailingIcon = { - Icon( - painter = painterResource(PrezelIcons.Cancel), - contentDescription = null, - modifier = Modifier - .clip(PrezelTheme.shapes.V6) - .clickable( - indication = ripple(), - interactionSource = null, - onClick = { value = "" }, - ), - ) - }, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - ) - - Spacer(modifier = Modifier.height(20.dp)) - PrezelButton( - text = "포커스 제거", - onClick = { focusManager.clearFocus() }, + PreviewColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) { + Text( + text = title, + style = PrezelTheme.typography.body2Bold, + color = PrezelTheme.colors.textLarge, ) + content() } } } @@ -287,23 +290,29 @@ private fun MainPrezelTextFieldPreview() { private fun PreviewTextFieldItem( label: String, value: String, - state: PrezelTextFieldState, + state: PrezelTextFieldStyle, modifier: Modifier = Modifier, + enabled: Boolean = true, + focused: Boolean = false, ) { PrezelTextField( value = value, onValueChange = {}, placeholder = "Placeholder", label = label, - state = state, + style = state, + focused = focused, modifier = modifier, onFocusChange = {}, + enabled = enabled, trailingIcon = { Icon( painter = painterResource(PrezelIcons.Blank), contentDescription = null, ) }, + keyboardOptions = KeyboardOptions.Default, + keyboardActions = KeyboardActions.Default, ) Spacer(modifier = Modifier.height(PrezelTheme.spacing.V16)) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextFieldState.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextFieldState.kt index 0f064bcf..190a1e84 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextFieldState.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/PrezelTextFieldState.kt @@ -3,31 +3,19 @@ package com.team.prezel.core.designsystem.component.textfield import androidx.compose.foundation.BorderStroke import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.runtime.setValue -import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.foundation.color.PrezelColors import com.team.prezel.core.designsystem.theme.PrezelTheme -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.debounce -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.onEach /** - * Prezel TextField의 상호작용 상태를 나타냅니다. + * Prezel TextField의 State를 나타냅니다. * * TextField가 현재 어떤 사용자 입력 상태에 놓여 있는지를 정의하며, * 테두리 두께, 색상, 텍스트 색상 등의 스타일 계산에 사용됩니다. */ -enum class PrezelTextFieldInteraction { +enum class PrezelTextFieldState { /** 기본 상태 (포커스 및 입력이 없는 상태) */ DEFAULT, @@ -45,96 +33,100 @@ enum class PrezelTextFieldInteraction { fun calculate( enabled: Boolean, focused: Boolean, - isIdle: Boolean, - ): PrezelTextFieldInteraction = + hasValue: Boolean, + ): PrezelTextFieldState = when { !enabled -> DISABLED - !focused -> DEFAULT - !isIdle -> TYPING - else -> TYPED + focused -> TYPING + hasValue -> TYPED + else -> DEFAULT } } } /** - * Prezel TextField 입력 결과에 대한 피드백 상태를 나타냅니다. + * Prezel TextField 입력 결과에 대한 Status를 나타냅니다. * - * 입력이 완료된 이후(`TYPED`) 상태에서 시각적인 피드백을 제공하기 위해 사용됩니다. + * 입력이 완료된 이후(`TYPED`) 상태에서 시각적인 Status를 제공하기 위해 사용됩니다. */ @Stable -sealed interface PrezelTextFieldFeedback { +sealed interface PrezelTextFieldStatus { val message: String - /** 기본 상태 (피드백 없음) */ + /** 기본 Status */ data class Default( override val message: String, - ) : PrezelTextFieldFeedback + ) : PrezelTextFieldStatus /** 긍정적인 입력 결과 */ data class Good( override val message: String, - ) : PrezelTextFieldFeedback + ) : PrezelTextFieldStatus /** 부정적인 입력 결과 */ data class Bad( override val message: String, - ) : PrezelTextFieldFeedback + ) : PrezelTextFieldStatus companion object { - val NO_MESSAGE = Default(message = "") + val DEFAULT = Default(message = "") } } /** * Prezel TextField의 상태 기반 스타일 정보를 정의합니다. * - * [interaction]과 [feedback] 조합을 통해 컨테이너 색상, 텍스트 색상, + * [state]와 [status] 조합을 통해 컨테이너 색상, 텍스트 색상, * 아이콘 색상, 테두리 스타일 등의 파생 스타일을 계산합니다. * * 이 객체는 UI 상태를 표현하는 값 객체로 사용되며, * 실제 색상 및 두께 계산 로직은 내부 함수에서 처리합니다. * - * @property interaction TextField의 현재 상호작용 상태 - * @property feedback 입력 결과에 대한 피드백 상태 + * @property state TextField의 현재 State + * @property status 입력 결과에 대한 Status */ @Immutable -data class PrezelTextFieldState( - val interaction: PrezelTextFieldInteraction = PrezelTextFieldInteraction.DEFAULT, - val feedback: PrezelTextFieldFeedback = PrezelTextFieldFeedback.NO_MESSAGE, +data class PrezelTextFieldStyle( + val state: PrezelTextFieldState = PrezelTextFieldState.DEFAULT, + val status: PrezelTextFieldStatus = PrezelTextFieldStatus.DEFAULT, ) { - val supportingText: String = feedback.message + val supportingText: String = status.message /** * TextField 컨테이너의 배경 색상을 반환합니다. * - * 입력 완료(`TYPED`) 상태에서만 피드백에 따라 배경 색상이 적용되며, + * 입력 중(`TYPING`) 또는 입력 완료(`TYPED`) 상태에서 Status에 따라 배경 색상이 적용되며, * 그 외 상태에서는 투명한 색상을 반환합니다. */ @Composable internal fun containerColor(colors: PrezelColors = PrezelTheme.colors): Color = - when (interaction) { - PrezelTextFieldInteraction.TYPED -> when (feedback) { - is PrezelTextFieldFeedback.Default -> Color.Transparent - is PrezelTextFieldFeedback.Good -> colors.feedbackGoodSmall - is PrezelTextFieldFeedback.Bad -> colors.feedbackBadSmall + when (state) { + PrezelTextFieldState.DEFAULT, + PrezelTextFieldState.DISABLED, + -> Color.Transparent + + PrezelTextFieldState.TYPING, + PrezelTextFieldState.TYPED, + -> when (status) { + is PrezelTextFieldStatus.Default -> Color.Transparent + is PrezelTextFieldStatus.Good -> colors.feedbackGoodSmall + is PrezelTextFieldStatus.Bad -> colors.feedbackBadSmall } - - else -> Color.Transparent } /** * TextField 내부 텍스트 색상을 반환합니다. * - * 상호작용 상태와 피드백 상태에 따라 텍스트 대비를 조정하며, + * State와 Status에 따라 텍스트 대비를 조정하며, * 다크 모드 여부에 따라 일부 색상이 달라질 수 있습니다. */ @Composable internal fun textColor(colors: PrezelColors = PrezelTheme.colors): Color = - when (interaction) { - PrezelTextFieldInteraction.DISABLED -> colors.textDisabled - PrezelTextFieldInteraction.DEFAULT -> colors.textSmall - PrezelTextFieldInteraction.TYPING -> colors.textLarge - PrezelTextFieldInteraction.TYPED -> colors.textLarge + when (state) { + PrezelTextFieldState.DISABLED -> colors.textDisabled + PrezelTextFieldState.DEFAULT -> colors.textSmall + PrezelTextFieldState.TYPING -> colors.textLarge + PrezelTextFieldState.TYPED -> colors.textLarge } /** @@ -142,63 +134,75 @@ data class PrezelTextFieldState( */ @Composable internal fun supportingTextColor(colors: PrezelColors = PrezelTheme.colors): Color = - when (interaction) { - PrezelTextFieldInteraction.TYPED -> when (feedback) { - is PrezelTextFieldFeedback.Default -> colors.textRegular - is PrezelTextFieldFeedback.Good -> colors.feedbackGoodRegular - is PrezelTextFieldFeedback.Bad -> colors.feedbackBadRegular + when (state) { + PrezelTextFieldState.DISABLED -> colors.textDisabled + PrezelTextFieldState.DEFAULT -> colors.textRegular + PrezelTextFieldState.TYPING -> when (status) { + is PrezelTextFieldStatus.Default -> colors.textRegular + is PrezelTextFieldStatus.Good -> colors.feedbackGoodRegular + is PrezelTextFieldStatus.Bad -> colors.feedbackBadRegular } - else -> colors.textRegular + PrezelTextFieldState.TYPED -> when (status) { + is PrezelTextFieldStatus.Default -> colors.textMedium + is PrezelTextFieldStatus.Good -> colors.feedbackGoodRegular + is PrezelTextFieldStatus.Bad -> colors.feedbackBadRegular + } } /** * TextField 우측 트레일링 아이콘의 색상을 반환합니다. * * 비활성화 상태에서는 비활성 색상을 사용하며, - * 입력 완료 상태에서는 피드백에 따라 아이콘 색상이 변경됩니다. + * 입력 완료 상태에서는 Status에 따라 아이콘 색상이 변경됩니다. */ @Composable internal fun trailingIconColor(colors: PrezelColors = PrezelTheme.colors): Color = - when (interaction) { - PrezelTextFieldInteraction.DISABLED, - PrezelTextFieldInteraction.DEFAULT, + when (state) { + PrezelTextFieldState.DISABLED, + PrezelTextFieldState.DEFAULT, -> colors.iconDisabled - PrezelTextFieldInteraction.TYPING -> colors.iconRegular - PrezelTextFieldInteraction.TYPED -> when (feedback) { - is PrezelTextFieldFeedback.Default -> colors.iconRegular - is PrezelTextFieldFeedback.Good -> colors.interactiveRegular - is PrezelTextFieldFeedback.Bad -> colors.feedbackBadRegular + PrezelTextFieldState.TYPING, + PrezelTextFieldState.TYPED, + -> when (status) { + is PrezelTextFieldStatus.Default -> colors.iconRegular + is PrezelTextFieldStatus.Good -> colors.interactiveRegular + is PrezelTextFieldStatus.Bad -> colors.feedbackBadRegular } } /** * TextField 테두리 스타일을 반환합니다. * - * 상호작용 상태에 따라 테두리 두께가 달라지며, - * 입력 완료 상태에서는 피드백에 따라 테두리 색상이 변경됩니다. + * State에 따라 테두리 두께가 달라지며, + * 입력 완료 상태에서는 Status에 따라 테두리 색상이 변경됩니다. */ @Composable internal fun borderStroke(colors: PrezelColors = PrezelTheme.colors): BorderStroke { - val borderWidth = when (interaction) { - PrezelTextFieldInteraction.DEFAULT, - PrezelTextFieldInteraction.DISABLED, + val borderWidth = when (state) { + PrezelTextFieldState.DEFAULT, + PrezelTextFieldState.DISABLED, -> 1.dp - PrezelTextFieldInteraction.TYPING, - PrezelTextFieldInteraction.TYPED, + PrezelTextFieldState.TYPING, + PrezelTextFieldState.TYPED, -> 2.dp } - val borderColor = when (interaction) { - PrezelTextFieldInteraction.DISABLED -> colors.borderDisabled - PrezelTextFieldInteraction.DEFAULT -> colors.borderSmall - PrezelTextFieldInteraction.TYPING -> colors.borderMedium - PrezelTextFieldInteraction.TYPED -> when (feedback) { - is PrezelTextFieldFeedback.Default -> colors.borderRegular - is PrezelTextFieldFeedback.Good -> colors.interactiveRegular - is PrezelTextFieldFeedback.Bad -> colors.feedbackBadRegular + val borderColor = when (state) { + PrezelTextFieldState.DISABLED -> colors.borderDisabled + PrezelTextFieldState.DEFAULT -> colors.borderSmall + PrezelTextFieldState.TYPING -> when (status) { + is PrezelTextFieldStatus.Default -> colors.borderMedium + is PrezelTextFieldStatus.Good -> colors.feedbackGoodRegular + is PrezelTextFieldStatus.Bad -> colors.feedbackBadRegular + } + + PrezelTextFieldState.TYPED -> when (status) { + is PrezelTextFieldStatus.Default -> colors.borderRegular + is PrezelTextFieldStatus.Good -> colors.feedbackGoodRegular + is PrezelTextFieldStatus.Bad -> colors.feedbackBadRegular } } @@ -206,34 +210,24 @@ data class PrezelTextFieldState( } } -@OptIn(FlowPreview::class) @Composable -internal fun rememberPrezelTextFieldInteraction( +internal fun rememberPrezelTextFieldState( value: String, enabled: Boolean, focused: Boolean, - idleMillis: Long = 500L, -): PrezelTextFieldInteraction { - var isIdle by remember { mutableStateOf(false) } - val latestValue by rememberUpdatedState(value) - val latestEnabled by rememberUpdatedState(enabled) - val latestFocused by rememberUpdatedState(focused) - - LaunchedEffect(focused) { - if (!focused) isIdle = false - } - - LaunchedEffect(idleMillis) { - snapshotFlow { latestValue } - .distinctUntilChanged() - .onEach { isIdle = false } - .debounce(idleMillis) - .collectLatest { if (latestEnabled && latestFocused) isIdle = true } - } - - return PrezelTextFieldInteraction.calculate( +): PrezelTextFieldState = + PrezelTextFieldState.calculate( enabled = enabled, focused = focused, - isIdle = isIdle, + hasValue = value.isNotEmpty(), ) + +internal fun applyPrezelTextInputPolicy( + value: String, + maxLength: Int, +): String { + require(maxLength >= 0) { "maxLength must be >= 0" } + return value + .replace("\n", "") + .take(maxLength) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/component/PrezelTextFieldSupportingText.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/component/PrezelTextFieldSupportingText.kt index 81d7692d..616df7da 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/component/PrezelTextFieldSupportingText.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/textfield/component/PrezelTextFieldSupportingText.kt @@ -3,22 +3,24 @@ package com.team.prezel.core.designsystem.component.textfield.component import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.team.prezel.core.designsystem.component.textfield.PrezelTextFieldFeedback -import com.team.prezel.core.designsystem.component.textfield.PrezelTextFieldInteraction +import androidx.compose.ui.graphics.Color import com.team.prezel.core.designsystem.component.textfield.PrezelTextFieldState +import com.team.prezel.core.designsystem.component.textfield.PrezelTextFieldStatus +import com.team.prezel.core.designsystem.component.textfield.PrezelTextFieldStyle import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.preview.PreviewSection import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable internal fun PrezelTextFieldSupportingText( - state: PrezelTextFieldState, + text: String, + textColor: Color, modifier: Modifier = Modifier, ) { Text( - text = state.supportingText, + text = text, style = PrezelTheme.typography.body3Regular, - color = state.supportingTextColor(), + color = textColor, modifier = modifier, maxLines = 1, ) @@ -28,25 +30,31 @@ internal fun PrezelTextFieldSupportingText( @Composable private fun PrezelTextFieldSupportingTextPreview() { PreviewSection(title = "Supporting Text") { + val default = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Default("헬퍼 메시지"), + ) PrezelTextFieldSupportingText( - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), - ), + text = default.supportingText, + textColor = default.supportingTextColor(), ) + val bad = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), + ) PrezelTextFieldSupportingText( - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Bad("헬퍼 메시지"), - ), + text = bad.supportingText, + textColor = bad.supportingTextColor(), ) + val good = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Good("헬퍼 메시지"), + ) PrezelTextFieldSupportingText( - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Good("헬퍼 메시지"), - ), + text = good.supportingText, + textColor = good.supportingTextColor(), ) } } diff --git a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/BaseViewModel.kt b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/base/BaseViewModel.kt similarity index 96% rename from Prezel/core/ui/src/main/java/com/team/prezel/core/ui/BaseViewModel.kt rename to Prezel/core/ui/src/main/java/com/team/prezel/core/ui/base/BaseViewModel.kt index 3c9cb2cb..7c58bd26 100644 --- a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/BaseViewModel.kt +++ b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/base/BaseViewModel.kt @@ -1,4 +1,4 @@ -package com.team.prezel.core.ui +package com.team.prezel.core.ui.base import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel diff --git a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelLottie.kt b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelLottie.kt new file mode 100644 index 00000000..c4f3d6a8 --- /dev/null +++ b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelLottie.kt @@ -0,0 +1,61 @@ +package com.team.prezel.core.ui.component + +import androidx.annotation.RawRes +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Modifier +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.compose.LottieCompositionSpec +import com.airbnb.lottie.compose.LottieConstants +import com.airbnb.lottie.compose.animateLottieCompositionAsState +import com.airbnb.lottie.compose.rememberLottieComposition +import com.team.prezel.core.designsystem.preview.BasicPreview +import com.team.prezel.core.designsystem.theme.PrezelTheme +import com.team.prezel.core.ui.R + +@Composable +fun PrezelLottie( + @RawRes resId: Int, + modifier: Modifier = Modifier, + isPlaying: Boolean = true, + iterations: Int = LottieConstants.IterateForever, + speed: Float = 1f, + restartOnPlay: Boolean = false, + onAnimationFrame: ((progress: Float) -> Unit)? = null, +) { + val composition by rememberLottieComposition( + spec = LottieCompositionSpec.RawRes(resId), + ) + + val progress by animateLottieCompositionAsState( + composition = composition, + isPlaying = isPlaying, + iterations = iterations, + speed = speed, + restartOnPlay = restartOnPlay, + ) + + val updatedCallback by rememberUpdatedState(onAnimationFrame) + LaunchedEffect(progress) { + updatedCallback?.invoke(progress) + } + + LottieAnimation( + composition = composition, + progress = { progress }, + modifier = modifier, + ) +} + +@BasicPreview +@Composable +private fun PrezelLottiePreview() { + PrezelTheme { + PrezelLottie( + resId = R.raw.asset_loading, + iterations = LottieConstants.IterateForever, + ) + } +} diff --git a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/StatusView.kt similarity index 77% rename from Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt rename to Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/StatusView.kt index 4d210788..9510cb8d 100644 --- a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt +++ b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/StatusView.kt @@ -1,6 +1,5 @@ -package com.team.prezel.core.ui +package com.team.prezel.core.ui.component -import androidx.annotation.RawRes import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -10,16 +9,10 @@ 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.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.airbnb.lottie.compose.LottieAnimation -import com.airbnb.lottie.compose.LottieCompositionSpec -import com.airbnb.lottie.compose.LottieConstants -import com.airbnb.lottie.compose.animateLottieCompositionAsState -import com.airbnb.lottie.compose.rememberLottieComposition import com.team.prezel.core.designsystem.component.actions.button.PrezelButton import com.team.prezel.core.designsystem.component.actions.button.config.ButtonHierarchy import com.team.prezel.core.designsystem.component.actions.button.config.ButtonSize @@ -76,26 +69,6 @@ fun StatusView( } } -@Composable -fun StatusLottie( - @RawRes lottieJsonResId: Int, - modifier: Modifier = Modifier.size(80.dp), -) { - val composition by rememberLottieComposition( - LottieCompositionSpec.RawRes(lottieJsonResId), - ) - val progress by animateLottieCompositionAsState( - composition = composition, - iterations = LottieConstants.IterateForever, - ) - - LottieAnimation( - composition = composition, - progress = { progress }, - modifier = modifier, - ) -} - @BasicPreview @Composable private fun StatusViewEmptyPreview() { @@ -151,17 +124,3 @@ private fun StatusViewErrorPreview() { ) } } - -@BasicPreview -@Composable -private fun StatusViewLoadingPreview() { - PrezelTheme { - StatusView( - title = "분석 중이에요", - description = "잠시만 기다려주세요", - visual = { - StatusLottie(lottieJsonResId = R.raw.asset_loading) - }, - ) - } -} diff --git a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/LocalSnackbarHostState.kt b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/state/LocalSnackbarHostState.kt similarity index 86% rename from Prezel/core/ui/src/main/java/com/team/prezel/core/ui/LocalSnackbarHostState.kt rename to Prezel/core/ui/src/main/java/com/team/prezel/core/ui/state/LocalSnackbarHostState.kt index e054c882..870ebdf8 100644 --- a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/LocalSnackbarHostState.kt +++ b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/state/LocalSnackbarHostState.kt @@ -1,4 +1,4 @@ -package com.team.prezel.core.ui +package com.team.prezel.core.ui.state import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.staticCompositionLocalOf diff --git a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/AdvancedImePadding.kt b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/util/AdvancedImePadding.kt similarity index 96% rename from Prezel/core/ui/src/main/java/com/team/prezel/core/ui/AdvancedImePadding.kt rename to Prezel/core/ui/src/main/java/com/team/prezel/core/ui/util/AdvancedImePadding.kt index 41336fcf..7fab941a 100644 --- a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/AdvancedImePadding.kt +++ b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/util/AdvancedImePadding.kt @@ -1,4 +1,4 @@ -package com.team.prezel.core.ui +package com.team.prezel.core.ui.util import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.consumeWindowInsets diff --git a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/OnHeightChanged.kt b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/util/OnHeightChanged.kt similarity index 92% rename from Prezel/core/ui/src/main/java/com/team/prezel/core/ui/OnHeightChanged.kt rename to Prezel/core/ui/src/main/java/com/team/prezel/core/ui/util/OnHeightChanged.kt index 606f7070..89c6e4cc 100644 --- a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/OnHeightChanged.kt +++ b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/util/OnHeightChanged.kt @@ -1,4 +1,4 @@ -package com.team.prezel.core.ui +package com.team.prezel.core.ui.util import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt index 7a2682f3..73c8efb6 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt @@ -28,7 +28,7 @@ import com.team.prezel.core.model.presentation.Audience import com.team.prezel.core.model.presentation.Category import com.team.prezel.core.model.presentation.Purpose import com.team.prezel.core.model.presentation.Style -import com.team.prezel.core.ui.LocalSnackbarHostState +import com.team.prezel.core.ui.state.LocalSnackbarHostState import com.team.prezel.feature.history.impl.component.HistoryEmptyContent import com.team.prezel.feature.history.impl.component.HistoryItemList import com.team.prezel.feature.history.impl.contract.HistoryUiEffect diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt index b32e1744..4fcec31a 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt @@ -6,7 +6,7 @@ import com.team.prezel.core.model.presentation.Category import com.team.prezel.core.model.presentation.Presentation import com.team.prezel.core.model.presentation.Purpose import com.team.prezel.core.model.presentation.Style -import com.team.prezel.core.ui.BaseViewModel +import com.team.prezel.core.ui.base.BaseViewModel import com.team.prezel.feature.history.impl.contract.HistoryUiEffect import com.team.prezel.feature.history.impl.contract.HistoryUiIntent import com.team.prezel.feature.history.impl.contract.HistoryUiState diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt index 2ea444f8..38be4caa 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt @@ -12,7 +12,7 @@ import com.team.prezel.core.designsystem.component.actions.button.config.ButtonS import com.team.prezel.core.designsystem.component.actions.button.config.ButtonType import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme -import com.team.prezel.core.ui.StatusView +import com.team.prezel.core.ui.component.StatusView import com.team.prezel.feature.history.impl.R import com.team.prezel.feature.history.impl.model.HistoryPageType diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiEffect.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiEffect.kt index 8f013deb..faa9ad91 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiEffect.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiEffect.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.history.impl.contract -import com.team.prezel.core.ui.UiEffect +import com.team.prezel.core.ui.base.UiEffect import com.team.prezel.feature.history.impl.model.HistoryUiMessage internal sealed interface HistoryUiEffect : UiEffect { diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiIntent.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiIntent.kt index 223b106e..a55202af 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiIntent.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiIntent.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.history.impl.contract -import com.team.prezel.core.ui.UiIntent +import com.team.prezel.core.ui.base.UiIntent internal sealed interface HistoryUiIntent : UiIntent { data object FetchData : HistoryUiIntent diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiState.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiState.kt index aa47c4da..ceccba29 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiState.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiState.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.history.impl.contract import androidx.compose.runtime.Immutable -import com.team.prezel.core.ui.UiState +import com.team.prezel.core.ui.base.UiState import com.team.prezel.feature.history.impl.model.HistoryPageUiModel import kotlinx.collections.immutable.ImmutableList diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeScreen.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeScreen.kt index 1f9b392b..1937c35a 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeScreen.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeScreen.kt @@ -24,8 +24,8 @@ import com.team.prezel.core.designsystem.component.feedback.snackbar.showPrezelS import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme import com.team.prezel.core.model.presentation.Category -import com.team.prezel.core.ui.LocalSnackbarHostState -import com.team.prezel.core.ui.onHeightChanged +import com.team.prezel.core.ui.state.LocalSnackbarHostState +import com.team.prezel.core.ui.util.onHeightChanged import com.team.prezel.feature.home.impl.component.HomePageLayout import com.team.prezel.feature.home.impl.component.body.EmptyPresentationSheet import com.team.prezel.feature.home.impl.component.body.PresentationSheet diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeViewModel.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeViewModel.kt index 6abf0658..b51ec51f 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeViewModel.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/HomeViewModel.kt @@ -6,7 +6,7 @@ import com.team.prezel.core.model.presentation.Category import com.team.prezel.core.model.presentation.Presentation import com.team.prezel.core.model.presentation.Purpose import com.team.prezel.core.model.presentation.Style -import com.team.prezel.core.ui.BaseViewModel +import com.team.prezel.core.ui.base.BaseViewModel import com.team.prezel.feature.home.impl.contract.HomeUiEffect import com.team.prezel.feature.home.impl.contract.HomeUiIntent import com.team.prezel.feature.home.impl.contract.HomeUiState diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/HomePageLayout.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/HomePageLayout.kt index 04badf22..95b2bf8d 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/HomePageLayout.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/HomePageLayout.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.coerceAtLeast import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme -import com.team.prezel.core.ui.onHeightChanged +import com.team.prezel.core.ui.util.onHeightChanged import com.team.prezel.feature.home.impl.R import com.team.prezel.feature.home.impl.component.body.HomeBottomSheetContent import com.team.prezel.feature.home.impl.component.body.HomeBottomSheetTitle diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiEffect.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiEffect.kt index edfcdd03..ad982ba7 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiEffect.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiEffect.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.home.impl.contract -import com.team.prezel.core.ui.UiEffect +import com.team.prezel.core.ui.base.UiEffect import com.team.prezel.feature.home.impl.model.HomeUiMessage internal sealed interface HomeUiEffect : UiEffect { diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiIntent.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiIntent.kt index ae9e7977..103fa67f 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiIntent.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiIntent.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.home.impl.contract -import com.team.prezel.core.ui.UiIntent +import com.team.prezel.core.ui.base.UiIntent internal sealed interface HomeUiIntent : UiIntent { data object FetchData : HomeUiIntent diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiState.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiState.kt index 2a3d5f8f..742cb022 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiState.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/contract/HomeUiState.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.home.impl.contract import androidx.compose.runtime.Immutable -import com.team.prezel.core.ui.UiState +import com.team.prezel.core.ui.base.UiState import com.team.prezel.feature.home.impl.model.PresentationUiModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginScreen.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginScreen.kt index 5af2aab7..3dfbdb50 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginScreen.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginScreen.kt @@ -40,7 +40,7 @@ import com.team.prezel.core.designsystem.component.feedback.snackbar.showPrezelS import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme -import com.team.prezel.core.ui.LocalSnackbarHostState +import com.team.prezel.core.ui.state.LocalSnackbarHostState import com.team.prezel.feature.login.api.AUTH_LOGO_SHARED_ELEMENT_KEY import com.team.prezel.feature.login.impl.R import com.team.prezel.feature.login.impl.landing.contract.LoginUiEffect diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginViewModel.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginViewModel.kt index 327eb366..ad33f64c 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginViewModel.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/LoginViewModel.kt @@ -3,7 +3,7 @@ package com.team.prezel.feature.login.impl.landing import androidx.lifecycle.viewModelScope import com.team.prezel.core.auth.model.AuthProvider import com.team.prezel.core.auth.model.AuthResult -import com.team.prezel.core.ui.BaseViewModel +import com.team.prezel.core.ui.base.BaseViewModel import com.team.prezel.feature.login.impl.BuildConfig import com.team.prezel.feature.login.impl.landing.contract.LoginUiEffect import com.team.prezel.feature.login.impl.landing.contract.LoginUiIntent diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiEffect.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiEffect.kt index 4c3a7047..9b7b38b3 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiEffect.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiEffect.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.login.impl.landing.contract import com.team.prezel.core.auth.model.AuthProvider -import com.team.prezel.core.ui.UiEffect +import com.team.prezel.core.ui.base.UiEffect import com.team.prezel.feature.login.impl.landing.model.LoginUiMessage internal sealed interface LoginUiEffect : UiEffect { diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiIntent.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiIntent.kt index c0d8f2fb..20610b13 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiIntent.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiIntent.kt @@ -2,7 +2,7 @@ package com.team.prezel.feature.login.impl.landing.contract import com.team.prezel.core.auth.model.AuthProvider import com.team.prezel.core.auth.model.AuthResult -import com.team.prezel.core.ui.UiIntent +import com.team.prezel.core.ui.base.UiIntent internal sealed interface LoginUiIntent : UiIntent { data class OnClickLogin( diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiState.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiState.kt index 0a7c3b41..543b16b0 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiState.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/landing/contract/LoginUiState.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.login.impl.landing.contract import androidx.compose.runtime.Immutable -import com.team.prezel.core.ui.UiState +import com.team.prezel.core.ui.base.UiState @Immutable internal data class LoginUiState( diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsScreen.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsScreen.kt index e98f5c3f..310ccb0b 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsScreen.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsScreen.kt @@ -1,6 +1,7 @@ package com.team.prezel.feature.login.impl.terms import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -209,7 +210,11 @@ private fun TermsSelectAllRow( modifier: Modifier = Modifier, ) { PrezelList( - modifier = modifier, + modifier = modifier.clickable( + onClick = onToggleAll, + indication = null, + interactionSource = null, + ), title = stringResource(R.string.feature_login_impl_terms_all), size = PrezelListSize.REGULAR, nested = true, diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsViewModel.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsViewModel.kt index e294f70e..66b86b84 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsViewModel.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/TermsViewModel.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.login.impl.terms import androidx.lifecycle.viewModelScope -import com.team.prezel.core.ui.BaseViewModel +import com.team.prezel.core.ui.base.BaseViewModel import com.team.prezel.feature.login.impl.terms.contract.TermsUiEffect import com.team.prezel.feature.login.impl.terms.contract.TermsUiIntent import com.team.prezel.feature.login.impl.terms.contract.TermsUiState diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiEffect.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiEffect.kt index 342ab709..a5c11b76 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiEffect.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiEffect.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.login.impl.terms.contract -import com.team.prezel.core.ui.UiEffect +import com.team.prezel.core.ui.base.UiEffect internal sealed interface TermsUiEffect : UiEffect { data object NavigateToProfile : TermsUiEffect diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiIntent.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiIntent.kt index 5069e2e8..b38fd048 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiIntent.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiIntent.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.login.impl.terms.contract -import com.team.prezel.core.ui.UiIntent +import com.team.prezel.core.ui.base.UiIntent internal sealed interface TermsUiIntent : UiIntent { data object ToggleAll : TermsUiIntent diff --git a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiState.kt b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiState.kt index 581c1ac7..4ca27a0f 100644 --- a/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiState.kt +++ b/Prezel/feature/login/impl/src/main/java/com/team/prezel/feature/login/impl/terms/contract/TermsUiState.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.login.impl.terms.contract import androidx.compose.runtime.Immutable -import com.team.prezel.core.ui.UiState +import com.team.prezel.core.ui.base.UiState @Immutable internal data class TermsUiState( diff --git a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileScreen.kt b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileScreen.kt index d941da3b..35ce18ad 100644 --- a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileScreen.kt +++ b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileScreen.kt @@ -3,6 +3,7 @@ package com.team.prezel.feature.profile.impl import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -13,6 +14,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.stringResource import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel @@ -22,8 +25,8 @@ import com.team.prezel.core.designsystem.component.feedback.snackbar.showPrezelS import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme import com.team.prezel.core.model.profile.User -import com.team.prezel.core.ui.LocalSnackbarHostState -import com.team.prezel.core.ui.advancedImePadding +import com.team.prezel.core.ui.state.LocalSnackbarHostState +import com.team.prezel.core.ui.util.advancedImePadding import com.team.prezel.feature.profile.impl.component.NicknameTextField import com.team.prezel.feature.profile.impl.component.ProfileImageEditor import com.team.prezel.feature.profile.impl.component.ProfileScreenTopAppBar @@ -141,8 +144,11 @@ private fun ProfileScreenContent( onClickProfileImage: () -> Unit, modifier: Modifier = Modifier, ) { + val focusManager = LocalFocusManager.current + Column( modifier = modifier + .pointerInput(Unit) { detectTapGestures(onTap = { focusManager.clearFocus() }) } .padding(horizontal = PrezelTheme.spacing.V20) .padding(top = PrezelTheme.spacing.V16), ) { diff --git a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileViewModel.kt b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileViewModel.kt index 9778bac2..77cd8eb3 100644 --- a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileViewModel.kt +++ b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/ProfileViewModel.kt @@ -5,7 +5,7 @@ import com.team.prezel.core.domain.usecase.user.FetchUserInfoUseCase import com.team.prezel.core.domain.usecase.user.ValidateNicknameUseCase import com.team.prezel.core.model.profile.Nickname import com.team.prezel.core.model.profile.User -import com.team.prezel.core.ui.BaseViewModel +import com.team.prezel.core.ui.base.BaseViewModel import com.team.prezel.feature.profile.impl.contract.ProfileUiEffect import com.team.prezel.feature.profile.impl.contract.ProfileUiIntent import com.team.prezel.feature.profile.impl.contract.ProfileUiState diff --git a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/component/NicknameTextField.kt b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/component/NicknameTextField.kt index 59d67e7f..2cc650f0 100644 --- a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/component/NicknameTextField.kt +++ b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/component/NicknameTextField.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.component.textfield.PrezelTextField -import com.team.prezel.core.designsystem.component.textfield.PrezelTextFieldFeedback +import com.team.prezel.core.designsystem.component.textfield.PrezelTextFieldStatus import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme import com.team.prezel.feature.profile.impl.R @@ -28,7 +28,7 @@ internal fun NicknameTextField( onValueChange = onNicknameChanged, label = stringResource(R.string.feature_profile_impl_nickname_text_field_label), placeholder = stringResource(R.string.feature_profile_impl_nickname_text_field_placeholder), - feedback = nicknameValidationState.toNicknameFeedback(), + status = nicknameValidationState.toNicknameStatus(), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, ), @@ -37,26 +37,26 @@ internal fun NicknameTextField( } @Composable -private fun NicknameValidationState.toNicknameFeedback(): PrezelTextFieldFeedback = +private fun NicknameValidationState.toNicknameStatus(): PrezelTextFieldStatus = when (this) { NicknameValidationState.Unchecked, NicknameValidationState.Checking, NicknameValidationState.TooLong, - -> PrezelTextFieldFeedback.NO_MESSAGE + -> PrezelTextFieldStatus.DEFAULT - NicknameValidationState.Available -> PrezelTextFieldFeedback.Good( + NicknameValidationState.Available -> PrezelTextFieldStatus.Default( message = stringResource(R.string.feature_profile_impl_nickname_helper_available), ) - NicknameValidationState.TooShort -> PrezelTextFieldFeedback.Bad( + NicknameValidationState.TooShort -> PrezelTextFieldStatus.Bad( message = stringResource(R.string.feature_profile_impl_nickname_helper_too_short), ) - NicknameValidationState.Duplicated -> PrezelTextFieldFeedback.Bad( + NicknameValidationState.Duplicated -> PrezelTextFieldStatus.Bad( message = stringResource(R.string.feature_profile_impl_nickname_helper_duplicated), ) - NicknameValidationState.InvalidCharacter -> PrezelTextFieldFeedback.Bad( + NicknameValidationState.InvalidCharacter -> PrezelTextFieldStatus.Bad( message = stringResource(R.string.feature_profile_impl_nickname_helper_unavailable), ) } diff --git a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiEffect.kt b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiEffect.kt index 5272c49e..be38e2bc 100644 --- a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiEffect.kt +++ b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiEffect.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.profile.impl.contract -import com.team.prezel.core.ui.UiEffect +import com.team.prezel.core.ui.base.UiEffect import com.team.prezel.feature.profile.impl.model.ProfileUiMessage internal sealed interface ProfileUiEffect : UiEffect { diff --git a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiIntent.kt b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiIntent.kt index 3831ee18..91e5f270 100644 --- a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiIntent.kt +++ b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiIntent.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.profile.impl.contract -import com.team.prezel.core.ui.UiIntent +import com.team.prezel.core.ui.base.UiIntent internal sealed interface ProfileUiIntent : UiIntent { data object FetchData : ProfileUiIntent diff --git a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiState.kt b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiState.kt index 7f34cf00..a23a2eee 100644 --- a/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiState.kt +++ b/Prezel/feature/profile/impl/src/main/java/com/team/prezel/feature/profile/impl/contract/ProfileUiState.kt @@ -2,7 +2,7 @@ package com.team.prezel.feature.profile.impl.contract import androidx.compose.runtime.Immutable import com.team.prezel.core.model.profile.User -import com.team.prezel.core.ui.UiState +import com.team.prezel.core.ui.base.UiState import com.team.prezel.feature.profile.impl.model.NicknameValidationState @Immutable diff --git a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/SplashViewModel.kt b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/SplashViewModel.kt index 87587b4d..a4476529 100644 --- a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/SplashViewModel.kt +++ b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/SplashViewModel.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.splash.impl import androidx.lifecycle.viewModelScope -import com.team.prezel.core.ui.BaseViewModel +import com.team.prezel.core.ui.base.BaseViewModel import com.team.prezel.feature.splash.impl.contract.SplashUiEffect import com.team.prezel.feature.splash.impl.contract.SplashUiIntent import com.team.prezel.feature.splash.impl.contract.SplashUiState diff --git a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiEffect.kt b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiEffect.kt index 82273d89..5bbe6918 100644 --- a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiEffect.kt +++ b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiEffect.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.splash.impl.contract -import com.team.prezel.core.ui.UiEffect +import com.team.prezel.core.ui.base.UiEffect sealed interface SplashUiEffect : UiEffect { data object NavigateToHome : SplashUiEffect diff --git a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiIntent.kt b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiIntent.kt index 328baf6c..326eb17e 100644 --- a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiIntent.kt +++ b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiIntent.kt @@ -1,6 +1,6 @@ package com.team.prezel.feature.splash.impl.contract -import com.team.prezel.core.ui.UiIntent +import com.team.prezel.core.ui.base.UiIntent sealed interface SplashUiIntent : UiIntent { data object CheckLoginStatus : SplashUiIntent diff --git a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiState.kt b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiState.kt index 6a06fb06..168ee701 100644 --- a/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiState.kt +++ b/Prezel/feature/splash/impl/src/main/java/com/team/prezel/feature/splash/impl/contract/SplashUiState.kt @@ -1,7 +1,7 @@ package com.team.prezel.feature.splash.impl.contract import androidx.compose.runtime.Immutable -import com.team.prezel.core.ui.UiState +import com.team.prezel.core.ui.base.UiState @Immutable internal data class SplashUiState(