From 87f114ed23a7a34e1c168ed137431777ddfb14e9 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Mon, 13 May 2024 12:32:27 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EC=82=AC=EC=9E=A5=EB=8B=98=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessMainActivity.kt | 6 +- .../changepassword/ChangePasswordScreen.kt | 3 +- .../ChangePasswordSideEffect.kt | 2 +- .../changepassword/ChangePasswordState.kt | 2 +- .../changepassword/ChangePasswordViewModel.kt | 11 +- .../FinishChangePasswordScreen.kt | 2 +- .../navigator/ChangePasswordRoute.kt | 2 +- .../navigator/FeatureChangePassword.kt | 9 +- .../PasswordAuthenticationScreen.kt | 2 +- .../PasswordAuthenticationSideEffect.kt | 5 +- .../PasswordAuthenticationState.kt | 7 +- .../PasswordAuthenticationViewModel.kt | 8 +- .../business/feature/signin/SignInScreen.kt | 299 ++++++++++++++++++ .../feature/signin/SignInSideEffect.kt | 20 ++ .../business/feature/signin/SignInState.kt | 7 + .../feature/signin/SignInViewModel.kt | 79 +++++ .../feature/signin/navigator/RouteSignIn.kt | 46 +++ .../signin/navigator/SignInNavigator.kt | 7 + business/src/main/res/values/strings.xml | 1 + core/src/main/res/values/strings.xml | 43 +++ .../koin/data/error/UserErrorHandlerImpl.kt | 2 + data/src/main/res/values/strings.xml | 1 + .../usecase/business/SendAuthCodeUseCase.kt | 1 - .../koin/ui/login/viewmodel/LoginViewModel.kt | 1 - 24 files changed, 528 insertions(+), 38 deletions(-) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/changepassword/ChangePasswordScreen.kt (98%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/changepassword/ChangePasswordSideEffect.kt (86%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/changepassword/ChangePasswordState.kt (87%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/changepassword/ChangePasswordViewModel.kt (92%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/finishchangepassword/FinishChangePasswordScreen.kt (98%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/navigator/ChangePasswordRoute.kt (60%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/navigator/FeatureChangePassword.kt (87%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/passwordauthentication/PasswordAuthenticationScreen.kt (99%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/passwordauthentication/PasswordAuthenticationSideEffect.kt (62%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/passwordauthentication/PasswordAuthenticationState.kt (58%) rename business/src/main/java/in/koreatech/business/{feature_changepassword => feature/changepassword}/passwordauthentication/PasswordAuthenticationViewModel.kt (95%) create mode 100644 business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/signin/navigator/SignInNavigator.kt diff --git a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt index ce32c3d3d..44b2ba66c 100644 --- a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt +++ b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt @@ -12,8 +12,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import dagger.hilt.android.AndroidEntryPoint -import `in`.koreatech.business.feature.signup.navigator.SignupNavigator -import `in`.koreatech.business.feature_changepassword.navigator.ChangePassword +import `in`.koreatech.business.feature.signin.navigator.SignInNavigator import `in`.koreatech.business.ui.theme.KOIN_ANDROIDTheme @AndroidEntryPoint @@ -27,8 +26,9 @@ class BusinessMainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { - ChangePassword() + //ChangePassword() //SignupNavigator(modifier = Modifier.fillMaxSize()) + SignInNavigator() } } } diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordScreen.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordScreen.kt similarity index 98% rename from business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordScreen.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordScreen.kt index 7b14fe386..924239549 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordScreen.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.changepassword +package `in`.koreatech.business.feature.changepassword.changepassword import androidx.compose.foundation.Image @@ -36,7 +36,6 @@ import `in`.koreatech.business.ui.theme.Blue1 import `in`.koreatech.business.ui.theme.ColorError import `in`.koreatech.business.ui.theme.ColorPrimary import `in`.koreatech.business.ui.theme.Gray5 -import `in`.koreatech.business.ui.theme.Red2 import `in`.koreatech.koin.core.toast.ToastUtil import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordSideEffect.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordSideEffect.kt similarity index 86% rename from business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordSideEffect.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordSideEffect.kt index d56510786..51db96c28 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordSideEffect.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordSideEffect.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.changepassword +package `in`.koreatech.business.feature.changepassword.changepassword sealed class ChangePasswordSideEffect { object ToastNullEmail: ChangePasswordSideEffect() diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordState.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordState.kt similarity index 87% rename from business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordState.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordState.kt index 0970c5e1f..9b36de472 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordState.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordState.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.changepassword +package `in`.koreatech.business.feature.changepassword.changepassword import android.os.Parcelable import kotlinx.parcelize.Parcelize diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordViewModel.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordViewModel.kt similarity index 92% rename from business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordViewModel.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordViewModel.kt index 3a5b26b73..527a4bc41 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/changepassword/ChangePasswordViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordViewModel.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.changepassword +package `in`.koreatech.business.feature.changepassword.changepassword import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel @@ -6,9 +6,6 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import `in`.koreatech.koin.domain.state.business.changepw.ChangePasswordExceptionState import `in`.koreatech.koin.domain.usecase.business.OwnerChangePasswordUseCase -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost @@ -19,7 +16,7 @@ import org.orbitmvi.orbit.viewmodel.container import javax.inject.Inject @HiltViewModel -class ChangePasswordViewModel @Inject constructor( +class ChangePasswordViewModel @Inject constructor( private val ownerChangePasswordUseCase: OwnerChangePasswordUseCase, savedStateHandle: SavedStateHandle ) : ViewModel(), ContainerHost { @@ -36,13 +33,13 @@ class ChangePasswordViewModel @Inject constructor( } } - fun fillAllPasswords() = intent { + private fun fillAllPasswords() = intent { reduce{ state.copy(fillAllPasswords = (state.password.isNotBlank() && state.passwordChecked.isNotBlank())) } } - fun coincidePasswordReset() = intent { + private fun coincidePasswordReset() = intent { reduce{ state.copy(notCoincidePW = false) } diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/finishchangepassword/FinishChangePasswordScreen.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/finishchangepassword/FinishChangePasswordScreen.kt similarity index 98% rename from business/src/main/java/in/koreatech/business/feature_changepassword/finishchangepassword/FinishChangePasswordScreen.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/finishchangepassword/FinishChangePasswordScreen.kt index 3225b0845..fee83c0af 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/finishchangepassword/FinishChangePasswordScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/finishchangepassword/FinishChangePasswordScreen.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.finishchangepassword +package `in`.koreatech.business.feature.changepassword.finishchangepassword import androidx.compose.foundation.Image import androidx.compose.foundation.clickable diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/navigator/ChangePasswordRoute.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/navigator/ChangePasswordRoute.kt similarity index 60% rename from business/src/main/java/in/koreatech/business/feature_changepassword/navigator/ChangePasswordRoute.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/navigator/ChangePasswordRoute.kt index df5550317..272440ff6 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/navigator/ChangePasswordRoute.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/navigator/ChangePasswordRoute.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.navigator +package `in`.koreatech.business.feature.changepassword.navigator enum class ChangePasswordRoute() { Login, diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/navigator/FeatureChangePassword.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/navigator/FeatureChangePassword.kt similarity index 87% rename from business/src/main/java/in/koreatech/business/feature_changepassword/navigator/FeatureChangePassword.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/navigator/FeatureChangePassword.kt index c756dd287..6bfcb10a0 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/navigator/FeatureChangePassword.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/navigator/FeatureChangePassword.kt @@ -1,6 +1,5 @@ -package `in`.koreatech.business.feature_changepassword.navigator +package `in`.koreatech.business.feature.changepassword.navigator -import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.navigation.NavController @@ -10,9 +9,9 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument -import `in`.koreatech.business.feature_changepassword.changepassword.ChangePasswordScreenImpl -import `in`.koreatech.business.feature_changepassword.finishchangepassword.FinishChangePasswordScreen -import `in`.koreatech.business.feature_changepassword.passwordauthentication.PasswordAuthenticationScreenImpl +import `in`.koreatech.business.feature.changepassword.changepassword.ChangePasswordScreenImpl +import `in`.koreatech.business.feature.changepassword.finishchangepassword.FinishChangePasswordScreen +import `in`.koreatech.business.feature.changepassword.passwordauthentication.PasswordAuthenticationScreenImpl @Composable diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationScreen.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationScreen.kt similarity index 99% rename from business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationScreen.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationScreen.kt index 869ed79b7..e79380053 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationScreen.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.passwordauthentication +package `in`.koreatech.business.feature.changepassword.passwordauthentication import androidx.compose.foundation.Image import androidx.compose.foundation.clickable diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationSideEffect.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationSideEffect.kt similarity index 62% rename from business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationSideEffect.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationSideEffect.kt index 59a21fe3b..6390344cc 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationSideEffect.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationSideEffect.kt @@ -1,7 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.passwordauthentication - -import `in`.koreatech.koin.domain.state.business.changepw.ChangePasswordContinuationState -import `in`.koreatech.koin.domain.state.business.changepw.ChangePasswordExceptionState +package `in`.koreatech.business.feature.changepassword.passwordauthentication sealed class PasswordAuthenticationSideEffect { data class GotoChangePasswordScreen(val email: String): PasswordAuthenticationSideEffect() diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationState.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationState.kt similarity index 58% rename from business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationState.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationState.kt index 3bcbd9ab7..332fbf933 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationState.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationState.kt @@ -1,9 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.passwordauthentication - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +package `in`.koreatech.business.feature.changepassword.passwordauthentication data class PasswordAuthenticationState ( val authenticationBtnIsClicked: Boolean = false, diff --git a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationViewModel.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationViewModel.kt similarity index 95% rename from business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationViewModel.kt rename to business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationViewModel.kt index a491c28c5..965e5d54f 100644 --- a/business/src/main/java/in/koreatech/business/feature_changepassword/passwordauthentication/PasswordAuthenticationViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/passwordauthentication/PasswordAuthenticationViewModel.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.business.feature_changepassword.passwordauthentication +package `in`.koreatech.business.feature.changepassword.passwordauthentication import androidx.lifecycle.ViewModel @@ -9,8 +9,6 @@ import `in`.koreatech.koin.domain.state.business.changepw.ChangePasswordExceptio import `in`.koreatech.koin.domain.usecase.business.SendAuthCodeUseCase import `in`.koreatech.koin.domain.usecase.owner.OwnerAuthenticateCode import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.cancellable -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch import org.orbitmvi.orbit.ContainerHost @@ -25,7 +23,9 @@ class PasswordAuthenticationViewModel @Inject constructor( private val sendAuthCodeUseCase: SendAuthCodeUseCase, private val ownerAuthenticateCode: OwnerAuthenticateCode ): ViewModel() , ContainerHost { - override val container = container(PasswordAuthenticationState()) + override val container = container( + PasswordAuthenticationState() + ) private val sendAuthCodeFlow = MutableSharedFlow() private val authenticateCodeFlow = MutableSharedFlow>() diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt new file mode 100644 index 000000000..98cfcdb4c --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt @@ -0,0 +1,299 @@ +package `in`.koreatech.business.feature.signin + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.PasswordVisualTransformation +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 `in`.koreatech.koin.core.R +import `in`.koreatech.business.ui.theme.Blue1 +import `in`.koreatech.business.ui.theme.ColorAccent +import `in`.koreatech.business.ui.theme.ColorPrimary +import `in`.koreatech.business.ui.theme.ColorSecondaryText +import `in`.koreatech.koin.core.toast.ToastUtil +import org.orbitmvi.orbit.compose.collectAsState +import org.orbitmvi.orbit.compose.collectSideEffect + + +@Composable +fun SignInScreenImpl( + modifier: Modifier = Modifier, + navigateToSignUp: () -> Unit, + navigateToFindPassword: () -> Unit, + navigateToMain: () -> Unit, + viewModel: SignInViewModel = hiltViewModel() +) { + val state = viewModel.collectAsState().value + + SignInScreen( + modifier = modifier, + id = state.id, + password = state.password, + onIdChange = { + id -> viewModel.insertId(id) + }, + onPasswordChange = { + password -> viewModel.insertPassword(password) + }, + onSignInClick = { + if(state.isFilledIdEmailField) viewModel.login(state.id.trim(), state.password.trim()) + else viewModel.toastNullMessage() + }, + onSignUpClick = {viewModel.navigateToSignUp()}, + onFindPasswordClick = {viewModel.navigateToFindPassword()} + ) + + HandleSideEffects(viewModel, navigateToSignUp, navigateToFindPassword, navigateToMain) +} +@Composable +fun SignInScreen ( + modifier: Modifier, + id: String, + password: String, + onIdChange: (String) -> Unit, + onPasswordChange: (String) -> Unit, + onSignInClick: () -> Unit, + onSignUpClick:() ->Unit, + onFindPasswordClick:() -> Unit + ){ + Column(modifier = modifier.fillMaxSize()) { + Row( + modifier = modifier + .padding(start = 32.dp, top = 88.dp, end = 32.dp, bottom = 80.dp) + .fillMaxWidth(), + ) { + Image( + painter = painterResource(id = R.drawable.logo_color_horizontal_300x168), + contentDescription = "Koin Logo", + modifier = modifier + .width(107.dp) + .height(60.dp) + ) + Text( + text = stringResource(id = R.string.for_business), + fontSize = 20.sp, + modifier = modifier + .padding(start = 8.dp, top = 30.dp) + ) + } + + BasicTextField( + value = id, + onValueChange = onIdChange, + maxLines = 1, + textStyle = TextStyle(fontSize = 15.sp), + decorationBox = { innerTextField -> + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth() + ) { + Box( + contentAlignment = Alignment.CenterStart, + modifier = Modifier + .fillMaxWidth() + ) { + if (id.isEmpty()) { + Text( + stringResource(R.string.id), + color = Blue1, + fontSize = 15.sp + ) + } + innerTextField() + } + Divider( + color = if (id.isEmpty()) Blue1 else Color.Black, + thickness = 1.dp, + modifier = Modifier.fillMaxWidth() + ) + } + }, + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 32.dp) + .padding(bottom = 28.dp) + ) + + BasicTextField( + value = password, + onValueChange = onPasswordChange, + maxLines = 1, + visualTransformation = PasswordVisualTransformation(), + textStyle = TextStyle(fontSize = 15.sp), + decorationBox = { innerTextField -> + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth() + ) { + Box( + contentAlignment = Alignment.CenterStart, + modifier = Modifier + .fillMaxWidth() + ) { + if (password.isEmpty()) { + Text( + stringResource(R.string.password), + color = Blue1, + fontSize = 15.sp + ) + } + innerTextField() + } + Divider( + color = if (password.isEmpty()) Blue1 else Color.Black, + thickness = 1.dp, + modifier = Modifier.fillMaxWidth() + ) + } + }, + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 32.dp) + .padding(bottom = 40.dp) + ) + + Button( + onClick = onSignInClick, + shape = RectangleShape, + colors = ButtonDefaults.buttonColors(ColorAccent), + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 32.dp) + .padding(bottom = 16.dp) + .height(44.dp) + + ) { + Text( + stringResource(R.string.navigation_item_login), + color = Color.White, + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + + Button( + onClick = onSignUpClick, + shape = RectangleShape, + colors = ButtonDefaults.buttonColors(ColorPrimary), + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 32.dp) + .padding(top = 16.dp, bottom = 24.dp) + .height(44.dp) + + ) { + Text( + stringResource(R.string.sign_up), + color = Color.White, + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + + Button( + onClick = onFindPasswordClick, + colors = ButtonDefaults.buttonColors(Color.White), + shape = RectangleShape, + modifier = modifier + .padding(horizontal = 127.dp) + .padding(top = 24.dp) + .fillMaxWidth() + + ) { + Row( + modifier = modifier.fillMaxWidth() + ){ + Image( + painter = painterResource(id = R.drawable.ic_password), + contentDescription = "password_icon", + modifier = modifier + .height(20.dp) + .width(20.dp) + ) + + Text( + stringResource(R.string.password_find), + color = ColorSecondaryText, + fontSize = 13.sp, + ) + } + } + + Text( + text = stringResource(R.string.copy_right), + modifier = modifier + .padding(top = 102.dp, bottom = 24.dp) + .padding(horizontal = 64.dp) + ) + + } +} + +@Composable +private fun HandleSideEffects( + viewModel: SignInViewModel, + navigateToSignUp: () -> Unit, + navigateToFindPassword: () -> Unit, + navigateToMain: () -> Unit) +{ + val context = LocalContext.current + viewModel.collectSideEffect { sideEffect -> + when (sideEffect) { + is SignInSideEffect.NavigateToMain -> navigateToMain() + is SignInSideEffect.NavigateToFindPassword -> navigateToFindPassword() + is SignInSideEffect.NavigateToSignUp -> navigateToSignUp() + is SignInSideEffect.ShowMessage -> ToastUtil.getInstance().makeShort(sideEffect.message) + is SignInSideEffect.ShowNullMessage -> { + val message = when (sideEffect.type) { + ErrorType.NullEmailOrPassword -> context.getString(R.string.login_required_field_not_filled) + } + ToastUtil.getInstance().makeShort(message) + } + } + } +} + +@Preview +@Composable +fun PreViewSignInScreen(){ + SignInScreen( + modifier = Modifier, + id = "", + password = "", + onIdChange = {}, + onPasswordChange = {}, + onSignInClick = {}, + onSignUpClick = {}, + onFindPasswordClick = {} + ) +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt new file mode 100644 index 000000000..a2e73087c --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt @@ -0,0 +1,20 @@ +package `in`.koreatech.business.feature.signin + +import `in`.koreatech.business.feature.changepassword.passwordauthentication.PasswordAuthenticationSideEffect + +sealed class SignInSideEffect { + + object NavigateToSignUp: SignInSideEffect() + + object NavigateToFindPassword: SignInSideEffect() + + object NavigateToMain: SignInSideEffect() + + data class ShowNullMessage(val type: ErrorType): SignInSideEffect() + + data class ShowMessage(val message: String): SignInSideEffect() +} + +enum class ErrorType { + NullEmailOrPassword +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt new file mode 100644 index 000000000..7b07fd915 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt @@ -0,0 +1,7 @@ +package `in`.koreatech.business.feature.signin + +data class SignInState ( + val id: String = "", + val password: String = "", + val isFilledIdEmailField: Boolean = false +) \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt new file mode 100644 index 000000000..960890cc3 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt @@ -0,0 +1,79 @@ +package `in`.koreatech.business.feature.signin + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.koreatech.koin.domain.usecase.user.UserLoginUseCase +import `in`.koreatech.koin.domain.util.onFailure +import `in`.koreatech.koin.domain.util.onSuccess +import kotlinx.coroutines.launch +import org.orbitmvi.orbit.ContainerHost +import org.orbitmvi.orbit.syntax.simple.intent +import org.orbitmvi.orbit.syntax.simple.postSideEffect +import org.orbitmvi.orbit.syntax.simple.reduce +import org.orbitmvi.orbit.viewmodel.container +import javax.inject.Inject + +@HiltViewModel +class SignInViewModel @Inject constructor( + private val userLoginUseCase: UserLoginUseCase +) : ViewModel(), ContainerHost { + override val container = container( + SignInState() + ) + + private fun fillAllPasswords() = intent { + reduce{ + state.copy(isFilledIdEmailField = (state.id.isNotBlank() && state.password.isNotBlank())) + } + } + + fun insertId(id: String) = intent{ + reduce { state.copy(id = id) } + fillAllPasswords() + } + + fun insertPassword(password: String) = intent{ + reduce { state.copy(password = password) } + fillAllPasswords() + } + + fun toastNullMessage() = intent { + postSideEffect(SignInSideEffect.ShowNullMessage(ErrorType.NullEmailOrPassword)) + } + + fun navigateToSignUp() = intent { + postSideEffect(SignInSideEffect.NavigateToSignUp) + } + + fun navigateToFindPassword() = intent { + postSideEffect(SignInSideEffect.NavigateToFindPassword) + } + + private fun navigateToMain() = intent { + postSideEffect(SignInSideEffect.NavigateToMain) + } + + + + fun login( + id: String, + password: String, + ){ + viewModelScope.launch { + userLoginUseCase( + email = id, + password = password + ) .onSuccess { + navigateToMain() + } + .onFailure { + toastErrorMessage(it.message) + } + } + } + + private fun toastErrorMessage(message: String) = intent { + postSideEffect(SignInSideEffect.ShowMessage(message)) + } +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt b/business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt new file mode 100644 index 000000000..bf4e1b35a --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt @@ -0,0 +1,46 @@ +package `in`.koreatech.business.feature.signin.navigator + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import `in`.koreatech.business.feature.changepassword.navigator.ChangePassword +import `in`.koreatech.business.feature.signin.SignInScreenImpl +import `in`.koreatech.business.feature.signup.navigator.SignupNavigator + +@Composable +fun SignInNavigator( + modifier: Modifier = Modifier, + navController: NavHostController = rememberNavController() +) { + NavHost( + navController = navController, + startDestination = SignInNavigator.SignIn.name, + modifier = modifier + ){ + composable(route = SignInNavigator.SignIn.name){ + SignInScreenImpl( + navigateToMain = {}, + navigateToSignUp = { + navController.navigate(SignInNavigator.SignUp.name) + }, + navigateToFindPassword = { + navController.navigate(SignInNavigator.FindPassword.name) + } + ) + } + + composable(route = SignInNavigator.SignUp.name){ + SignupNavigator( + modifier = Modifier.fillMaxSize() + ) + } + + composable(route = SignInNavigator.FindPassword.name){ + ChangePassword() + } + } +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/navigator/SignInNavigator.kt b/business/src/main/java/in/koreatech/business/feature/signin/navigator/SignInNavigator.kt new file mode 100644 index 000000000..448207247 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/signin/navigator/SignInNavigator.kt @@ -0,0 +1,7 @@ +package `in`.koreatech.business.feature.signin.navigator + +enum class SignInNavigator() { + SignIn, + SignUp, + FindPassword +} \ No newline at end of file diff --git a/business/src/main/res/values/strings.xml b/business/src/main/res/values/strings.xml index be24bb85c..602c47a3b 100644 --- a/business/src/main/res/values/strings.xml +++ b/business/src/main/res/values/strings.xml @@ -7,6 +7,7 @@ backArrow 오류가 발생하였습니다. 잠시뒤에 다시 시도해 주세요 + 이메일로 발송된 인증번호 6자리를 입력해 주세요. 인증번호가 일치하지 않습니다. diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index e97e247f1..a8fe2f7ce 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -77,4 +77,47 @@ 님, 안녕하세요! 내 정보 햄버거 + + + + Copyright @ BCSD Lab All rights reserved. + 회원가입 + 사장님용\n회원가입 + 로그인 화면 바로가기 + backArrow + 오류가 발생하였습니다. 잠시뒤에 다시 시도해 주세요 + For Business + 아이디와 비밀번호를 입력해주세요 + + + + 이메일로 발송된 인증번호 6자리를 입력해 주세요. + 인증번호가 일치하지 않습니다. + 인증번호를 입력해주세요 + 인증번호발송 + 재발송 + 인증번호 입력 + + + 아이디 + 이메일 입력 + 이메일 인증하기 + 이메일 주소를 입력해주세요 + 이메일 주소가 올바르지 않습니다. + + + 비밀번호 + * 특수문자 포함 영어와 숫자 조합 6~18 자리 + 비밀번호를 입력해 주세요. + 확인 비밀번호를 입력해 주세요. + 비밀번호가 일치하지 않습니다. + 비밀번호가 변경되었습니다.\n새로운 비밀번호로 로그인 부탁드립니다. + 비밀번호 변경 완료 + 비밀번호 확인 + 새 비밀번호 + 비밀번호 변경하기 + 비밀번호 찾기 + 비밀번호 변경 + 비밀번호가 일치하지 않습니다. + diff --git a/data/src/main/java/in/koreatech/koin/data/error/UserErrorHandlerImpl.kt b/data/src/main/java/in/koreatech/koin/data/error/UserErrorHandlerImpl.kt index a4c6f9084..1a93dfc93 100644 --- a/data/src/main/java/in/koreatech/koin/data/error/UserErrorHandlerImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/error/UserErrorHandlerImpl.kt @@ -23,6 +23,8 @@ class UserErrorHandlerImpl @Inject constructor( is HttpException -> { when(it.code()) { 401 -> ErrorHandler(context.getString(R.string.error_login_incorrect)) + 404 -> ErrorHandler(context.getString(R.string.error_forgotpassword_no_user)) + 400 -> ErrorHandler(context.getString(R.string.error_wrong_password)) else -> ErrorHandler(context.getString(R.string.error_network)) } } diff --git a/data/src/main/res/values/strings.xml b/data/src/main/res/values/strings.xml index d59d863ed..3ce19ca5d 100644 --- a/data/src/main/res/values/strings.xml +++ b/data/src/main/res/values/strings.xml @@ -4,6 +4,7 @@ 서버 오류가 발생했습니다. 네트워크 연결을 확인해 주세요. 알 수 없는 오류가 발생했습니다. + 비밀번호가 틀렸습니다. 가입되지 않은 아이디입니다. diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SendAuthCodeUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SendAuthCodeUseCase.kt index 3620a8629..c8f024fe4 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SendAuthCodeUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SendAuthCodeUseCase.kt @@ -17,7 +17,6 @@ class SendAuthCodeUseCase @Inject constructor( when { email == "" -> Result.failure(ChangePasswordExceptionState.ToastNullEmail) email.isOwnerNotEmailValid() -> Result.failure(ChangePasswordExceptionState.ToastIsNotEmail) - else -> ownerChangePasswordRepository.requestEmailVerification( email = email ).map { ChangePasswordContinuationState.SendAuthCode} diff --git a/koin/src/main/java/in/koreatech/koin/ui/login/viewmodel/LoginViewModel.kt b/koin/src/main/java/in/koreatech/koin/ui/login/viewmodel/LoginViewModel.kt index 3513306c6..05c52fedc 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/login/viewmodel/LoginViewModel.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/login/viewmodel/LoginViewModel.kt @@ -8,7 +8,6 @@ import `in`.koreatech.koin.domain.usecase.user.UserLoginUseCase import `in`.koreatech.koin.domain.util.onFailure import `in`.koreatech.koin.domain.util.onSuccess import `in`.koreatech.koin.ui.login.LoginState -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow From 249ba410a6b3442ec60243d1b2c4176014520c7d Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Wed, 15 May 2024 14:02:18 +0900 Subject: [PATCH 2/6] =?UTF-8?q?1=EC=B0=A8=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessMainActivity.kt | 33 +++++-- .../business/feature/signin/SignInScreen.kt | 85 +++++++++++++------ .../business/feature/signin/SignInState.kt | 2 +- .../feature/signin/SignInViewModel.kt | 56 ++++++------ business/src/main/res/values/strings.xml | 1 + 5 files changed, 114 insertions(+), 63 deletions(-) diff --git a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt index 44b2ba66c..bc981d416 100644 --- a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt +++ b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt @@ -4,12 +4,17 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import dagger.hilt.android.AndroidEntryPoint import `in`.koreatech.business.feature.signin.navigator.SignInNavigator @@ -21,14 +26,26 @@ class BusinessMainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { KOIN_ANDROIDTheme { - // A surface container using the 'background' color from the theme - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colors.background - ) { - //ChangePassword() - //SignupNavigator(modifier = Modifier.fillMaxSize()) - SignInNavigator() + Scaffold( + topBar = { + TopAppBar( + title = { + Text( + text = stringResource(R.string.koin_for_business), + style = MaterialTheme.typography.h3, + fontWeight = FontWeight.Bold + ) + } + ) + } + ) + { innerPadding -> + Surface( + modifier = Modifier.padding(innerPadding), + color = MaterialTheme.colors.background + ) { + SignInNavigator() + } } } } diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt index 98cfcdb4c..db8643eff 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt @@ -1,5 +1,6 @@ package `in`.koreatech.business.feature.signin +import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -15,10 +16,6 @@ import androidx.compose.material.ButtonDefaults import androidx.compose.material.Divider import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -64,8 +61,7 @@ fun SignInScreenImpl( password -> viewModel.insertPassword(password) }, onSignInClick = { - if(state.isFilledIdEmailField) viewModel.login(state.id.trim(), state.password.trim()) - else viewModel.toastNullMessage() + viewModel.login(state.id.trim(), state.password.trim()) }, onSignUpClick = {viewModel.navigateToSignUp()}, onFindPasswordClick = {viewModel.navigateToFindPassword()} @@ -86,21 +82,21 @@ fun SignInScreen ( ){ Column(modifier = modifier.fillMaxSize()) { Row( - modifier = modifier + modifier = Modifier .padding(start = 32.dp, top = 88.dp, end = 32.dp, bottom = 80.dp) .fillMaxWidth(), ) { Image( painter = painterResource(id = R.drawable.logo_color_horizontal_300x168), contentDescription = "Koin Logo", - modifier = modifier + modifier = Modifier .width(107.dp) .height(60.dp) ) Text( text = stringResource(id = R.string.for_business), fontSize = 20.sp, - modifier = modifier + modifier = Modifier .padding(start = 8.dp, top = 30.dp) ) } @@ -137,7 +133,7 @@ fun SignInScreen ( ) } }, - modifier = modifier + modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) .padding(bottom = 28.dp) @@ -176,7 +172,7 @@ fun SignInScreen ( ) } }, - modifier = modifier + modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) .padding(bottom = 40.dp) @@ -186,7 +182,7 @@ fun SignInScreen ( onClick = onSignInClick, shape = RectangleShape, colors = ButtonDefaults.buttonColors(ColorAccent), - modifier = modifier + modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) .padding(bottom = 16.dp) @@ -205,7 +201,7 @@ fun SignInScreen ( onClick = onSignUpClick, shape = RectangleShape, colors = ButtonDefaults.buttonColors(ColorPrimary), - modifier = modifier + modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) .padding(top = 16.dp, bottom = 24.dp) @@ -224,19 +220,19 @@ fun SignInScreen ( onClick = onFindPasswordClick, colors = ButtonDefaults.buttonColors(Color.White), shape = RectangleShape, - modifier = modifier + modifier = Modifier .padding(horizontal = 127.dp) .padding(top = 24.dp) .fillMaxWidth() ) { Row( - modifier = modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth() ){ Image( painter = painterResource(id = R.drawable.ic_password), contentDescription = "password_icon", - modifier = modifier + modifier = Modifier .height(20.dp) .width(20.dp) ) @@ -251,7 +247,7 @@ fun SignInScreen ( Text( text = stringResource(R.string.copy_right), - modifier = modifier + modifier = Modifier .padding(top = 102.dp, bottom = 24.dp) .padding(horizontal = 64.dp) ) @@ -285,15 +281,52 @@ private fun HandleSideEffects( @Preview @Composable -fun PreViewSignInScreen(){ +fun PreViewSignInScreen( + modifier: Modifier = Modifier, + id: String = "", + password: String = "", + onIdChange: (String) -> Unit = {}, + onPasswordChange: (String) -> Unit = {}, + onSignInClick: () -> Unit = {}, + onSignUpClick: () -> Unit = {}, + onFindPasswordClick: () -> Unit = {} +){ + SignInScreen( + modifier = modifier, + id = id, + password = password, + onIdChange = onIdChange, + onPasswordChange = onPasswordChange, + onSignInClick = onSignInClick, + onSignUpClick = onSignUpClick, + onFindPasswordClick = onFindPasswordClick + ) +} + +@Preview( + showBackground = true, + uiMode = UI_MODE_NIGHT_YES, + name = "DefaultPreviewDark" +) +@Composable +fun PreViewDarkModeSignInScreen( + modifier: Modifier = Modifier, + id: String = "", + password: String = "", + onIdChange: (String) -> Unit = {}, + onPasswordChange: (String) -> Unit = {}, + onSignInClick: () -> Unit = {}, + onSignUpClick: () -> Unit = {}, + onFindPasswordClick: () -> Unit = {} +){ SignInScreen( - modifier = Modifier, - id = "", - password = "", - onIdChange = {}, - onPasswordChange = {}, - onSignInClick = {}, - onSignUpClick = {}, - onFindPasswordClick = {} + modifier = modifier, + id = id, + password = password, + onIdChange = onIdChange, + onPasswordChange = onPasswordChange, + onSignInClick = onSignInClick, + onSignUpClick = onSignUpClick, + onFindPasswordClick = onFindPasswordClick ) } \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt index 7b07fd915..bdb9383ed 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt @@ -3,5 +3,5 @@ package `in`.koreatech.business.feature.signin data class SignInState ( val id: String = "", val password: String = "", - val isFilledIdEmailField: Boolean = false + val validateField: Boolean = false ) \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt index 960890cc3..c2cb86aec 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt @@ -21,27 +21,15 @@ class SignInViewModel @Inject constructor( override val container = container( SignInState() ) - - private fun fillAllPasswords() = intent { - reduce{ - state.copy(isFilledIdEmailField = (state.id.isNotBlank() && state.password.isNotBlank())) - } - } - fun insertId(id: String) = intent{ reduce { state.copy(id = id) } - fillAllPasswords() + validateField() } fun insertPassword(password: String) = intent{ reduce { state.copy(password = password) } - fillAllPasswords() - } - - fun toastNullMessage() = intent { - postSideEffect(SignInSideEffect.ShowNullMessage(ErrorType.NullEmailOrPassword)) + validateField() } - fun navigateToSignUp() = intent { postSideEffect(SignInSideEffect.NavigateToSignUp) } @@ -50,30 +38,42 @@ class SignInViewModel @Inject constructor( postSideEffect(SignInSideEffect.NavigateToFindPassword) } - private fun navigateToMain() = intent { - postSideEffect(SignInSideEffect.NavigateToMain) - } - - - fun login( id: String, password: String, ){ - viewModelScope.launch { - userLoginUseCase( - email = id, - password = password - ) .onSuccess { + if(SignInState().validateField){ + viewModelScope.launch { + userLoginUseCase( + email = id, + password = password + ) .onSuccess { navigateToMain() - } - .onFailure { - toastErrorMessage(it.message) } + .onFailure { + toastErrorMessage(it.message) + } + } + } + else{ + toastNullMessage() } } + private fun navigateToMain() = intent { + postSideEffect(SignInSideEffect.NavigateToMain) + } + + private fun toastNullMessage() = intent { + postSideEffect(SignInSideEffect.ShowNullMessage(ErrorType.NullEmailOrPassword)) + } private fun toastErrorMessage(message: String) = intent { postSideEffect(SignInSideEffect.ShowMessage(message)) } + + private fun validateField() = intent { + reduce{ + state.copy(validateField = (state.id.isNotBlank() && state.password.isNotBlank())) + } + } } \ No newline at end of file diff --git a/business/src/main/res/values/strings.xml b/business/src/main/res/values/strings.xml index 602c47a3b..66179e5bd 100644 --- a/business/src/main/res/values/strings.xml +++ b/business/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ 로그인 화면 바로가기 backArrow 오류가 발생하였습니다. 잠시뒤에 다시 시도해 주세요 + Koin For Business From 9368eb5a8b942f3306a3b04fece66947869db9c6 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Wed, 15 May 2024 14:07:53 +0900 Subject: [PATCH 3/6] =?UTF-8?q?1=EC=B0=A8=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../changepassword/ChangePasswordScreen.kt | 8 ++++---- .../changepassword/ChangePasswordState.kt | 2 +- .../changepassword/ChangePasswordViewModel.kt | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordScreen.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordScreen.kt index 924239549..624e262f7 100644 --- a/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordScreen.kt @@ -53,7 +53,7 @@ fun ChangePasswordScreenImpl( password = state.password, passwordChecked = state.passwordChecked, notCoincidePassword = state.notCoincidePW, - fillAllPasswords = state.fillAllPasswords, + passwordsFieldIsValidate = state.PasswordsFieldIsValidate, passwordIsEmpty = state.passwordIsBlank(), passwordCheckedIsEmpty = state.passwordCheckedIsBlank(), onPasswordChange = { @@ -76,7 +76,7 @@ fun ChangePasswordScreen( password: String, passwordChecked: String, notCoincidePassword: Boolean, - fillAllPasswords :Boolean, + passwordsFieldIsValidate :Boolean, passwordIsEmpty: Boolean, passwordCheckedIsEmpty: Boolean, onPasswordChange: (String) -> Unit, @@ -201,7 +201,7 @@ fun ChangePasswordScreen( Button( onClick = onChangePasswordClick, shape = RectangleShape, - colors = if(fillAllPasswords) ButtonDefaults.buttonColors(ColorPrimary) + colors = if(passwordsFieldIsValidate) ButtonDefaults.buttonColors(ColorPrimary) else ButtonDefaults.buttonColors(Gray5), modifier = modifier .padding(horizontal = 32.dp) @@ -266,7 +266,7 @@ fun PreviewChangePassswordScreen() { password = "", passwordChecked = "", notCoincidePassword = true, - fillAllPasswords = true, + passwordsFieldIsValidate = true, passwordIsEmpty = true, passwordCheckedIsEmpty = true, onPasswordChange = {}, diff --git a/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordState.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordState.kt index 9b36de472..8eef41e3b 100644 --- a/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordState.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordState.kt @@ -9,7 +9,7 @@ data class ChangePasswordState( val passwordChecked: String = "", val email: String = "", val notCoincidePW: Boolean = false, - val fillAllPasswords: Boolean = false + val PasswordsFieldIsValidate: Boolean = false ): Parcelable fun ChangePasswordState.passwordIsBlank() = password.isBlank() diff --git a/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordViewModel.kt b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordViewModel.kt index 527a4bc41..4824f5a6f 100644 --- a/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/changepassword/changepassword/ChangePasswordViewModel.kt @@ -33,13 +33,13 @@ class ChangePasswordViewModel @Inject constructor( } } - private fun fillAllPasswords() = intent { + private fun passwordsFieldIsValidate() = intent { reduce{ - state.copy(fillAllPasswords = (state.password.isNotBlank() && state.passwordChecked.isNotBlank())) + state.copy(PasswordsFieldIsValidate = (state.password.isNotBlank() && state.passwordChecked.isNotBlank())) } } - private fun coincidePasswordReset() = intent { + private fun notCoincidePWisValidate() = intent { reduce{ state.copy(notCoincidePW = false) } @@ -47,14 +47,14 @@ class ChangePasswordViewModel @Inject constructor( fun insertPassword(password: String) = intent{ reduce { state.copy(password = password) } - coincidePasswordReset() - fillAllPasswords() + notCoincidePWisValidate() + passwordsFieldIsValidate() } fun insertPasswordChecked(passwordChecked: String) = intent{ reduce { state.copy(passwordChecked = passwordChecked) } - coincidePasswordReset() - fillAllPasswords() + notCoincidePWisValidate() + passwordsFieldIsValidate() } fun changePassword( From f77262e901803609a6c2be0c1380838f5398178d Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Wed, 15 May 2024 15:39:51 +0900 Subject: [PATCH 4/6] =?UTF-8?q?2=EC=B0=A8=20=EC=BD=94=EB=A9=98=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/feature/signin/SignInScreen.kt | 18 +++++----- .../feature/signin/SignInViewModel.kt | 34 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt index db8643eff..e5ef81566 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt @@ -61,7 +61,7 @@ fun SignInScreenImpl( password -> viewModel.insertPassword(password) }, onSignInClick = { - viewModel.login(state.id.trim(), state.password.trim()) + viewModel.login() }, onSignUpClick = {viewModel.navigateToSignUp()}, onFindPasswordClick = {viewModel.navigateToFindPassword()} @@ -71,14 +71,14 @@ fun SignInScreenImpl( } @Composable fun SignInScreen ( - modifier: Modifier, - id: String, - password: String, - onIdChange: (String) -> Unit, - onPasswordChange: (String) -> Unit, - onSignInClick: () -> Unit, - onSignUpClick:() ->Unit, - onFindPasswordClick:() -> Unit + modifier: Modifier = Modifier, + id: String = "", + password: String = "", + onIdChange: (String) -> Unit = {}, + onPasswordChange: (String) -> Unit = {}, + onSignInClick: () -> Unit = {}, + onSignUpClick: () -> Unit = {}, + onFindPasswordClick: () -> Unit = {} ){ Column(modifier = modifier.fillMaxSize()) { Row( diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt index c2cb86aec..015b99a12 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt @@ -21,6 +21,7 @@ class SignInViewModel @Inject constructor( override val container = container( SignInState() ) + fun insertId(id: String) = intent{ reduce { state.copy(id = id) } validateField() @@ -38,25 +39,24 @@ class SignInViewModel @Inject constructor( postSideEffect(SignInSideEffect.NavigateToFindPassword) } - fun login( - id: String, - password: String, - ){ - if(SignInState().validateField){ - viewModelScope.launch { - userLoginUseCase( - email = id, - password = password - ) .onSuccess { - navigateToMain() - } - .onFailure { - toastErrorMessage(it.message) + fun login(){ + intent{ + if(state.validateField){ + viewModelScope.launch { + userLoginUseCase( + email = state.id.trim(), + password = state.password.trim() + ) .onSuccess { + navigateToMain() } + .onFailure { + toastErrorMessage(it.message) + } + } + } + else{ + toastNullMessage() } - } - else{ - toastNullMessage() } } From 2c8675bfc1883ff1cadd99af3ec8769a451f2147 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Fri, 13 Sep 2024 18:30:51 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20UI=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessMainActivity.kt | 1 + .../business/feature/signin/SignInScreen.kt | 161 ++++++++---------- .../feature/signin/SignInSideEffect.kt | 3 +- .../business/feature/signin/SignInState.kt | 3 +- .../feature/signin/SignInViewModel.kt | 39 +++-- .../feature/signin/navigator/RouteSignIn.kt | 6 +- .../business/navigation/TmpScreen.kt | 14 ++ .../src/main/res/drawable/koin_owner_logo.xml | 30 ++++ core/src/main/res/values/strings.xml | 3 + .../in/koreatech/koin/data/api/UserApi.kt | 5 + .../koin/data/constant/URLConstant.kt | 1 + .../data/repository/UserRepositoryImpl.kt | 9 + .../data/request/owner/OwnerLoginRequest.kt | 8 + .../data/response/owner/OwnerAuthResponse.kt | 8 + .../source/remote/UserRemoteDataSource.kt | 8 + .../koin/domain/model/user/AuthToken.kt | 2 +- .../koin/domain/repository/UserRepository.kt | 6 + .../usecase/business/OwnerSignInUseCase.kt | 28 +++ 18 files changed, 228 insertions(+), 107 deletions(-) create mode 100644 business/src/main/java/in/koreatech/business/navigation/TmpScreen.kt create mode 100644 core/src/main/res/drawable/koin_owner_logo.xml create mode 100644 data/src/main/java/in/koreatech/koin/data/request/owner/OwnerLoginRequest.kt create mode 100644 data/src/main/java/in/koreatech/koin/data/response/owner/OwnerAuthResponse.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/business/OwnerSignInUseCase.kt diff --git a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt index 85d1e6f53..9268fa345 100644 --- a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt +++ b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt @@ -26,6 +26,7 @@ class BusinessMainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { + //KoinBusinessNavHost() SignInNavigator() } } diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt index e5ef81566..f86eee169 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt @@ -2,6 +2,8 @@ package `in`.koreatech.business.feature.signin import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -9,6 +11,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.Button @@ -26,6 +29,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -41,7 +45,7 @@ import org.orbitmvi.orbit.compose.collectSideEffect @Composable -fun SignInScreenImpl( +fun SignInScreen( modifier: Modifier = Modifier, navigateToSignUp: () -> Unit, navigateToFindPassword: () -> Unit, @@ -50,10 +54,12 @@ fun SignInScreenImpl( ) { val state = viewModel.collectAsState().value - SignInScreen( + SignInScreenImpl( modifier = modifier, id = state.id, password = state.password, + nullErrorMessage = state.nullErrorMessage, + notValidateField = state.notValidateField, onIdChange = { id -> viewModel.insertId(id) }, @@ -70,10 +76,12 @@ fun SignInScreenImpl( HandleSideEffects(viewModel, navigateToSignUp, navigateToFindPassword, navigateToMain) } @Composable -fun SignInScreen ( +fun SignInScreenImpl( modifier: Modifier = Modifier, id: String = "", password: String = "", + nullErrorMessage: String = "", + notValidateField: Boolean = false, onIdChange: (String) -> Unit = {}, onPasswordChange: (String) -> Unit = {}, onSignInClick: () -> Unit = {}, @@ -81,26 +89,24 @@ fun SignInScreen ( onFindPasswordClick: () -> Unit = {} ){ Column(modifier = modifier.fillMaxSize()) { + Row( modifier = Modifier - .padding(start = 32.dp, top = 88.dp, end = 32.dp, bottom = 80.dp) - .fillMaxWidth(), - ) { + .fillMaxWidth() + .padding(horizontal = 32.dp, vertical = 95.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ){ Image( - painter = painterResource(id = R.drawable.logo_color_horizontal_300x168), - contentDescription = "Koin Logo", - modifier = Modifier - .width(107.dp) - .height(60.dp) - ) - Text( - text = stringResource(id = R.string.for_business), - fontSize = 20.sp, + painter = painterResource(id = R.drawable.koin_owner_logo), + contentDescription = "Koin Owner Logo", modifier = Modifier - .padding(start = 8.dp, top = 30.dp) + .size(150.dp), + alignment = Alignment.CenterStart ) } + BasicTextField( value = id, onValueChange = onIdChange, @@ -109,7 +115,6 @@ fun SignInScreen ( decorationBox = { innerTextField -> Column( modifier = Modifier - .padding(horizontal = 16.dp) .fillMaxWidth() ) { Box( @@ -119,7 +124,7 @@ fun SignInScreen ( ) { if (id.isEmpty()) { Text( - stringResource(R.string.id), + stringResource(R.string.phone_number), color = Blue1, fontSize = 15.sp ) @@ -127,9 +132,11 @@ fun SignInScreen ( innerTextField() } Divider( - color = if (id.isEmpty()) Blue1 else Color.Black, + color = if (notValidateField) ColorAccent else Blue1, thickness = 1.dp, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp) ) } }, @@ -148,7 +155,6 @@ fun SignInScreen ( decorationBox = { innerTextField -> Column( modifier = Modifier - .padding(horizontal = 16.dp) .fillMaxWidth() ) { Box( @@ -165,17 +171,29 @@ fun SignInScreen ( } innerTextField() } + Divider( - color = if (password.isEmpty()) Blue1 else Color.Black, + color = if (notValidateField) ColorAccent else Blue1, thickness = 1.dp, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp) ) } }, modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) - .padding(bottom = 40.dp) + ) + + Text( + modifier = Modifier + .padding(horizontal = 32.dp) + .padding(top = 4.dp) + , + fontSize = 11.sp, + text = if(notValidateField) nullErrorMessage else "", + color = ColorAccent ) Button( @@ -185,6 +203,7 @@ fun SignInScreen ( modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) + .padding(top = 40.dp) .padding(bottom = 16.dp) .height(44.dp) @@ -216,42 +235,33 @@ fun SignInScreen ( ) } - Button( - onClick = onFindPasswordClick, - colors = ButtonDefaults.buttonColors(Color.White), - shape = RectangleShape, + Row( modifier = Modifier - .padding(horizontal = 127.dp) - .padding(top = 24.dp) .fillMaxWidth() + .height(35.dp) + .padding(horizontal = 127.dp) + .clickable { + onFindPasswordClick() + }, + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ){ + Image( + painter = painterResource(id = R.drawable.ic_password), + contentDescription = "password_icon", + modifier = Modifier + .height(20.dp) + .width(20.dp) + .padding(end = 4.dp) + ) - ) { - Row( - modifier = Modifier.fillMaxWidth() - ){ - Image( - painter = painterResource(id = R.drawable.ic_password), - contentDescription = "password_icon", - modifier = Modifier - .height(20.dp) - .width(20.dp) - ) - - Text( - stringResource(R.string.password_find), - color = ColorSecondaryText, - fontSize = 13.sp, - ) - } + Text( + stringResource(R.string.password_find), + color = ColorSecondaryText, + fontSize = 13.sp, + textAlign = TextAlign.Center + ) } - - Text( - text = stringResource(R.string.copy_right), - modifier = Modifier - .padding(top = 102.dp, bottom = 24.dp) - .padding(horizontal = 64.dp) - ) - } } @@ -268,12 +278,15 @@ private fun HandleSideEffects( is SignInSideEffect.NavigateToMain -> navigateToMain() is SignInSideEffect.NavigateToFindPassword -> navigateToFindPassword() is SignInSideEffect.NavigateToSignUp -> navigateToSignUp() - is SignInSideEffect.ShowMessage -> ToastUtil.getInstance().makeShort(sideEffect.message) + is SignInSideEffect.ShowMessage -> { + viewModel.setErrorMessage(sideEffect.message) + } is SignInSideEffect.ShowNullMessage -> { val message = when (sideEffect.type) { - ErrorType.NullEmailOrPassword -> context.getString(R.string.login_required_field_not_filled) + ErrorType.NullPhoneNumber -> context.getString(R.string.phone_number_is_null) + ErrorType.NullPassword -> context.getString(R.string.password_is_null) } - ToastUtil.getInstance().makeShort(message) + viewModel.setErrorMessage(message) } } } @@ -291,35 +304,7 @@ fun PreViewSignInScreen( onSignUpClick: () -> Unit = {}, onFindPasswordClick: () -> Unit = {} ){ - SignInScreen( - modifier = modifier, - id = id, - password = password, - onIdChange = onIdChange, - onPasswordChange = onPasswordChange, - onSignInClick = onSignInClick, - onSignUpClick = onSignUpClick, - onFindPasswordClick = onFindPasswordClick - ) -} - -@Preview( - showBackground = true, - uiMode = UI_MODE_NIGHT_YES, - name = "DefaultPreviewDark" -) -@Composable -fun PreViewDarkModeSignInScreen( - modifier: Modifier = Modifier, - id: String = "", - password: String = "", - onIdChange: (String) -> Unit = {}, - onPasswordChange: (String) -> Unit = {}, - onSignInClick: () -> Unit = {}, - onSignUpClick: () -> Unit = {}, - onFindPasswordClick: () -> Unit = {} -){ - SignInScreen( + SignInScreenImpl( modifier = modifier, id = id, password = password, diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt index 037c49bec..84cd78151 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInSideEffect.kt @@ -14,5 +14,6 @@ sealed class SignInSideEffect { } enum class ErrorType { - NullEmailOrPassword + NullPhoneNumber, + NullPassword } \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt index bdb9383ed..7d68b0509 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt @@ -3,5 +3,6 @@ package `in`.koreatech.business.feature.signin data class SignInState ( val id: String = "", val password: String = "", - val validateField: Boolean = false + val nullErrorMessage: String = "", + val notValidateField: Boolean = false ) \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt index 015b99a12..b6331d617 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt @@ -1,8 +1,10 @@ package `in`.koreatech.business.feature.signin +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.koreatech.koin.domain.usecase.business.OwnerSignInUseCase import `in`.koreatech.koin.domain.usecase.user.UserLoginUseCase import `in`.koreatech.koin.domain.util.onFailure import `in`.koreatech.koin.domain.util.onSuccess @@ -16,7 +18,7 @@ import javax.inject.Inject @HiltViewModel class SignInViewModel @Inject constructor( - private val userLoginUseCase: UserLoginUseCase + private val ownerSignInUseCase: OwnerSignInUseCase ) : ViewModel(), ContainerHost { override val container = container( SignInState() @@ -24,12 +26,10 @@ class SignInViewModel @Inject constructor( fun insertId(id: String) = intent{ reduce { state.copy(id = id) } - validateField() } fun insertPassword(password: String) = intent{ reduce { state.copy(password = password) } - validateField() } fun navigateToSignUp() = intent { postSideEffect(SignInSideEffect.NavigateToSignUp) @@ -41,10 +41,11 @@ class SignInViewModel @Inject constructor( fun login(){ intent{ - if(state.validateField){ + if((state.id.isNotBlank() && state.password.isNotBlank())){ + state.copy(notValidateField = false) viewModelScope.launch { - userLoginUseCase( - email = state.id.trim(), + ownerSignInUseCase( + phoneNumber = state.id.trim(), password = state.password.trim() ) .onSuccess { navigateToMain() @@ -55,25 +56,35 @@ class SignInViewModel @Inject constructor( } } else{ - toastNullMessage() + showNullMessage() } } } + fun setErrorMessage(message: String){ + intent { + reduce{ + state.copy( + nullErrorMessage = message + ) + } + } + } private fun navigateToMain() = intent { postSideEffect(SignInSideEffect.NavigateToMain) } - private fun toastNullMessage() = intent { - postSideEffect(SignInSideEffect.ShowNullMessage(ErrorType.NullEmailOrPassword)) + private fun showNullMessage() { + intent { + reduce { + state.copy(notValidateField = true) + } + if(state.id.isBlank()) postSideEffect(SignInSideEffect.ShowNullMessage(ErrorType.NullPhoneNumber)) + else if(state.password.isBlank()) postSideEffect(SignInSideEffect.ShowNullMessage(ErrorType.NullPassword)) + } } private fun toastErrorMessage(message: String) = intent { postSideEffect(SignInSideEffect.ShowMessage(message)) } - private fun validateField() = intent { - reduce{ - state.copy(validateField = (state.id.isNotBlank() && state.password.isNotBlank())) - } - } } \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt b/business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt index d55e4054e..da74a8a20 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/navigator/RouteSignIn.kt @@ -1,5 +1,6 @@ package `in`.koreatech.business.feature.signin.navigator +import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -8,9 +9,10 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import `in`.koreatech.business.feature.findpassword.navigator.ChangePassword -import `in`.koreatech.business.feature.signin.SignInScreenImpl +import `in`.koreatech.business.feature.signin.SignInScreen import `in`.koreatech.business.feature.signup.navigator.SignupNavigator +@OptIn(ExperimentalAnimationApi::class) @Composable fun SignInNavigator( modifier: Modifier = Modifier, @@ -22,7 +24,7 @@ fun SignInNavigator( modifier = modifier ){ composable(route = SignInNavigator.SignIn.name){ - SignInScreenImpl( + SignInScreen( navigateToMain = {}, navigateToSignUp = { navController.navigate(SignInNavigator.SignUp.name) diff --git a/business/src/main/java/in/koreatech/business/navigation/TmpScreen.kt b/business/src/main/java/in/koreatech/business/navigation/TmpScreen.kt new file mode 100644 index 000000000..3332a8cbc --- /dev/null +++ b/business/src/main/java/in/koreatech/business/navigation/TmpScreen.kt @@ -0,0 +1,14 @@ +package `in`.koreatech.business.navigation + +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable + +@Composable +fun TestScreen( + onSignUpComplete: () -> Unit = {} +) { + Button(onClick = onSignUpComplete ) { + Text("임시 버튼") + } +} \ No newline at end of file diff --git a/core/src/main/res/drawable/koin_owner_logo.xml b/core/src/main/res/drawable/koin_owner_logo.xml new file mode 100644 index 000000000..21a6176f6 --- /dev/null +++ b/core/src/main/res/drawable/koin_owner_logo.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index b53d58dfc..738c80d0a 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ 네트워크 환경을 확인해주세요 + 휴대폰 번호 권한이 필요합니다. 확인 확인하기 @@ -114,6 +115,7 @@ 오류가 발생하였습니다. 잠시뒤에 다시 시도해 주세요 For Business 아이디와 비밀번호를 입력해주세요 + 전화번호를 입력해주세요. @@ -145,6 +147,7 @@ 비밀번호 찾기 비밀번호 변경 비밀번호가 일치하지 않습니다. + 비밀번호를 입력해주세요. ======= diff --git a/data/src/main/java/in/koreatech/koin/data/api/UserApi.kt b/data/src/main/java/in/koreatech/koin/data/api/UserApi.kt index 5c46836b3..e8e1f1fd0 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/UserApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/UserApi.kt @@ -1,10 +1,12 @@ package `in`.koreatech.koin.data.api import `in`.koreatech.koin.data.constant.URLConstant +import `in`.koreatech.koin.data.request.owner.OwnerLoginRequest import `in`.koreatech.koin.data.request.user.IdRequest import `in`.koreatech.koin.data.request.user.LoginRequest import `in`.koreatech.koin.data.request.user.RefreshRequest import `in`.koreatech.koin.data.request.user.StudentInfoRequest +import `in`.koreatech.koin.data.response.owner.OwnerAuthResponse import `in`.koreatech.koin.data.response.user.AuthResponse import `in`.koreatech.koin.data.response.user.RefreshResponse import retrofit2.Response @@ -14,6 +16,9 @@ interface UserApi { @POST(URLConstant.USER.LOGIN) suspend fun getToken(@Body loginRequest: LoginRequest): AuthResponse + @POST(URLConstant.OWNER.SIGNIN) + suspend fun getOwnerToken(@Body ownerLoginRequest: OwnerLoginRequest): OwnerAuthResponse + @POST(URLConstant.USER.STUDENT.REGISTER) suspend fun postRegister(@Body studentInfoRequest: StudentInfoRequest) diff --git a/data/src/main/java/in/koreatech/koin/data/constant/URLConstant.kt b/data/src/main/java/in/koreatech/koin/data/constant/URLConstant.kt index a9f0b1026..d67f13eb6 100644 --- a/data/src/main/java/in/koreatech/koin/data/constant/URLConstant.kt +++ b/data/src/main/java/in/koreatech/koin/data/constant/URLConstant.kt @@ -77,6 +77,7 @@ object URLConstant { const val OWNER = "owner" const val OWNERS = "owners" const val VERIFICATION = "verification" + const val SIGNIN = "$OWNER/login" const val REGISTER: String = "$OWNERS/register" const val REGISTER_PHONE: String = "$OWNERS/register/phone" const val CODE = "$OWNERS/$VERIFICATION/code" diff --git a/data/src/main/java/in/koreatech/koin/data/repository/UserRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/UserRepositoryImpl.kt index ee7ea8714..8a52643c9 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/UserRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/UserRepositoryImpl.kt @@ -2,6 +2,7 @@ package `in`.koreatech.koin.data.repository import `in`.koreatech.koin.data.mapper.toUser import `in`.koreatech.koin.data.mapper.toUserRequest +import `in`.koreatech.koin.data.request.owner.OwnerLoginRequest import `in`.koreatech.koin.data.request.user.IdRequest import `in`.koreatech.koin.data.request.user.LoginRequest import `in`.koreatech.koin.data.request.user.PasswordRequest @@ -29,6 +30,14 @@ class UserRepositoryImpl @Inject constructor( return AuthToken(authResponse.token, authResponse.refreshToken, authResponse.userType) } + override suspend fun getOwnerToken(phoneNumber: String, hashedPassword: String): AuthToken { + val authResponse = userRemoteDataSource.getOwnerToken( + OwnerLoginRequest(phoneNumber, hashedPassword) + ) + + return AuthToken(authResponse.token, authResponse.refreshToken) + } + override suspend fun getUserInfo(): User { return userRemoteDataSource.getUserInfo().toUser().also { userLocalDataSource.updateUserInfo(it) diff --git a/data/src/main/java/in/koreatech/koin/data/request/owner/OwnerLoginRequest.kt b/data/src/main/java/in/koreatech/koin/data/request/owner/OwnerLoginRequest.kt new file mode 100644 index 000000000..1a2b52b4c --- /dev/null +++ b/data/src/main/java/in/koreatech/koin/data/request/owner/OwnerLoginRequest.kt @@ -0,0 +1,8 @@ +package `in`.koreatech.koin.data.request.owner + +import com.google.gson.annotations.SerializedName + +data class OwnerLoginRequest( + @SerializedName("account") val phoneNumber: String, + @SerializedName("password") val password: String, +) \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/response/owner/OwnerAuthResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/owner/OwnerAuthResponse.kt new file mode 100644 index 000000000..77c5ef4c2 --- /dev/null +++ b/data/src/main/java/in/koreatech/koin/data/response/owner/OwnerAuthResponse.kt @@ -0,0 +1,8 @@ +package `in`.koreatech.koin.data.response.owner + +import com.google.gson.annotations.SerializedName + +data class OwnerAuthResponse ( + @SerializedName("token") val token: String, + @SerializedName("refresh_token") val refreshToken: String +) diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/UserRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/UserRemoteDataSource.kt index 736be5b40..423085662 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/UserRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/UserRemoteDataSource.kt @@ -2,12 +2,14 @@ package `in`.koreatech.koin.data.source.remote import `in`.koreatech.koin.data.api.UserApi import `in`.koreatech.koin.data.api.auth.UserAuthApi +import `in`.koreatech.koin.data.request.owner.OwnerLoginRequest import `in`.koreatech.koin.data.request.user.DeviceTokenRequest import `in`.koreatech.koin.data.request.user.IdRequest import `in`.koreatech.koin.data.request.user.LoginRequest import `in`.koreatech.koin.data.request.user.PasswordRequest import `in`.koreatech.koin.data.request.user.StudentInfoRequest import `in`.koreatech.koin.data.request.user.UserRequest +import `in`.koreatech.koin.data.response.owner.OwnerAuthResponse import `in`.koreatech.koin.data.response.user.* class UserRemoteDataSource( @@ -20,6 +22,12 @@ class UserRemoteDataSource( return userApi.getToken(loginRequest) } + suspend fun getOwnerToken( + ownerLoginRequest: OwnerLoginRequest + ): OwnerAuthResponse { + return userApi.getOwnerToken(ownerLoginRequest) + } + suspend fun getUserInfo(): UserResponse { return userAuthApi.getUser() } diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/user/AuthToken.kt b/domain/src/main/java/in/koreatech/koin/domain/model/user/AuthToken.kt index dad8bf7e7..f456339fc 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/user/AuthToken.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/user/AuthToken.kt @@ -3,5 +3,5 @@ package `in`.koreatech.koin.domain.model.user data class AuthToken( val token: String, val refreshToken: String, - val userType: String?, + val userType: String? = "", ) diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/UserRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/UserRepository.kt index c8abff0b3..3c60269d8 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/UserRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/UserRepository.kt @@ -10,6 +10,12 @@ interface UserRepository { hashedPassword: String, ): AuthToken + suspend fun getOwnerToken( + phoneNumber: String, + hashedPassword: String, + ): AuthToken + + suspend fun getUserInfo(): User fun getUserInfoFlow(): Flow suspend fun requestPasswordResetEmail(email: String) diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/business/OwnerSignInUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/OwnerSignInUseCase.kt new file mode 100644 index 000000000..c04974f16 --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/OwnerSignInUseCase.kt @@ -0,0 +1,28 @@ +package `in`.koreatech.koin.domain.usecase.business + +import `in`.koreatech.koin.domain.error.user.UserErrorHandler +import `in`.koreatech.koin.domain.model.error.ErrorHandler +import `in`.koreatech.koin.domain.repository.TokenRepository +import `in`.koreatech.koin.domain.repository.UserRepository +import `in`.koreatech.koin.domain.util.ext.toSHA256 +import javax.inject.Inject + +class OwnerSignInUseCase @Inject constructor( + private val userRepository: UserRepository, + private val tokenRepository: TokenRepository, + private val userErrorHandler: UserErrorHandler, +) { + suspend operator fun invoke( + phoneNumber: String, + password: String, + ): Pair { + return try { + val authToken = userRepository.getOwnerToken(phoneNumber, password.toSHA256()) + tokenRepository.saveAccessToken(authToken.token) + tokenRepository.saveRefreshToken(authToken.refreshToken) + Unit to null + } catch (throwable: Throwable) { + null to userErrorHandler.handleGetTokenError(throwable) + } + } +} \ No newline at end of file From 03cb2f476b28cf9bd9f3fb9649549423396973d7 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Mon, 16 Sep 2024 21:04:39 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=201=EC=B0=A8=20?= =?UTF-8?q?=EC=BD=94=EB=A9=98=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/feature/signin/SignInScreen.kt | 16 ++++++---------- .../business/feature/signin/SignInState.kt | 2 +- .../business/feature/signin/SignInViewModel.kt | 10 +++++----- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt index f86eee169..ba812ef93 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt @@ -58,14 +58,10 @@ fun SignInScreen( modifier = modifier, id = state.id, password = state.password, - nullErrorMessage = state.nullErrorMessage, + errorMessage = state.errorMessage, notValidateField = state.notValidateField, - onIdChange = { - id -> viewModel.insertId(id) - }, - onPasswordChange = { - password -> viewModel.insertPassword(password) - }, + onIdChange = viewModel::insertId, + onPasswordChange = viewModel::insertPassword, onSignInClick = { viewModel.login() }, @@ -80,7 +76,7 @@ fun SignInScreenImpl( modifier: Modifier = Modifier, id: String = "", password: String = "", - nullErrorMessage: String = "", + errorMessage: String = "", notValidateField: Boolean = false, onIdChange: (String) -> Unit = {}, onPasswordChange: (String) -> Unit = {}, @@ -192,7 +188,7 @@ fun SignInScreenImpl( .padding(top = 4.dp) , fontSize = 11.sp, - text = if(notValidateField) nullErrorMessage else "", + text = if(notValidateField) errorMessage else "", color = ColorAccent ) @@ -223,7 +219,7 @@ fun SignInScreenImpl( modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) - .padding(top = 16.dp, bottom = 24.dp) + .padding(bottom = 24.dp) .height(44.dp) ) { diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt index 7d68b0509..d9d5d9f7e 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInState.kt @@ -3,6 +3,6 @@ package `in`.koreatech.business.feature.signin data class SignInState ( val id: String = "", val password: String = "", - val nullErrorMessage: String = "", + val errorMessage: String = "", val notValidateField: Boolean = false ) \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt index b6331d617..b762c8f62 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInViewModel.kt @@ -51,12 +51,12 @@ class SignInViewModel @Inject constructor( navigateToMain() } .onFailure { - toastErrorMessage(it.message) + showErrorMessage(it.message) } } } else{ - showNullMessage() + showErrorMessage() } } } @@ -65,7 +65,7 @@ class SignInViewModel @Inject constructor( intent { reduce{ state.copy( - nullErrorMessage = message + errorMessage = message ) } } @@ -74,7 +74,7 @@ class SignInViewModel @Inject constructor( postSideEffect(SignInSideEffect.NavigateToMain) } - private fun showNullMessage() { + private fun showErrorMessage() { intent { reduce { state.copy(notValidateField = true) @@ -83,7 +83,7 @@ class SignInViewModel @Inject constructor( else if(state.password.isBlank()) postSideEffect(SignInSideEffect.ShowNullMessage(ErrorType.NullPassword)) } } - private fun toastErrorMessage(message: String) = intent { + private fun showErrorMessage(message: String) = intent { postSideEffect(SignInSideEffect.ShowMessage(message)) }