From 443c1c5350008899bf4149694c300e50901c21d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AA=85=ED=9B=88?= Date: Tue, 13 Aug 2024 23:06:02 +0900 Subject: [PATCH 1/5] :recycle: :: Use SavedStateHandle To AuthViewModel --- .../com/bitgoeul/login/viewmodel/AuthViewModel.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/feature/login/src/main/java/com/bitgoeul/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/bitgoeul/login/viewmodel/AuthViewModel.kt index aa854350..71d347f8 100644 --- a/feature/login/src/main/java/com/bitgoeul/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/bitgoeul/login/viewmodel/AuthViewModel.kt @@ -1,5 +1,6 @@ package com.bitgoeul.login.viewmodel +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.msg.common.errorhandling.errorHandling @@ -19,13 +20,22 @@ import javax.inject.Inject class AuthViewModel @Inject constructor( private val loginUseCase: LoginUseCase, private val saveTokenUseCase: SaveTokenUseCase, + private val savedStateHandle: SavedStateHandle ) : ViewModel() { + companion object { + private const val EMAIL = "email" + private const val PASSWORD = "password" + } private val _saveTokenResponse = MutableStateFlow>(Event.Loading) val saveTokenRequest = _saveTokenResponse.asStateFlow() private val _loginResponse = MutableStateFlow>(Event.Loading) val loginResponse = _loginResponse.asStateFlow() + internal var email = savedStateHandle.getStateFlow(key = EMAIL, initialValue = "") + + internal var password = savedStateHandle.getStateFlow(key = PASSWORD, initialValue = "") + internal fun login( email: String, password: String @@ -58,4 +68,8 @@ class AuthViewModel @Inject constructor( _saveTokenResponse.value = it.errorHandling() } } + + internal fun onEmailChange(value: String) { savedStateHandle[EMAIL] = value } + + internal fun onPasswordChange(value: String) { savedStateHandle[PASSWORD] = value } } From 8f667ad9a1c2c5c4ea1d1e12e4344b9c1ba8ef90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AA=85=ED=9B=88?= Date: Tue, 13 Aug 2024 23:11:42 +0900 Subject: [PATCH 2/5] :recycle: :: Refactor LoginScreen / Apply ViewModel Changed --- .../java/com/bitgoeul/login/LoginScreen.kt | 90 ++++++++++--------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt index 05cf473d..e4dbe946 100644 --- a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt @@ -14,9 +14,11 @@ import androidx.compose.foundation.layout.width import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusManager @@ -28,6 +30,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.bitgoeul.login.viewmodel.AuthViewModel import com.msg.common.event.Event import com.msg.design_system.R @@ -50,10 +53,17 @@ internal fun LoginRoute( onLoginClicked: () -> Unit, viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), ) { + val emailState by viewModel.email.collectAsStateWithLifecycle() + val passwordState by viewModel.password.collectAsStateWithLifecycle() + val coroutineScope = rememberCoroutineScope() val context = LocalContext.current LoginScreen( + email = emailState, + password = passwordState, + onEmailChange = viewModel::onEmailChange, + onPasswordChange = viewModel::onPasswordChange, onSignUpClicked = onSignUpClicked, onFindPasswordClicked = onFindPasswordClicked, onLoginClicked = { email, password -> @@ -98,23 +108,26 @@ private suspend fun getLoginData( @Composable internal fun LoginScreen( + modifier: Modifier = Modifier, + email: String, + password: String, + onEmailChange: (String) -> Unit, + onPasswordChange: (String) -> Unit, focusManager: FocusManager = LocalFocusManager.current, onSignUpClicked: () -> Unit, onLoginClicked: (String, String) -> Unit, onFindPasswordClicked: () -> Unit, ) { LockScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) - val isEmailErrorStatus = remember { mutableStateOf(false) } - val isPasswordErrorStatus = remember { mutableStateOf(false) } - val isErrorTextShow = remember { mutableStateOf(false) } + val (isEmailErrorStatus, setIsEmailErrorStatus) = rememberSaveable { mutableStateOf(false) } + val isPasswordErrorStatus by rememberSaveable{ mutableStateOf(false) } + val isErrorTextShow by rememberSaveable { mutableStateOf(false) } var isTextStatus = "" - val emailState = remember { mutableStateOf("") } - val passwordState = remember { mutableStateOf("") } BitgoeulAndroidTheme { color, type -> Surface { Column( - modifier = Modifier + modifier = modifier .fillMaxSize() .pointerInput(Unit) { detectTapGestures { @@ -123,14 +136,14 @@ internal fun LoginScreen( }, horizontalAlignment = Alignment.CenterHorizontally ) { - Spacer(modifier = Modifier.height(48.dp)) + Spacer(modifier = modifier.height(48.dp)) Row( - modifier = Modifier.fillMaxWidth() + modifier = modifier.fillMaxWidth() ) { - Spacer(modifier = Modifier.width(28.dp)) + Spacer(modifier = modifier.width(28.dp)) Text( - modifier = Modifier, + modifier = modifier, text = stringResource(id = R.string.project_name), color = color.BLACK, style = type.titleLarge, @@ -138,27 +151,25 @@ internal fun LoginScreen( ) } - Spacer(modifier = Modifier.height(80.dp)) + Spacer(modifier = modifier.height(80.dp)) Row( - modifier = Modifier + modifier = modifier .fillMaxWidth() .padding(horizontal = 28.dp), ) { DefaultTextField( - modifier = Modifier + modifier = modifier .fillMaxWidth() .height(54.dp), placeholder = stringResource(id = R.string.email), errorText = stringResource(id = R.string.error_text_email), onValueChange = { isTextStatus = it - emailState.value = it - }, - isError = isEmailErrorStatus.value, - onButtonClicked = { - isEmailErrorStatus.value = isTextStatus.isNullOrBlank() + onEmailChange(it) }, + isError = isEmailErrorStatus, + onButtonClicked = { setIsEmailErrorStatus(isTextStatus.isNullOrBlank()) }, isLinked = false, isDisabled = false, isReadOnly = false, @@ -166,66 +177,61 @@ internal fun LoginScreen( ) } - if (isErrorTextShow.value) { - Spacer(modifier = Modifier.height(0.dp)) + if (isErrorTextShow) { + Spacer(modifier = modifier.height(0.dp)) } else { - Spacer(modifier = Modifier.height(16.dp)) + Spacer(modifier = modifier.height(16.dp)) } Row( - modifier = Modifier + modifier = modifier .fillMaxWidth() .padding(horizontal = 28.dp), ) { PasswordTextField( - modifier = Modifier + modifier = modifier .fillMaxWidth() .height(54.dp), placeholder = stringResource(id = R.string.password), errorText = stringResource(id = R.string.wrong_password), - onValueChange = { - passwordState.value = it - }, - onLinkClicked = { - onFindPasswordClicked() - }, - isError = isPasswordErrorStatus.value, + onValueChange = onPasswordChange, + onLinkClicked = { onFindPasswordClicked() }, + isError = isPasswordErrorStatus, isLinked = true, linkText = stringResource(id = R.string.find_password), isDisabled = false, ) } - Spacer(modifier = Modifier.height(180.dp)) + Spacer(modifier = modifier.height(180.dp)) Row( - modifier = Modifier + modifier = modifier .fillMaxWidth() .padding(horizontal = 28.dp), ) { BitgoeulButton( - text = stringResource(id = R.string.login), - modifier = Modifier + modifier = modifier .fillMaxWidth() .height(52.dp), - state = if (emailState.value.checkEmailRegex() && passwordState.value.checkPasswordRegex()) ButtonState.Enable else ButtonState.Disable, + text = stringResource(id = R.string.login), + state = if (email.checkEmailRegex() && password.checkPasswordRegex()) ButtonState.Enable else ButtonState.Disable, onClicked = { - onLoginClicked(emailState.value, passwordState.value) + onLoginClicked(email, password) } ) } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = modifier.height(8.dp)) Text( - modifier = Modifier, text = "또는", style = type.labelMedium, color = color.G1, fontSize = 14.sp, ) - Spacer(modifier = Modifier.height(2.dp)) + Spacer(modifier = modifier.height(2.dp)) LinkText( text = stringResource(id = R.string.sign_up) @@ -244,6 +250,10 @@ private fun LoginScreenPre() { onSignUpClicked = { /*TODO*/ }, onLoginClicked = { _, _ -> }, onFindPasswordClicked = { /*TODO*/ }, - focusManager = LocalFocusManager.current + focusManager = LocalFocusManager.current, + email = "", + password = "", + onEmailChange = {}, + onPasswordChange = {} ) } \ No newline at end of file From db2be52a483359e0ab0b780cbe2a6aa55d5fc4b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AA=85=ED=9B=88?= Date: Tue, 13 Aug 2024 23:13:54 +0900 Subject: [PATCH 3/5] :recycle: :: isNullBlank() -> isBlank() --- feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt index e4dbe946..4f63d939 100644 --- a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt @@ -169,7 +169,7 @@ internal fun LoginScreen( onEmailChange(it) }, isError = isEmailErrorStatus, - onButtonClicked = { setIsEmailErrorStatus(isTextStatus.isNullOrBlank()) }, + onButtonClicked = { setIsEmailErrorStatus(isTextStatus.isBlank()) }, isLinked = false, isDisabled = false, isReadOnly = false, From 1e0c2a891fbc2add12bf3610663d04b75956ca29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AA=85=ED=9B=88?= Date: Tue, 13 Aug 2024 23:16:31 +0900 Subject: [PATCH 4/5] :fire: :: Fire isTextStatus --- .../login/src/main/java/com/bitgoeul/login/LoginScreen.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt index 4f63d939..6d7cf147 100644 --- a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt @@ -122,7 +122,6 @@ internal fun LoginScreen( val (isEmailErrorStatus, setIsEmailErrorStatus) = rememberSaveable { mutableStateOf(false) } val isPasswordErrorStatus by rememberSaveable{ mutableStateOf(false) } val isErrorTextShow by rememberSaveable { mutableStateOf(false) } - var isTextStatus = "" BitgoeulAndroidTheme { color, type -> Surface { @@ -164,12 +163,9 @@ internal fun LoginScreen( .height(54.dp), placeholder = stringResource(id = R.string.email), errorText = stringResource(id = R.string.error_text_email), - onValueChange = { - isTextStatus = it - onEmailChange(it) - }, + onValueChange = onEmailChange, isError = isEmailErrorStatus, - onButtonClicked = { setIsEmailErrorStatus(isTextStatus.isBlank()) }, + onButtonClicked = { setIsEmailErrorStatus(email.isBlank()) }, isLinked = false, isDisabled = false, isReadOnly = false, From 3bdd285318f299b87ac5a49be397fa78d1e64625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AA=85=ED=9B=88?= Date: Wed, 14 Aug 2024 08:46:59 +0900 Subject: [PATCH 5/5] :recycle: :: Apply Reviewer(Simplify Code) --- feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt index 6d7cf147..61a59169 100644 --- a/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt @@ -191,7 +191,7 @@ internal fun LoginScreen( placeholder = stringResource(id = R.string.password), errorText = stringResource(id = R.string.wrong_password), onValueChange = onPasswordChange, - onLinkClicked = { onFindPasswordClicked() }, + onLinkClicked = onFindPasswordClicked, isError = isPasswordErrorStatus, isLinked = true, linkText = stringResource(id = R.string.find_password),