From 2ed517b6883a1c83ace9279170c856951e0399f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=98=84=EC=84=9C?= Date: Sat, 24 Feb 2024 15:20:55 +0900 Subject: [PATCH 1/4] :lipstick: :: Add round icon --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0970a23..ffb4a4b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/logo" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" + android:roundIcon="@mipmap/logo" android:supportsRtl="true" android:theme="@style/Theme.DotoriAndroid" tools:targetApi="31"> From 4ce7e2427fdb196364e2dee5d93bdab84b0317fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=98=84=EC=84=9C?= Date: Sat, 24 Feb 2024 15:21:32 +0900 Subject: [PATCH 2/4] :sparkles: :: Create isStrongEmail --- .../java/com/msg/presentation/view/util/isStrongEmail.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 presentation/src/main/java/com/msg/presentation/view/util/isStrongEmail.kt diff --git a/presentation/src/main/java/com/msg/presentation/view/util/isStrongEmail.kt b/presentation/src/main/java/com/msg/presentation/view/util/isStrongEmail.kt new file mode 100644 index 0000000..7e719ad --- /dev/null +++ b/presentation/src/main/java/com/msg/presentation/view/util/isStrongEmail.kt @@ -0,0 +1,6 @@ +package com.msg.presentation.view.util + +fun isStrongEmail(email: String): Boolean { + val regex = Regex("^s\\d{5}@gsm\\.hs\\.kr\$") + return regex.matches(email) +} \ No newline at end of file From 3cec1bbe77b6af07a84f792f03a2bdb7a73e74ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=98=84=EC=84=9C?= Date: Sat, 24 Feb 2024 15:21:39 +0900 Subject: [PATCH 3/4] :sparkles: :: Create isStrongPassword --- .../java/com/msg/presentation/view/util/isStrongPassword.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 presentation/src/main/java/com/msg/presentation/view/util/isStrongPassword.kt diff --git a/presentation/src/main/java/com/msg/presentation/view/util/isStrongPassword.kt b/presentation/src/main/java/com/msg/presentation/view/util/isStrongPassword.kt new file mode 100644 index 0000000..90b015a --- /dev/null +++ b/presentation/src/main/java/com/msg/presentation/view/util/isStrongPassword.kt @@ -0,0 +1,6 @@ +package com.msg.presentation.view.util + +fun isStrongPassword(password: String): Boolean { + val regex = Regex("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@\$!%*#?&])[A-Za-z\\d@\$!%*#?&]{8,20}\$") + return regex.matches(password) +} \ No newline at end of file From a2a183468af03b5355ee0fd633038743989715f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=98=84=EC=84=9C?= Date: Sat, 24 Feb 2024 15:22:25 +0900 Subject: [PATCH 4/4] :sparkles: :: Apply regular expression --- .../presentation/view/login/LoginScreen.kt | 31 ++++++++++----- .../view/signup/AuthenticationScreen.kt | 12 +++++- .../view/signup/PasswordScreen.kt | 10 ++++- .../presentation/viewmodel/LoginViewModel.kt | 39 ++++++++++--------- .../presentation/viewmodel/SignUpViewModel.kt | 1 + 5 files changed, 61 insertions(+), 32 deletions(-) diff --git a/presentation/src/main/java/com/msg/presentation/view/login/LoginScreen.kt b/presentation/src/main/java/com/msg/presentation/view/login/LoginScreen.kt index edec01a..8894885 100644 --- a/presentation/src/main/java/com/msg/presentation/view/login/LoginScreen.kt +++ b/presentation/src/main/java/com/msg/presentation/view/login/LoginScreen.kt @@ -1,7 +1,7 @@ package com.msg.presentation.view.login import android.annotation.SuppressLint -import android.util.Log +import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -23,6 +24,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -37,9 +39,9 @@ import com.dotori.dotori_components.theme.LockIcon import com.dotori.dotori_components.theme.PersonIcon import com.dotori.dotori_components.theme.XMarkIcon import com.msg.domain.model.auth.LoginRequestModel -import com.msg.domain.model.auth.LoginResponseModel import com.msg.presentation.viewmodel.LoginViewModel import com.msg.presentation.viewmodel.util.Event +import com.msg.presentation.view.util.isStrongEmail @SuppressLint("RememberReturnType") @Composable @@ -49,6 +51,7 @@ fun LoginScreen( navigateToMain: () -> Unit, navigateToSignUp: () -> Unit ) { + val context = LocalContext.current var idText by remember { mutableStateOf("") } var passwordText by remember { mutableStateOf("") } var isIdClicked by remember { mutableStateOf(false) } @@ -56,9 +59,13 @@ fun LoginScreen( val loginUiState by loginViewModel.loginState.collectAsState() - when (loginUiState) { - is Event.Success -> navigateToMain() - else -> {} + LaunchedEffect(loginUiState) { + when (loginUiState) { + is Event.Success -> navigateToMain() + is Event.BadRequest -> Toast.makeText(context, "비밀번호가 일치하지 않습니다.", Toast.LENGTH_SHORT).show() + is Event.NotFound -> Toast.makeText(context, "해당 유저가 존재하지 않습니다.", Toast.LENGTH_SHORT).show() + else -> Unit + } } Column( @@ -144,12 +151,16 @@ fun LoginScreen( .height(52.dp), text = "로그인" ) { - loginViewModel.login( - LoginRequestModel( - email = idText, - password = passwordText + if (isStrongEmail(idText)) { + loginViewModel.login( + LoginRequestModel( + email = idText, + password = passwordText + ) ) - ) + } else { + Toast.makeText(context, "gsm메일 형식에 맞게 입력해주세요.", Toast.LENGTH_SHORT).show() + } } Spacer(modifier = Modifier.height(16.dp)) Row( diff --git a/presentation/src/main/java/com/msg/presentation/view/signup/AuthenticationScreen.kt b/presentation/src/main/java/com/msg/presentation/view/signup/AuthenticationScreen.kt index f3cb5f5..f6bd117 100644 --- a/presentation/src/main/java/com/msg/presentation/view/signup/AuthenticationScreen.kt +++ b/presentation/src/main/java/com/msg/presentation/view/signup/AuthenticationScreen.kt @@ -1,5 +1,6 @@ package com.msg.presentation.view.signup +import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -22,6 +23,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModelStoreOwner @@ -35,6 +37,7 @@ import com.dotori.dotori_components.theme.XMarkIcon import com.msg.domain.model.email.EmailVerifyRequestModel import com.msg.domain.model.email.SendEmailRequestModel import com.msg.presentation.view.signup.component.SignUpDatIndicator +import com.msg.presentation.view.util.isStrongEmail import com.msg.presentation.viewmodel.util.Event import com.msg.presentation.viewmodel.util.SignUpViewModelProvider @@ -47,6 +50,7 @@ fun AuthenticationScreen( navigateToPassword: () -> Unit ) { SignUpViewModelProvider(viewModelStoreOwner = viewModelStoreOwner) { signUpViewModel -> + val context = LocalContext.current var emailText by remember { mutableStateOf("") } var numberText by remember { mutableStateOf("") } var isEmailClicked by remember { mutableStateOf(false) } @@ -140,8 +144,12 @@ fun AuthenticationScreen( .height(52.dp), text = "인증하기" ) { - signUpViewModel.email.value = emailText - signUpViewModel.sendEmail(SendEmailRequestModel(signUpViewModel.email.value)) + if (isStrongEmail(emailText)) { + signUpViewModel.email.value = emailText + signUpViewModel.sendEmail(SendEmailRequestModel(signUpViewModel.email.value)) + } else { + Toast.makeText(context, "gsm메일 형식에 맞게 입력해주세요.", Toast.LENGTH_SHORT).show() + } } } Spacer(modifier = Modifier.height(24.dp)) diff --git a/presentation/src/main/java/com/msg/presentation/view/signup/PasswordScreen.kt b/presentation/src/main/java/com/msg/presentation/view/signup/PasswordScreen.kt index 425f561..1a2acd5 100644 --- a/presentation/src/main/java/com/msg/presentation/view/signup/PasswordScreen.kt +++ b/presentation/src/main/java/com/msg/presentation/view/signup/PasswordScreen.kt @@ -1,5 +1,6 @@ package com.msg.presentation.view.signup +import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -22,6 +23,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign @@ -38,6 +40,7 @@ import com.dotori.dotori_components.theme.EyeOpenIcon import com.dotori.dotori_components.theme.XMarkIcon import com.msg.domain.model.auth.SignUpRequestModel import com.msg.presentation.view.signup.component.SignUpDatIndicator +import com.msg.presentation.view.util.isStrongPassword import com.msg.presentation.viewmodel.util.Event import com.msg.presentation.viewmodel.util.SignUpViewModelProvider @@ -49,6 +52,7 @@ fun PasswordScreen( navigateToLogin: () -> Unit ) { SignUpViewModelProvider(viewModelStoreOwner = viewModelStoreOwner) { signUpViewModel -> + val context = LocalContext.current var passwordText by remember { mutableStateOf("") } var checkPasswordText by remember { mutableStateOf("") } var isPasswordVisible by remember { mutableStateOf(false) } @@ -190,7 +194,11 @@ fun PasswordScreen( .height(52.dp), text = "회원가입" ) { - if (passwordText == checkPasswordText) { + if (passwordText != checkPasswordText) { + Toast.makeText(context, "비밀번호가 서로 일치하지 않습니다..", Toast.LENGTH_SHORT).show() + } else if (!isStrongPassword(passwordText)) { + Toast.makeText(context, "비밀번호 형식에 맞게 입력해주세요.", Toast.LENGTH_SHORT).show() + } else { signUpViewModel.password.value = passwordText signUpViewModel.signUp( SignUpRequestModel( diff --git a/presentation/src/main/java/com/msg/presentation/viewmodel/LoginViewModel.kt b/presentation/src/main/java/com/msg/presentation/viewmodel/LoginViewModel.kt index f7b919b..39a2d0b 100644 --- a/presentation/src/main/java/com/msg/presentation/viewmodel/LoginViewModel.kt +++ b/presentation/src/main/java/com/msg/presentation/viewmodel/LoginViewModel.kt @@ -27,23 +27,24 @@ class LoginViewModel @Inject constructor( val loginState = _loginState.asStateFlow() fun login(loginRequestModel: LoginRequestModel) = viewModelScope.launch { - loginUseCase(loginRequestModel) - .onSuccess { - _loginState.value = Event.Success(it) - saveTokenUseCase( - accessToken = it.accessToken, - refreshToken = it.refreshToken, - expiresAt = it.expiresAt - ) - saveRoleUseCase(it.roles.toString()) - Log.d("failure", "success") - } - .onFailure { - Log.d("failure", it.message.toString()) - it.exceptionHandling( - badRequestAction = { _loginState.value = Event.BadRequest }, - notFoundAction = { _loginState.value = Event.NotFound } - ) - } - } + _loginState.value = Event.Loading + loginUseCase(loginRequestModel) + .onSuccess { + _loginState.value = Event.Success(it) + saveTokenUseCase( + accessToken = it.accessToken, + refreshToken = it.refreshToken, + expiresAt = it.expiresAt + ) + saveRoleUseCase(it.roles.toString()) + Log.d("failure", "success") + } + .onFailure { + Log.d("failure", it.message.toString()) + it.exceptionHandling( + badRequestAction = { _loginState.value = Event.BadRequest }, + notFoundAction = { _loginState.value = Event.NotFound } + ) + } + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/msg/presentation/viewmodel/SignUpViewModel.kt b/presentation/src/main/java/com/msg/presentation/viewmodel/SignUpViewModel.kt index bdeaa10..a6d0cd6 100644 --- a/presentation/src/main/java/com/msg/presentation/viewmodel/SignUpViewModel.kt +++ b/presentation/src/main/java/com/msg/presentation/viewmodel/SignUpViewModel.kt @@ -41,6 +41,7 @@ class SignUpViewModel @Inject constructor( fun signUp(body: SignUpRequestModel) = viewModelScope.launch { + _signUpState.value = Event.Loading signUpUseCase(body) .onSuccess { _signUpState.value = Event.Success()