From a5e817bf97980fd440d4cc8cafff91e0d2bfaa0c Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 01:36:36 +0900 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20BaseViewModel=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `core:ui` 모듈 내 공통으로 사용되는 UI 베이스 클래스들의 패키지 위치를 변경하고, 이를 참조하는 모든 피처 모듈의 임포트 경로를 업데이트했습니다. * **refactor: BaseViewModel 위치 이동 및 패키지명 변경** * `com.team.prezel.core.ui.BaseViewModel` -> `com.team.prezel.core.ui.base.BaseViewModel`로 이동 * `UiState`, `UiIntent`, `UiEffect` 인터페이스를 `com.team.prezel.core.ui.base` 패키지로 관리하도록 구조 개선 * **refactor: 피처 모듈 내 참조 경로 업데이트** * `home`, `profile`, `login`, `history`, `splash` 등 각 피처 모듈 내 `ViewModel`, `UiState`, `UiIntent`, `UiEffect`에서 변경된 `core.ui.base` 패키지를 참조하도록 수정했습니다. --- .../java/com/team/prezel/core/ui/{ => base}/BaseViewModel.kt | 2 +- .../com/team/prezel/feature/history/impl/HistoryViewModel.kt | 2 +- .../prezel/feature/history/impl/contract/HistoryUiEffect.kt | 2 +- .../prezel/feature/history/impl/contract/HistoryUiIntent.kt | 2 +- .../team/prezel/feature/history/impl/contract/HistoryUiState.kt | 2 +- .../java/com/team/prezel/feature/home/impl/HomeViewModel.kt | 2 +- .../com/team/prezel/feature/home/impl/contract/HomeUiEffect.kt | 2 +- .../com/team/prezel/feature/home/impl/contract/HomeUiIntent.kt | 2 +- .../com/team/prezel/feature/home/impl/contract/HomeUiState.kt | 2 +- .../team/prezel/feature/login/impl/landing/LoginViewModel.kt | 2 +- .../prezel/feature/login/impl/landing/contract/LoginUiEffect.kt | 2 +- .../prezel/feature/login/impl/landing/contract/LoginUiIntent.kt | 2 +- .../prezel/feature/login/impl/landing/contract/LoginUiState.kt | 2 +- .../com/team/prezel/feature/login/impl/terms/TermsViewModel.kt | 2 +- .../prezel/feature/login/impl/terms/contract/TermsUiEffect.kt | 2 +- .../prezel/feature/login/impl/terms/contract/TermsUiIntent.kt | 2 +- .../prezel/feature/login/impl/terms/contract/TermsUiState.kt | 2 +- .../com/team/prezel/feature/profile/impl/ProfileViewModel.kt | 2 +- .../prezel/feature/profile/impl/contract/ProfileUiEffect.kt | 2 +- .../prezel/feature/profile/impl/contract/ProfileUiIntent.kt | 2 +- .../team/prezel/feature/profile/impl/contract/ProfileUiState.kt | 2 +- .../java/com/team/prezel/feature/splash/impl/SplashViewModel.kt | 2 +- .../team/prezel/feature/splash/impl/contract/SplashUiEffect.kt | 2 +- .../team/prezel/feature/splash/impl/contract/SplashUiIntent.kt | 2 +- .../team/prezel/feature/splash/impl/contract/SplashUiState.kt | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) rename Prezel/core/ui/src/main/java/com/team/prezel/core/ui/{ => base}/BaseViewModel.kt (96%) 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/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/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/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/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/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/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/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/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( From 0748efe8e7f6e1a6a0e7ca59f238d0d1dc4da40c Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 01:56:38 +0900 Subject: [PATCH 2/9] =?UTF-8?q?refactor:=20StatusView=20=EC=9C=84=EC=B9=98?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99=20=EB=B0=8F=20PrezelLottie=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: StatusView 패키지 위치 변경 및 코드 정리 * `StatusView`를 `com.team.prezel.core.ui`에서 `com.team.prezel.core.ui.component` 패키지로 이동하였습니다. * `StatusView.kt` 내부에 정의되어 있던 `StatusLottie`와 로딩 프리뷰 코드를 제거하였습니다. * feat: 공용 Lottie 컴포저블 `PrezelLottie` 구현 * Lottie 애니메이션을 일관되게 사용하기 위해 `PrezelLottie` 컴포넌트를 새롭게 추가하였습니다. * `isPlaying`, `iterations`, `speed`, `onAnimationFrame` 등 다양한 속성을 제어할 수 있도록 파라미터를 제공합니다. * refactor: HistoryEmptyContent 내 StatusView 참조 수정 * `StatusView` 패키지 위치 변경에 따른 import 문을 업데이트하였습니다. --- .../prezel/core/ui/component/PrezelLottie.kt | 61 +++++++++++++++++++ .../core/ui/{ => component}/StatusView.kt | 43 +------------ .../impl/component/HistoryEmptyContent.kt | 2 +- 3 files changed, 63 insertions(+), 43 deletions(-) create mode 100644 Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelLottie.kt rename Prezel/core/ui/src/main/java/com/team/prezel/core/ui/{ => component}/StatusView.kt (77%) 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..c09ee927 --- /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.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) + + if (updatedCallback != null) { + 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/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 From bdeb8df64bb6355f98f884fe5ca4149f3bb1b953 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 01:57:23 +0900 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20core:ui=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EB=82=B4=20=EC=9C=A0=ED=8B=B8=EB=A6=AC=ED=8B=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit core:ui 모듈의 유지보수성을 높이기 위해 파일 위치를 기능별 패키지(`util`, `state`)로 재배치하고 관련 임포트를 업데이트했습니다. * **refactor: 유틸리티 및 상태 관련 파일 패키지 이동** * `AdvancedImePadding.kt` 및 `OnHeightChanged.kt` 파일을 `com.team.prezel.core.ui.util` 패키지로 이동했습니다. * `LocalSnackbarHostState.kt` 파일을 `com.team.prezel.core.ui.state` 패키지로 이동했습니다. * **style: 변경된 구조에 따른 임포트 경로 수정** * `ProfileScreen`, `HistoryScreen`, `HomeScreen`, `LoginScreen` 등 각 피처 모듈에서 변경된 패키지 경로를 반영하도록 수정했습니다. * `PrezelApp` 및 `DoubleBackToExitHandler` 내 `LocalSnackbarHostState` 참조 경로를 업데이트했습니다. --- .../main/java/com/team/prezel/ui/DoubleBackToExitHandler.kt | 2 +- Prezel/app/src/main/java/com/team/prezel/ui/PrezelApp.kt | 2 +- .../team/prezel/core/ui/{ => state}/LocalSnackbarHostState.kt | 2 +- .../com/team/prezel/core/ui/{ => util}/AdvancedImePadding.kt | 2 +- .../com/team/prezel/core/ui/{ => util}/OnHeightChanged.kt | 2 +- .../com/team/prezel/feature/history/impl/HistoryScreen.kt | 2 +- .../main/java/com/team/prezel/feature/home/impl/HomeScreen.kt | 4 ++-- .../team/prezel/feature/home/impl/component/HomePageLayout.kt | 2 +- .../com/team/prezel/feature/login/impl/landing/LoginScreen.kt | 2 +- .../com/team/prezel/feature/profile/impl/ProfileScreen.kt | 4 ++-- 10 files changed, 12 insertions(+), 12 deletions(-) rename Prezel/core/ui/src/main/java/com/team/prezel/core/ui/{ => state}/LocalSnackbarHostState.kt (86%) rename Prezel/core/ui/src/main/java/com/team/prezel/core/ui/{ => util}/AdvancedImePadding.kt (96%) rename Prezel/core/ui/src/main/java/com/team/prezel/core/ui/{ => util}/OnHeightChanged.kt (92%) 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 182126b8..e7c28915 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.modal.snackbar.dismissById import com.team.prezel.core.designsystem.component.modal.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/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 4a519dd0..c7614fa4 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/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 4a0c7c83..aad10cc9 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.modal.snackbar.showPrezelSnac 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/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/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 a018d390..adea24fd 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.modal.snackbar.showPrezelSnac 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/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 7057f354..a7e00608 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 @@ -22,8 +22,8 @@ import com.team.prezel.core.designsystem.component.modal.snackbar.showPrezelSnac 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 From e81331be8ca7cce38691035f892a28594e7cba83 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 04:16:14 +0900 Subject: [PATCH 4/9] =?UTF-8?q?refactor:=20PrezelTextField=20=EB=B0=8F=20P?= =?UTF-8?q?rezelTextArea=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TextField와 TextArea의 상태 관리 로직을 단순화하고 명칭을 직관적으로 변경하여 유지보수성을 높였습니다. * **명칭 및 타입 변경**: * `PrezelTextFieldInteraction` -> `PrezelTextFieldState`로 변경 (DEFAULT, DISABLED, TYPING, TYPED) * `PrezelTextFieldFeedback` -> `PrezelTextFieldStatus`로 변경 (Default, Good, Bad) * `PrezelTextFieldState` -> `PrezelTextFieldStyle`로 변경 (State와 Status를 결합한 스타일 정보 객체) * **로직 개선**: * `rememberPrezelTextFieldInteraction`의 복잡한 `debounce` 기반 Idle 상태 체크 로직을 제거하고, 포커스 여부와 값 존재 여부에 따라 상태를 결정하는 `rememberPrezelTextFieldState`로 단순화했습니다. * 공통 텍스트 입력 정책(`applyPrezelTextInputPolicy`)을 추출하여 TextField와 TextArea에서 공유하도록 수정했습니다. * 포커스 상태일 때 플레이스홀더를 숨기던 로직을 `showPlaceholder` 파라미터 제어를 통해 명확하게 처리했습니다. * **UI 및 스타일 수정**: * `TYPING` 상태에서도 `Status`에 따라 배경색과 테두리 색상이 반영되도록 스타일 계산 로직을 업데이트했습니다. * `State`와 `Status` 조합에 따른 텍스트, 아이콘, 테두리 색상 적용 규칙을 세분화했습니다. * **기타**: * Preview 코드를 상태별(Default, Disabled, Typing, Typed)로 분리하여 가독성을 개선했습니다. * 불필요한 import 문과 사용되지 않는 파라미터를 정리했습니다. --- .../component/textfield/PrezelTextArea.kt | 212 ++++++++-------- .../component/textfield/PrezelTextField.kt | 227 +++++++++--------- .../textfield/PrezelTextFieldState.kt | 195 ++++++++------- .../PrezelTextFieldSupportingText.kt | 24 +- 4 files changed, 340 insertions(+), 318 deletions(-) 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..677b44b5 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 state = 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, + placeholder = placeholder, state = state, 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, + state: PrezelTextFieldStyle, + focused: Boolean, onFocusChange: (Boolean) -> Unit, label: String?, enabled: Boolean, @@ -120,7 +110,7 @@ private fun PrezelTextArea( decorationBox = { innerTextField -> PrezelTextAreaDecorationBox( innerTextField = innerTextField, - showPlaceholder = value.isEmpty(), + showPlaceholder = !focused && value.isEmpty(), placeholder = placeholder, state = state, counter = { @@ -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,8 +298,10 @@ 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, @@ -291,9 +310,10 @@ private fun PrezelTextAreaPreviewItem( label = label, state = 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..0a903332 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, + placeholder = placeholder, state = 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, + state: PrezelTextFieldStyle, + focused: Boolean, onFocusChange: (Boolean) -> Unit, modifier: Modifier = Modifier, label: String? = null, @@ -127,7 +115,7 @@ private fun PrezelTextField( decorationBox = { innerTextField -> PrezelTextFieldDecorationBox( innerTextField = innerTextField, - showPlaceholder = value.isEmpty(), + showPlaceholder = !focused && value.isEmpty(), placeholder = placeholder, trailingIcon = trailingIcon, state = state, @@ -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,8 +290,10 @@ 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, @@ -296,14 +301,18 @@ private fun PreviewTextFieldItem( placeholder = "Placeholder", label = label, state = 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..0270790e 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,20 @@ 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 +34,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 +135,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 +211,22 @@ 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 +): PrezelTextFieldState = + remember(value, enabled, focused) { + PrezelTextFieldState.calculate(enabled = enabled, focused = focused, hasValue = value.isNotEmpty()) } - LaunchedEffect(idleMillis) { - snapshotFlow { latestValue } - .distinctUntilChanged() - .onEach { isIdle = false } - .debounce(idleMillis) - .collectLatest { if (latestEnabled && latestFocused) isIdle = true } - } - - return PrezelTextFieldInteraction.calculate( - enabled = enabled, - focused = focused, - isIdle = isIdle, - ) +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..66873beb 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,16 +3,16 @@ 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 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, + state: PrezelTextFieldStyle, modifier: Modifier = Modifier, ) { Text( @@ -29,23 +29,23 @@ internal fun PrezelTextFieldSupportingText( private fun PrezelTextFieldSupportingTextPreview() { PreviewSection(title = "Supporting Text") { PrezelTextFieldSupportingText( - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Default("헬퍼 메시지"), + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Default("헬퍼 메시지"), ), ) PrezelTextFieldSupportingText( - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Bad("헬퍼 메시지"), + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), ), ) PrezelTextFieldSupportingText( - state = PrezelTextFieldState( - interaction = PrezelTextFieldInteraction.TYPED, - feedback = PrezelTextFieldFeedback.Good("헬퍼 메시지"), + state = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Good("헬퍼 메시지"), ), ) } From 3cd99c5f2b0f80c118f1777a17660bb3cfa3c7be Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 04:17:33 +0900 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=99=B8=EB=B6=80=20=EC=98=81=EC=97=AD=20?= =?UTF-8?q?=ED=84=B0=EC=B9=98=20=EC=8B=9C=20=ED=8F=AC=EC=BB=A4=EC=8A=A4=20?= =?UTF-8?q?=ED=95=B4=EC=A0=9C=20=EB=B0=8F=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=83=81=ED=83=9C=20API=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **feat: 프로필 화면 배경 터치 시 키보드 숨김 기능 추가** * `ProfileContent` 컨테이너에 `pointerInput`과 `FocusManager`를 적용하여, 빈 영역을 탭했을 때 입력 포커스가 해제되도록 개선했습니다. * **refactor: 디자인 시스템 변경에 따른 텍스트 필드 상태 관련 코드 수정** * `PrezelTextField`의 파라미터가 `feedback`에서 `status`로 변경됨에 따라 관련 로직을 수정했습니다. * `PrezelTextFieldFeedback`을 `PrezelTextFieldStatus`로 교체하였습니다. * `toNicknameFeedback` 확장 함수명을 `toNicknameStatus`로 변경하고, 내부 상태 매핑 로직(`NO_MESSAGE` -> `DEFAULT`, `Good` -> `Default`)을 최신 디자인 시스템 정의에 맞게 업데이트했습니다. --- .../prezel/feature/profile/impl/ProfileScreen.kt | 6 ++++++ .../profile/impl/component/NicknameTextField.kt | 16 ++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) 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 a7e00608..df464107 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 @@ -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/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), ) } From 2bedbb3d0b54143a14c54f4131226e16ababc715 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 04:49:40 +0900 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20PrezelLottie=20=EC=95=A0?= =?UTF-8?q?=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=BD=9C=EB=B0=B1=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `onAnimationFrame` 콜백이 `progress` 상태 변화에 따라 실행되도록 `LaunchedEffect`를 적용하였습니다. * 기존 컴포저블 본문에서 직접 호출하던 방식에서 Side-effect API를 사용하는 구조로 변경하여 안정성을 높였습니다. --- .../java/com/team/prezel/core/ui/component/PrezelLottie.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index c09ee927..c4f3d6a8 100644 --- 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 @@ -2,6 +2,7 @@ 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 @@ -37,8 +38,7 @@ fun PrezelLottie( ) val updatedCallback by rememberUpdatedState(onAnimationFrame) - - if (updatedCallback != null) { + LaunchedEffect(progress) { updatedCallback?.invoke(progress) } From fcea21b04572a23ffd32c420e18cc710132b9afc Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 04:52:18 +0900 Subject: [PATCH 7/9] =?UTF-8?q?refactor:=20PrezelTextFieldState=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=ED=8F=AC=EB=A7=B7=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelTextField`의 상태 관리 로직을 최적화하고 가독성을 위해 코드 포맷을 수정했습니다. * **refactor: remember 블록 제거 및 상태 계산 로직 최적화** * `rememberPrezelTextFieldState` 함수에서 불필요한 `remember` 블록을 제거하여 호출부에서 상태를 직접 계산하도록 변경했습니다. * **style: 코드 포맷팅 및 들여쓰기 수정** * `PrezelTextFieldStyle` 내 `backgroundColor`, `iconColor`, `border` 관련 `when` 조건문의 들여쓰기를 수정하여 가독성을 개선했습니다. * 불필요한 import(`androidx.compose.runtime.remember`)를 제거했습니다. --- .../textfield/PrezelTextFieldState.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 0270790e..93e11acc 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 @@ -4,7 +4,6 @@ import androidx.compose.foundation.BorderStroke import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable -import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.foundation.color.PrezelColors @@ -104,11 +103,11 @@ data class PrezelTextFieldStyle( when (state) { PrezelTextFieldState.DEFAULT, PrezelTextFieldState.DISABLED, - -> Color.Transparent + -> Color.Transparent PrezelTextFieldState.TYPING, PrezelTextFieldState.TYPED, - -> when (status) { + -> when (status) { is PrezelTextFieldStatus.Default -> Color.Transparent is PrezelTextFieldStatus.Good -> colors.feedbackGoodSmall is PrezelTextFieldStatus.Bad -> colors.feedbackBadSmall @@ -162,11 +161,11 @@ data class PrezelTextFieldStyle( when (state) { PrezelTextFieldState.DISABLED, PrezelTextFieldState.DEFAULT, - -> colors.iconDisabled + -> colors.iconDisabled PrezelTextFieldState.TYPING, PrezelTextFieldState.TYPED, - -> when (status) { + -> when (status) { is PrezelTextFieldStatus.Default -> colors.iconRegular is PrezelTextFieldStatus.Good -> colors.interactiveRegular is PrezelTextFieldStatus.Bad -> colors.feedbackBadRegular @@ -184,11 +183,11 @@ data class PrezelTextFieldStyle( val borderWidth = when (state) { PrezelTextFieldState.DEFAULT, PrezelTextFieldState.DISABLED, - -> 1.dp + -> 1.dp PrezelTextFieldState.TYPING, PrezelTextFieldState.TYPED, - -> 2.dp + -> 2.dp } val borderColor = when (state) { @@ -216,10 +215,11 @@ internal fun rememberPrezelTextFieldState( value: String, enabled: Boolean, focused: Boolean, -): PrezelTextFieldState = - remember(value, enabled, focused) { - PrezelTextFieldState.calculate(enabled = enabled, focused = focused, hasValue = value.isNotEmpty()) - } +): PrezelTextFieldState = PrezelTextFieldState.calculate( + enabled = enabled, + focused = focused, + hasValue = value.isNotEmpty(), +) internal fun applyPrezelTextInputPolicy( value: String, From b2cb7f9ab057fe4146da86c5dfaee240b42afa7b Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 04:56:52 +0900 Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20TextField=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EB=AA=85=EC=B9=AD=20=EB=B0=8F=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelTextField` 및 `PrezelTextArea` 컴포넌트의 가독성을 높이고 내부 로직을 정리하였습니다. * **refactor: TextField 및 TextArea 파라미터 명칭 변경** * 내부 UI 구성에 사용되는 `PrezelTextFieldStyle` 타입의 파라미터 명칭을 `state`에서 `style`로 변경하여 역할을 명확히 함 * `rememberPrezelTextFieldState` 결과값 변수명을 `state`에서 `style`로 변경 * **refactor: PrezelTextFieldSupportingText 구조 개선** * 기존에 `PrezelTextFieldStyle` 객체 전체를 전달받던 방식에서 `text`와 `textColor`를 개별 파라미터로 직접 전달받도록 수정하여 결합도를 낮춤 * 변경된 구조에 맞춰 Preview 코드 및 호출부 로직 수정 * **style: 코드 포맷팅 및 정렬 수정** * `PrezelTextFieldState.kt` 내 `when` 문 및 함수 반환 타입 선언부의 들여쓰기와 줄바꿈을 일관성 있게 수정하여 가독성 개선 --- .../component/textfield/PrezelTextArea.kt | 18 ++++----- .../component/textfield/PrezelTextField.kt | 14 +++---- .../textfield/PrezelTextFieldState.kt | 23 +++++------ .../PrezelTextFieldSupportingText.kt | 38 +++++++++++-------- 4 files changed, 51 insertions(+), 42 deletions(-) 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 677b44b5..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 @@ -47,7 +47,7 @@ fun PrezelTextArea( ) { var focused by remember { mutableStateOf(false) } - val state = rememberPrezelTextFieldState( + val style = rememberPrezelTextFieldState( value = value, enabled = enabled, focused = focused, @@ -60,7 +60,7 @@ fun PrezelTextArea( if (applied != value) onValueChange(applied) }, placeholder = placeholder, - state = state, + style = style, maxLength = maxLength, focused = focused, onFocusChange = { isFocused -> focused = isFocused }, @@ -79,7 +79,7 @@ private fun PrezelTextArea( onValueChange: (String) -> Unit, placeholder: String, maxLength: Int, - state: PrezelTextFieldStyle, + style: PrezelTextFieldStyle, focused: Boolean, onFocusChange: (Boolean) -> Unit, label: String?, @@ -103,7 +103,7 @@ 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, @@ -112,11 +112,11 @@ private fun PrezelTextArea( innerTextField = innerTextField, 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), @@ -124,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()) } } } @@ -308,7 +308,7 @@ private fun PrezelTextAreaPreviewItem( onValueChange = {}, placeholder = "Placeholder", label = label, - state = state, + style = state, maxLength = 100, focused = focused, modifier = modifier, 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 0a903332..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 @@ -66,7 +66,7 @@ fun PrezelTextField( if (applied != value) onValueChange(applied) }, placeholder = placeholder, - state = state, + style = state, focused = focused, onFocusChange = { isFocused -> focused = isFocused }, modifier = modifier, @@ -83,7 +83,7 @@ private fun PrezelTextField( value: String, onValueChange: (String) -> Unit, placeholder: String, - state: PrezelTextFieldStyle, + style: PrezelTextFieldStyle, focused: Boolean, onFocusChange: (Boolean) -> Unit, modifier: Modifier = Modifier, @@ -108,7 +108,7 @@ 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, @@ -118,14 +118,14 @@ private fun PrezelTextField( 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()) } } } @@ -300,7 +300,7 @@ private fun PreviewTextFieldItem( onValueChange = {}, placeholder = "Placeholder", label = label, - state = state, + style = state, focused = focused, modifier = modifier, onFocusChange = {}, 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 93e11acc..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 @@ -103,11 +103,11 @@ data class PrezelTextFieldStyle( when (state) { PrezelTextFieldState.DEFAULT, PrezelTextFieldState.DISABLED, - -> Color.Transparent + -> Color.Transparent PrezelTextFieldState.TYPING, PrezelTextFieldState.TYPED, - -> when (status) { + -> when (status) { is PrezelTextFieldStatus.Default -> Color.Transparent is PrezelTextFieldStatus.Good -> colors.feedbackGoodSmall is PrezelTextFieldStatus.Bad -> colors.feedbackBadSmall @@ -161,11 +161,11 @@ data class PrezelTextFieldStyle( when (state) { PrezelTextFieldState.DISABLED, PrezelTextFieldState.DEFAULT, - -> colors.iconDisabled + -> colors.iconDisabled PrezelTextFieldState.TYPING, PrezelTextFieldState.TYPED, - -> when (status) { + -> when (status) { is PrezelTextFieldStatus.Default -> colors.iconRegular is PrezelTextFieldStatus.Good -> colors.interactiveRegular is PrezelTextFieldStatus.Bad -> colors.feedbackBadRegular @@ -183,11 +183,11 @@ data class PrezelTextFieldStyle( val borderWidth = when (state) { PrezelTextFieldState.DEFAULT, PrezelTextFieldState.DISABLED, - -> 1.dp + -> 1.dp PrezelTextFieldState.TYPING, PrezelTextFieldState.TYPED, - -> 2.dp + -> 2.dp } val borderColor = when (state) { @@ -215,11 +215,12 @@ internal fun rememberPrezelTextFieldState( value: String, enabled: Boolean, focused: Boolean, -): PrezelTextFieldState = PrezelTextFieldState.calculate( - enabled = enabled, - focused = focused, - hasValue = value.isNotEmpty(), -) +): PrezelTextFieldState = + PrezelTextFieldState.calculate( + enabled = enabled, + focused = focused, + hasValue = value.isNotEmpty(), + ) internal fun applyPrezelTextInputPolicy( value: String, 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 66873beb..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,6 +3,7 @@ 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 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 @@ -12,13 +13,14 @@ import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable internal fun PrezelTextFieldSupportingText( - state: PrezelTextFieldStyle, + 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 = PrezelTextFieldStyle( - state = PrezelTextFieldState.TYPED, - status = PrezelTextFieldStatus.Default("헬퍼 메시지"), - ), + text = default.supportingText, + textColor = default.supportingTextColor(), ) + val bad = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), + ) PrezelTextFieldSupportingText( - state = PrezelTextFieldStyle( - state = PrezelTextFieldState.TYPED, - status = PrezelTextFieldStatus.Bad("헬퍼 메시지"), - ), + text = bad.supportingText, + textColor = bad.supportingTextColor(), ) + val good = PrezelTextFieldStyle( + state = PrezelTextFieldState.TYPED, + status = PrezelTextFieldStatus.Good("헬퍼 메시지"), + ) PrezelTextFieldSupportingText( - state = PrezelTextFieldStyle( - state = PrezelTextFieldState.TYPED, - status = PrezelTextFieldStatus.Good("헬퍼 메시지"), - ), + text = good.supportingText, + textColor = good.supportingTextColor(), ) } } From 77c8f35c73f1719c5ce2434fd683064292b19f9a Mon Sep 17 00:00:00 2001 From: moondev03 Date: Wed, 22 Apr 2026 04:59:07 +0900 Subject: [PATCH 9/9] =?UTF-8?q?refactor:=20TermsScreen=20=EB=82=B4=20?= =?UTF-8?q?=EC=95=BD=EA=B4=80=20=EC=A0=84=EC=B2=B4=20=EB=8F=99=EC=9D=98=20?= =?UTF-8?q?=EC=98=81=EC=97=AD=20=ED=81=B4=EB=A6=AD=20=EB=B2=94=EC=9C=84=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `TermsScreen`의 전체 동의 리스트 아이템(`PrezelList`)에 `clickable` 수식어를 추가하여, 체크박스뿐만 아니라 텍스트 영역을 클릭해도 `onToggleAll` 이벤트가 발생하도록 개선했습니다. 리플 효과(indication)와 상호작용 소스(interactionSource)를 `null`로 설정하여 불필요한 시각적 효과를 제거했습니다. --- .../team/prezel/feature/login/impl/terms/TermsScreen.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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,