From c509561d33e7ad51a90b221cb3c486bc89973b22 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 04:14:17 +0900 Subject: [PATCH 01/28] =?UTF-8?q?UI=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/frontend/ui/login/RegisterUI.kt | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 06e21cf..bb8a71f 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -2,11 +2,21 @@ package com.example.frontend.ui.login import android.content.Context import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.material.icons.Icons +import androidx.compose.material.icons.filled.Email import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface @@ -19,12 +29,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext 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 com.example.frontend.api.AuthService import com.example.frontend.model.EmailModel import com.example.frontend.model.RegisterModel @@ -46,7 +54,7 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { Column( - horizontalAlignment = Alignment.CenterHorizontally + modifier = Modifier.padding(20.dp) ) { // TODO(heka1024): 키보드 입력 창에서 '다음' 버튼 등으로 넘어갈 수 있게 하기 @@ -54,40 +62,47 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { // 눌러서 내려가는 건 // 다음을 띄우려면 // imeAction = ImeAction.Next - EmailAuthenticationField( - email = email, - onEmailChanged = { newEmail -> email = newEmail }, - onSendClicked = { sendButtonHandler(context, email, response) }, +// EmailAuthenticationField( +// email = email, +// onEmailChanged = { newEmail -> email = newEmail }, +// onSendClicked = { sendButtonHandler(context, email, response) }, +// ) + + OutlinedTextField( + value = email, + onValueChange = { newEmail -> email = newEmail }, + label = { Text("Email Address") }, + leadingIcon = { + Icon(imageVector = Icons.Default.Email, contentDescription = "Email") + }, ) + Button( + onClick = { sendButtonHandler(context, email, response) }, + colors = ButtonDefaults.buttonColors(Purple80), + modifier = Modifier + .padding(top = 20.dp) + .align(Alignment.End) + ) { Text(text = "Send") } + + // Rightmost button + OutlinedTextField( value = code, onValueChange = { code = it }, label = { Text("Code") }, - modifier = Modifier - .offset(x = (-35).dp) - .background(Color.Transparent) - .width(255.dp) ) OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") }, - modifier = Modifier - .offset(x = (-35).dp) - .background(colorScheme.background) - .width(255.dp) ) OutlinedTextField( value = password, onValueChange = { password = it }, label = { Text("Password") }, - modifier = Modifier - .offset(x = (-35).dp) - .background(colorScheme.background) - .width(255.dp), visualTransformation = PasswordVisualTransformation() ) @@ -106,7 +121,6 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { ) } ) - } } @@ -181,13 +195,16 @@ fun EmailAuthenticationField( Row( modifier = Modifier .fillMaxWidth() - .padding(start = 42.dp, end = 20.dp), + .padding(end = 20.dp), horizontalArrangement = Arrangement.SpaceBetween ) { OutlinedTextField( value = email, onValueChange = onEmailChanged, label = { Text("Email Address") }, + leadingIcon = { + Icon(imageVector = Icons.Default.Email, contentDescription = "Email") + }, modifier = Modifier .padding(end = 8.dp) // Add some padding to separate from the button .width(255.dp) From 3f32ecd6d76f649b87a050b31798c07ef8cb58a9 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 04:14:26 +0900 Subject: [PATCH 02/28] =?UTF-8?q?Validator=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/frontend/utilities/validators.kt | 8 ++++++ .../com/example/frontend/ValidatorsKtTest.kt | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 frontend/app/src/main/java/com/example/frontend/utilities/validators.kt create mode 100644 frontend/app/src/test/java/com/example/frontend/ValidatorsKtTest.kt diff --git a/frontend/app/src/main/java/com/example/frontend/utilities/validators.kt b/frontend/app/src/main/java/com/example/frontend/utilities/validators.kt new file mode 100644 index 0000000..cb98ca6 --- /dev/null +++ b/frontend/app/src/main/java/com/example/frontend/utilities/validators.kt @@ -0,0 +1,8 @@ +package com.example.frontend.utilities + +/* + * @snu.ac.kr 이메일 형식인지 확인하는 함수 + */ +fun isValidSnuMail(email: String): Boolean { + return email.endsWith("@snu.ac.kr") +} \ No newline at end of file diff --git a/frontend/app/src/test/java/com/example/frontend/ValidatorsKtTest.kt b/frontend/app/src/test/java/com/example/frontend/ValidatorsKtTest.kt new file mode 100644 index 0000000..8cf32dc --- /dev/null +++ b/frontend/app/src/test/java/com/example/frontend/ValidatorsKtTest.kt @@ -0,0 +1,27 @@ +package com.example.frontend + +import com.example.frontend.utilities.isValidSnuMail +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + + +class ValidatorsTest { + @Test + fun `isValidSnuMail should return true when email ends with @snu_ac_kr`() { + val email = "test@snu.ac.kr" + + val result = isValidSnuMail(email) + + assertTrue(result) + } + + @Test + fun `isValidSnuMail should return false when email does not end with @snu_ac_kr`() { + val email = "test@gmail.com" + + val result = isValidSnuMail(email) + + assertFalse(result) + } +} \ No newline at end of file From 328d3dd94c61e5d6b2805fd062b569cb99639f8e Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 04:16:40 +0900 Subject: [PATCH 03/28] Add valid mail check --- .../main/java/com/example/frontend/ui/login/RegisterUI.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index bb8a71f..5bc9d5c 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -38,6 +38,7 @@ import com.example.frontend.model.EmailModel import com.example.frontend.model.RegisterModel import com.example.frontend.ui.theme.FrontendTheme import com.example.frontend.ui.theme.Purple80 +import com.example.frontend.utilities.isValidSnuMail import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -51,6 +52,7 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { var response = remember { mutableStateOf("") } var name by remember { mutableStateOf("") } var code by remember { mutableStateOf("") } + val isInitialInput = email.isEmpty() && password.isEmpty() Column( @@ -75,6 +77,8 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { leadingIcon = { Icon(imageVector = Icons.Default.Email, contentDescription = "Email") }, + isError = !isValidSnuMail(email) && !isInitialInput, + supportingText = { if (!isValidSnuMail(email) && !isInitialInput) Text("SNU Mail을 입력해주세요") }, ) Button( @@ -85,8 +89,6 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { .align(Alignment.End) ) { Text(text = "Send") } - // Rightmost button - OutlinedTextField( value = code, onValueChange = { code = it }, From a5db12fa93821bb67ad161300a8b7eca5236bbe0 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 04:22:35 +0900 Subject: [PATCH 04/28] Remove unnecessary code --- .../example/frontend/ui/login/RegisterUI.kt | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 5bc9d5c..97618d3 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -2,15 +2,11 @@ package com.example.frontend.ui.login import android.content.Context import android.widget.Toast -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.material.icons.Icons import androidx.compose.material.icons.filled.Email import androidx.compose.material3.Button @@ -186,39 +182,3 @@ fun RegisterUIPreview() { } } } - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun EmailAuthenticationField( - email: String, - onEmailChanged: (String) -> Unit, - onSendClicked: () -> Unit -) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(end = 20.dp), - horizontalArrangement = Arrangement.SpaceBetween - ) { - OutlinedTextField( - value = email, - onValueChange = onEmailChanged, - label = { Text("Email Address") }, - leadingIcon = { - Icon(imageVector = Icons.Default.Email, contentDescription = "Email") - }, - modifier = Modifier - .padding(end = 8.dp) // Add some padding to separate from the button - .width(255.dp) - ) - - Button( - onClick = onSendClicked, - modifier = Modifier - .align(Alignment.CenterVertically) // Center the button vertically inside the Row - , colors = ButtonDefaults.buttonColors(Purple80) - ) { - Text(text = "Send") - } - } -} From 65d68063c79e1da7386843026854da696d56dcc5 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 04:54:15 +0900 Subject: [PATCH 05/28] Change to emailmodel --- .../app/src/main/java/com/example/frontend/api/AuthService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/src/main/java/com/example/frontend/api/AuthService.kt b/frontend/app/src/main/java/com/example/frontend/api/AuthService.kt index b870b9c..7b64584 100644 --- a/frontend/app/src/main/java/com/example/frontend/api/AuthService.kt +++ b/frontend/app/src/main/java/com/example/frontend/api/AuthService.kt @@ -23,7 +23,7 @@ interface AuthService { fun login(@Body loginModel: LoginModel?): Call? @POST("/verification_mails") - fun verifyEmail(@Body email: String): Call? + fun verifyEmail(@Body email: EmailModel): Call @POST("/users") fun register(@Body registerModel: RegisterModel?): Call From 4fa2055076857371a2688d53f5db4f4c4f7936d3 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 05:04:21 +0900 Subject: [PATCH 06/28] Change test --- .../app/src/test/java/com/example/frontend/LoginUIKtTest.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt b/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt index 2e3e7d2..9c7ff39 100644 --- a/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt +++ b/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt @@ -4,7 +4,6 @@ import android.content.Context import androidx.compose.runtime.mutableStateOf import com.example.frontend.api.AuthService import com.example.frontend.model.AuthResponse -import com.google.android.gms.maps.model.LatLng import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -16,7 +15,6 @@ import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnitRunner import retrofit2.Call import retrofit2.Callback -import retrofit2.Response @RunWith(MockitoJUnitRunner::class) @@ -48,7 +46,7 @@ class LoginUIKtTest { verify(mockCall).enqueue(argumentCaptor.capture()) // Simulate a successful response - val response = Response.success(AuthResponse("token", "username", LatLng(0.0, 0.0))) +// val response = Response.success(AuthResponse("token", "username", LatLng(0.0, 0.0))) // TODO: 테스트 수정 // argumentCaptor.value.onResponse(mockCall, response) // From ca614615d50b72d9c854cf4c36a02a944fe32885 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 05:04:53 +0900 Subject: [PATCH 07/28] Add `HttpStatus` --- .../example/frontend/utilities/HttpStatus.kt | 24 +++++++++++++ .../com/example/frontend/HttpStatusTest.kt | 34 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 frontend/app/src/main/java/com/example/frontend/utilities/HttpStatus.kt create mode 100644 frontend/app/src/test/java/com/example/frontend/HttpStatusTest.kt diff --git a/frontend/app/src/main/java/com/example/frontend/utilities/HttpStatus.kt b/frontend/app/src/main/java/com/example/frontend/utilities/HttpStatus.kt new file mode 100644 index 0000000..f7ffc34 --- /dev/null +++ b/frontend/app/src/main/java/com/example/frontend/utilities/HttpStatus.kt @@ -0,0 +1,24 @@ +package com.example.frontend.utilities + +enum class HttpStatus(val code: Int) { + OK(200), + CREATED(201), + ACCEPTED(202), + NO_CONTENT(204), + BAD_REQUEST(400), + UNAUTHORIZED(401), + FORBIDDEN(403), + NOT_FOUND(404), + UNPROCESSABLE_ENTITY(422), + INTERNAL_SERVER_ERROR(500), + BAD_GATEWAY(502), + SERVICE_UNAVAILABLE(503), + GATEWAY_TIMEOUT(504) + ; + + companion object { + fun fromCode(code: Int): HttpStatus { + return values().find { it.code == code } ?: throw Exception("Invalid HTTP status code: $code") + } + } +} \ No newline at end of file diff --git a/frontend/app/src/test/java/com/example/frontend/HttpStatusTest.kt b/frontend/app/src/test/java/com/example/frontend/HttpStatusTest.kt new file mode 100644 index 0000000..145a768 --- /dev/null +++ b/frontend/app/src/test/java/com/example/frontend/HttpStatusTest.kt @@ -0,0 +1,34 @@ +package com.example.frontend + +import com.example.frontend.utilities.HttpStatus +import org.junit.Assert.assertEquals +import org.junit.Assert.assertThrows +import org.junit.Test + +class HttpStatusTest { + @Test + fun `fromCode returns OK for 200`() { + val status = HttpStatus.fromCode(200) + assertEquals(HttpStatus.OK, status) + } + + @Test + fun `fromCode returns CREATED for 201`() { + val status = HttpStatus.fromCode(201) + assertEquals(HttpStatus.CREATED, status) + } + + @Test + fun `fromCode throws exception for invalid code`() { + assertThrows(Exception::class.java) { + HttpStatus.fromCode(999) + } + } + + @Test + fun `fromCode throws exception for negative code`() { + assertThrows(Exception::class.java) { + HttpStatus.fromCode(-1) + } + } +} From d391bc0ef515a7d2a134608b0e81f62c56d64a2e Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 05:05:04 +0900 Subject: [PATCH 08/28] Add `HttpStatus` Checking --- .../example/frontend/ui/login/RegisterUI.kt | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 97618d3..5b2f290 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -34,6 +34,7 @@ import com.example.frontend.model.EmailModel import com.example.frontend.model.RegisterModel import com.example.frontend.ui.theme.FrontendTheme import com.example.frontend.ui.theme.Purple80 +import com.example.frontend.utilities.HttpStatus import com.example.frontend.utilities.isValidSnuMail import retrofit2.Call import retrofit2.Callback @@ -122,25 +123,29 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { } } -fun sendButtonHandler( +/* + * 서버에게 인증 코드를 요청하는 함수 + */ +private fun sendButtonHandler( context: Context, email: String, result: MutableState, authService: AuthService = AuthService.create() ) { - val emailModel = EmailModel(email) -// val call = authService.verifyEmail(emailModel) -// call!!.enqueue(object : Callback { -// override fun onResponse(call: Call, response: Response) { -// result.value = "Response Code: " + response.code() -// Toast.makeText(context, "이메일을 확인해주세요", Toast.LENGTH_LONG).show() -// } -// -// override fun onFailure(call: Call, t: Throwable) { -// result.value = "Error: " + t.message -// Toast.makeText(context, result.value, Toast.LENGTH_LONG).show() -// } -// }) + authService.verifyEmail(EmailModel(email)).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (HttpStatus.fromCode(response.code()) != HttpStatus.CREATED) { + Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() + return + } else { + Toast.makeText(context, "인증 코드가 전송되었습니다!", Toast.LENGTH_LONG).show() + } + } + + override fun onFailure(call: Call, t: Throwable) { + Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() + } + }) } fun registerButtonHandler( From 447fb9f469f8d30c035663a1a065eaf88f2f8bc4 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 06:06:59 +0900 Subject: [PATCH 09/28] Add indicator --- .../com/example/frontend/ui/login/RegisterUI.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 5b2f290..fa7a6a3 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -49,8 +49,9 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { var response = remember { mutableStateOf("") } var name by remember { mutableStateOf("") } var code by remember { mutableStateOf("") } - val isInitialInput = email.isEmpty() && password.isEmpty() + val isInitialInput = email.isEmpty() && password.isEmpty() + val isWaitingForResponse = remember { mutableStateOf(false) } Column( modifier = Modifier.padding(20.dp) @@ -79,11 +80,12 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { ) Button( - onClick = { sendButtonHandler(context, email, response) }, + onClick = { isWaitingForResponse.value = true; sendButtonHandler(context, email, isWaitingForResponse) }, colors = ButtonDefaults.buttonColors(Purple80), modifier = Modifier .padding(top = 20.dp) - .align(Alignment.End) + .align(Alignment.End), + enabled = !isWaitingForResponse.value, ) { Text(text = "Send") } OutlinedTextField( @@ -129,21 +131,22 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { private fun sendButtonHandler( context: Context, email: String, - result: MutableState, + isWaitingForResponse: MutableState, authService: AuthService = AuthService.create() ) { authService.verifyEmail(EmailModel(email)).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (HttpStatus.fromCode(response.code()) != HttpStatus.CREATED) { Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() - return } else { Toast.makeText(context, "인증 코드가 전송되었습니다!", Toast.LENGTH_LONG).show() } + isWaitingForResponse.value = false } override fun onFailure(call: Call, t: Throwable) { Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() + isWaitingForResponse.value = false } }) } From b51964001a52f539251ef32fc492aa364c22000e Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 06:08:32 +0900 Subject: [PATCH 10/28] Remove warning --- .../src/main/java/com/example/frontend/ui/login/RegisterUI.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index fa7a6a3..ca7b39a 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -43,10 +43,10 @@ import retrofit2.Response @OptIn(ExperimentalMaterial3Api::class) @Composable fun RegisterUI(onSwitchToLogin: () -> Unit) { - var context = LocalContext.current + val context = LocalContext.current var email by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } - var response = remember { mutableStateOf("") } + val response = remember { mutableStateOf("") } var name by remember { mutableStateOf("") } var code by remember { mutableStateOf("") } From 88ab8ffc53f1e0dcbf182c8cf128d854c4661406 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 20:39:48 +0900 Subject: [PATCH 11/28] Optimize import --- .../main/java/com/example/frontend/ui/login/RegisterUI.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 43fd0e7..e7764a9 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -2,17 +2,13 @@ package com.example.frontend.ui.login import android.content.Context import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Email import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api From 0c29530948f4e345fb442b38c4eecd3ccc761967 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 20:42:43 +0900 Subject: [PATCH 12/28] FillMaxWidth --- .../java/com/example/frontend/ui/login/RegisterUI.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index e7764a9..cac19e7 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -5,6 +5,7 @@ import android.widget.Toast import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer 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.material.icons.Icons @@ -78,13 +79,13 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { }, isError = !isValidSnuMail(email) && !isInitialInput, supportingText = { if (!isValidSnuMail(email) && !isInitialInput) Text("SNU Mail을 입력해주세요") }, + modifier = Modifier.fillMaxWidth() ) Button( onClick = { isWaitingForResponse.value = true; sendButtonHandler(context, email, isWaitingForResponse) }, colors = ButtonDefaults.buttonColors(Purple80), modifier = Modifier - .padding(top = 20.dp) .align(Alignment.End), enabled = !isWaitingForResponse.value, ) { Text(text = "Send") } @@ -93,19 +94,22 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { value = code, onValueChange = { code = it }, label = { Text("Code") }, + modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") }, + modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = password, onValueChange = { password = it }, label = { Text("Password") }, - visualTransformation = PasswordVisualTransformation() + visualTransformation = PasswordVisualTransformation(), + modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(30.dp)) @@ -121,7 +125,8 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { response, onSwitchToLogin ) - } + }, + modifier = Modifier.fillMaxWidth(), ) } } From f973e82b053a27e9120f09b3bfc741bc6d5a32db Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 21:19:34 +0900 Subject: [PATCH 13/28] UseCase --- .../example/frontend/ui/login/RegisterUI.kt | 34 +++------------- .../usecase/SendVerificationCodeUseCase.kt | 39 +++++++++++++++++++ 2 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 frontend/app/src/main/java/com/example/frontend/usecase/SendVerificationCodeUseCase.kt diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index cac19e7..7864ddb 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -31,12 +31,11 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.example.frontend.api.AuthService -import com.example.frontend.model.EmailModel import com.example.frontend.model.RegisterModel import com.example.frontend.ui.component.CustomButton import com.example.frontend.ui.theme.FrontendTheme import com.example.frontend.ui.theme.Purple80 -import com.example.frontend.utilities.HttpStatus +import com.example.frontend.usecase.SendVerificationCodeUseCase import com.example.frontend.utilities.isValidSnuMail import retrofit2.Call import retrofit2.Callback @@ -83,7 +82,10 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { ) Button( - onClick = { isWaitingForResponse.value = true; sendButtonHandler(context, email, isWaitingForResponse) }, + onClick = { + isWaitingForResponse.value = true + SendVerificationCodeUseCase(context, email, isWaitingForResponse).execute() + }, colors = ButtonDefaults.buttonColors(Purple80), modifier = Modifier .align(Alignment.End), @@ -131,32 +133,6 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { } } -/* - * 서버에게 인증 코드를 요청하는 함수 - */ -private fun sendButtonHandler( - context: Context, - email: String, - isWaitingForResponse: MutableState, - authService: AuthService = AuthService.create() -) { - authService.verifyEmail(EmailModel(email)).enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - if (HttpStatus.fromCode(response.code()) != HttpStatus.CREATED) { - Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() - } else { - Toast.makeText(context, "인증 코드가 전송되었습니다!", Toast.LENGTH_LONG).show() - } - isWaitingForResponse.value = false - } - - override fun onFailure(call: Call, t: Throwable) { - Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() - isWaitingForResponse.value = false - } - }) -} - fun registerButtonHandler( context: Context, email: String, diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/SendVerificationCodeUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/SendVerificationCodeUseCase.kt new file mode 100644 index 0000000..e030220 --- /dev/null +++ b/frontend/app/src/main/java/com/example/frontend/usecase/SendVerificationCodeUseCase.kt @@ -0,0 +1,39 @@ +package com.example.frontend.usecase + +import android.content.Context +import android.widget.Toast +import androidx.compose.runtime.MutableState +import com.example.frontend.api.AuthService +import com.example.frontend.model.EmailModel +import com.example.frontend.utilities.HttpStatus +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +/* + * 이메일 인증 코드를 보내는 유스케이스 + */ +class SendVerificationCodeUseCase( + private val context: Context, + private val email: String, + private val isWaitingForResponse: MutableState, + private val authService: AuthService = AuthService.create() +) { + fun execute() { + authService.verifyEmail(EmailModel(email)).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (HttpStatus.fromCode(response.code()) != HttpStatus.CREATED) { + Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() + } else { + Toast.makeText(context, "인증 코드가 전송되었습니다!", Toast.LENGTH_LONG).show() + } + isWaitingForResponse.value = false + } + + override fun onFailure(call: Call, t: Throwable) { + Toast.makeText(context, "에러가 발생했어요.", Toast.LENGTH_LONG).show() + isWaitingForResponse.value = false + } + }) + } +} From 7a301908f8c0a828568c472b522589063dcd4b10 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 21:22:15 +0900 Subject: [PATCH 14/28] Refactor usecase --- .../example/frontend/ui/login/RegisterUI.kt | 48 ++----------------- .../frontend/usecase/RegisterUseCase.kt | 40 ++++++++++++++++ 2 files changed, 44 insertions(+), 44 deletions(-) create mode 100644 frontend/app/src/main/java/com/example/frontend/usecase/RegisterUseCase.kt diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 7864ddb..9c6ffbd 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -1,7 +1,5 @@ package com.example.frontend.ui.login -import android.content.Context -import android.widget.Toast import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -19,7 +17,6 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -30,16 +27,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.frontend.api.AuthService -import com.example.frontend.model.RegisterModel import com.example.frontend.ui.component.CustomButton import com.example.frontend.ui.theme.FrontendTheme import com.example.frontend.ui.theme.Purple80 +import com.example.frontend.usecase.RegisterUseCase import com.example.frontend.usecase.SendVerificationCodeUseCase import com.example.frontend.utilities.isValidSnuMail -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -117,48 +110,15 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { Spacer(modifier = Modifier.height(30.dp)) CustomButton( buttonText = "Register", + modifier = Modifier.fillMaxWidth(), onClickHandler = { - registerButtonHandler( - context, - email, - code, - name, - password, - response, - onSwitchToLogin - ) + RegisterUseCase(context, email, code, name, password, response, onSwitchToLogin) + .execute() }, - modifier = Modifier.fillMaxWidth(), ) } } -fun registerButtonHandler( - context: Context, - email: String, - code: String, - name: String, - password: String, - result: MutableState, - onSwitchToLogin: () -> Unit, - authService: AuthService = AuthService.create() -) { - val registerModel = RegisterModel(email, code, name, password) - val call = authService.register(registerModel) - call!!.enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - result.value = "Response Code: " + response.code() - Toast.makeText(context, "회원가입 성공!", Toast.LENGTH_LONG).show() - onSwitchToLogin() - } - - override fun onFailure(call: Call, t: Throwable) { - result.value = "Error: " + t.message - Toast.makeText(context, result.value, Toast.LENGTH_LONG).show() - } - }) -} - @Preview(showBackground = true) @Composable fun RegisterUIPreview() { diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/RegisterUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/RegisterUseCase.kt new file mode 100644 index 0000000..1908a25 --- /dev/null +++ b/frontend/app/src/main/java/com/example/frontend/usecase/RegisterUseCase.kt @@ -0,0 +1,40 @@ +package com.example.frontend.usecase + +import android.content.Context +import android.widget.Toast +import androidx.compose.runtime.MutableState +import com.example.frontend.api.AuthService +import com.example.frontend.model.RegisterModel +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +/* + * 회원 가입을 담당한다 + */ +class RegisterUseCase( + private val context: Context, + private val email: String, + private val code: String, + private val name: String, + private val password: String, + private val result: MutableState, + private val onSwitchToLogin: () -> Unit, + private val authService: AuthService = AuthService.create() +) { + fun execute() { + val registerModel = RegisterModel(email, code, name, password) + authService.register(registerModel).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + result.value = "Response Code: " + response.code() + Toast.makeText(context, "회원가입 성공!", Toast.LENGTH_LONG).show() + onSwitchToLogin() + } + + override fun onFailure(call: Call, t: Throwable) { + result.value = "Error: " + t.message + Toast.makeText(context, result.value, Toast.LENGTH_LONG).show() + } + }) + } +} From 6d5893483bb44ce74ce184fdafd86afb6b70da1a Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 21:22:50 +0900 Subject: [PATCH 15/28] Move usecase to `login` --- .../src/main/java/com/example/frontend/ui/login/LoginUI.kt | 2 +- .../src/main/java/com/example/frontend/ui/login/RegisterUI.kt | 4 ++-- .../com/example/frontend/usecase/{ => login}/LoginUseCase.kt | 4 ++-- .../example/frontend/usecase/{ => login}/RegisterUseCase.kt | 2 +- .../usecase/{ => login}/SendVerificationCodeUseCase.kt | 2 +- .../app/src/test/java/com/example/frontend/LoginUIKtTest.kt | 3 +-- 6 files changed, 8 insertions(+), 9 deletions(-) rename frontend/app/src/main/java/com/example/frontend/usecase/{ => login}/LoginUseCase.kt (98%) rename frontend/app/src/main/java/com/example/frontend/usecase/{ => login}/RegisterUseCase.kt (96%) rename frontend/app/src/main/java/com/example/frontend/usecase/{ => login}/SendVerificationCodeUseCase.kt (97%) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt index af8b49b..6e12681 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.example.frontend.ui.component.CustomButton import com.example.frontend.ui.theme.FrontendTheme -import com.example.frontend.usecase.LoginUseCase +import com.example.frontend.usecase.login.LoginUseCase @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 9c6ffbd..becdb1e 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -30,8 +30,8 @@ import androidx.compose.ui.unit.dp import com.example.frontend.ui.component.CustomButton import com.example.frontend.ui.theme.FrontendTheme import com.example.frontend.ui.theme.Purple80 -import com.example.frontend.usecase.RegisterUseCase -import com.example.frontend.usecase.SendVerificationCodeUseCase +import com.example.frontend.usecase.login.RegisterUseCase +import com.example.frontend.usecase.login.SendVerificationCodeUseCase import com.example.frontend.utilities.isValidSnuMail @OptIn(ExperimentalMaterial3Api::class) diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/LoginUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt similarity index 98% rename from frontend/app/src/main/java/com/example/frontend/usecase/LoginUseCase.kt rename to frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt index 458c3de..67cae17 100644 --- a/frontend/app/src/main/java/com/example/frontend/usecase/LoginUseCase.kt +++ b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt @@ -1,4 +1,4 @@ -package com.example.frontend.usecase +package com.example.frontend.usecase.login import android.app.Activity import android.content.Context @@ -98,4 +98,4 @@ class LoginUseCase( apply() } } -} \ No newline at end of file +} diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/RegisterUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/login/RegisterUseCase.kt similarity index 96% rename from frontend/app/src/main/java/com/example/frontend/usecase/RegisterUseCase.kt rename to frontend/app/src/main/java/com/example/frontend/usecase/login/RegisterUseCase.kt index 1908a25..83ef286 100644 --- a/frontend/app/src/main/java/com/example/frontend/usecase/RegisterUseCase.kt +++ b/frontend/app/src/main/java/com/example/frontend/usecase/login/RegisterUseCase.kt @@ -1,4 +1,4 @@ -package com.example.frontend.usecase +package com.example.frontend.usecase.login import android.content.Context import android.widget.Toast diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/SendVerificationCodeUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/login/SendVerificationCodeUseCase.kt similarity index 97% rename from frontend/app/src/main/java/com/example/frontend/usecase/SendVerificationCodeUseCase.kt rename to frontend/app/src/main/java/com/example/frontend/usecase/login/SendVerificationCodeUseCase.kt index e030220..a861929 100644 --- a/frontend/app/src/main/java/com/example/frontend/usecase/SendVerificationCodeUseCase.kt +++ b/frontend/app/src/main/java/com/example/frontend/usecase/login/SendVerificationCodeUseCase.kt @@ -1,4 +1,4 @@ -package com.example.frontend.usecase +package com.example.frontend.usecase.login import android.content.Context import android.widget.Toast diff --git a/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt b/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt index 2cd57f9..771de13 100644 --- a/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt +++ b/frontend/app/src/test/java/com/example/frontend/LoginUIKtTest.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.compose.runtime.mutableStateOf import com.example.frontend.api.AuthService import com.example.frontend.model.AuthResponse -import com.example.frontend.usecase.LoginUseCase +import com.example.frontend.usecase.login.LoginUseCase import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -16,7 +16,6 @@ import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnitRunner import retrofit2.Call import retrofit2.Callback -import retrofit2.Response @RunWith(MockitoJUnitRunner::class) From eb95522a4ff0a9764606cc6a8b4eafbfd24a0143 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 21:37:35 +0900 Subject: [PATCH 16/28] Add Next Buttons --- .../example/frontend/ui/login/RegisterUI.kt | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index becdb1e..507bf55 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -6,6 +6,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.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Email import androidx.compose.material3.Button @@ -24,6 +25,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -85,18 +88,26 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { enabled = !isWaitingForResponse.value, ) { Text(text = "Send") } + // Only number and upper case alphabet OutlinedTextField( value = code, onValueChange = { code = it }, label = { Text("Code") }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + keyboardOptions = KeyboardOptions( + capitalization = KeyboardCapitalization.Characters, + imeAction = ImeAction.Next, + ), ) OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Next, + ) ) OutlinedTextField( @@ -104,7 +115,10 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { onValueChange = { password = it }, label = { Text("Password") }, visualTransformation = PasswordVisualTransformation(), - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Done, + ) ) Spacer(modifier = Modifier.height(30.dp)) From d11c1192722a3fadd4cbf2bab18d06a0fee15623 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Mon, 4 Dec 2023 21:50:17 +0900 Subject: [PATCH 17/28] Add keyboardOptions --- .../com/example/frontend/ui/login/LoginUI.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt index 6e12681..5c2b75a 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Email import androidx.compose.material.icons.filled.Lock @@ -21,6 +22,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -43,11 +45,12 @@ fun LoginUI() { value = email, onValueChange = { email = it }, label = { Text("Email Address") }, - leadingIcon = { - Icon(imageVector = Icons.Default.Email, contentDescription = null) - }, + leadingIcon = { Icon(imageVector = Icons.Default.Email, contentDescription = null) }, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) ) + Spacer(modifier = Modifier.height(20.dp)) + OutlinedTextField( value = password, onValueChange = { password = it }, @@ -55,9 +58,14 @@ fun LoginUI() { leadingIcon = { Icon(imageVector = Icons.Default.Lock, contentDescription = null) }, - visualTransformation = PasswordVisualTransformation() + visualTransformation = PasswordVisualTransformation(), + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Done + ) ) + Spacer(modifier = Modifier.height(140.dp)) + CustomButton( buttonText = "Login", onClickHandler = { LoginUseCase(context, email, password, response).execute() } From 09b9a510d7dab92c213d19fa3ed3981b87dc050d Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:04:20 +0900 Subject: [PATCH 18/28] Add encrypted Store --- .../EncryptedSharedPreferenceKVStore.kt | 28 +++++++++++++++++++ .../utilities/SharedPreferenceKVStore.kt | 4 +-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 frontend/app/src/main/java/com/example/frontend/utilities/EncryptedSharedPreferenceKVStore.kt diff --git a/frontend/app/src/main/java/com/example/frontend/utilities/EncryptedSharedPreferenceKVStore.kt b/frontend/app/src/main/java/com/example/frontend/utilities/EncryptedSharedPreferenceKVStore.kt new file mode 100644 index 0000000..f6946ab --- /dev/null +++ b/frontend/app/src/main/java/com/example/frontend/utilities/EncryptedSharedPreferenceKVStore.kt @@ -0,0 +1,28 @@ +package com.example.frontend.utilities + +import android.content.Context +import android.content.SharedPreferences +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey + +/* + * KVStore implementation using SharedPreference, which is encrypted + */ +class EncryptedSharedPreferenceKVStore(context: Context) : SharedPreferenceKVStore(context) { + private val masterKey = MasterKey.Builder(context) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + + override val appPrefs: SharedPreferences = + EncryptedSharedPreferences.create( + context, + APP_PREFS, + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ) + + companion object { + private const val APP_PREFS = "secure_app_prefs" + } +} diff --git a/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt b/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt index e6d2a75..9026d2a 100644 --- a/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt +++ b/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt @@ -6,8 +6,8 @@ import android.content.SharedPreferences /* * KVStore implementation using SharedPreference */ -class SharedPreferenceKVStore(context: Context) : KVStore { - private val appPrefs: SharedPreferences = +open class SharedPreferenceKVStore(context: Context) : KVStore { + protected open val appPrefs: SharedPreferences = context.getSharedPreferences(APP_PREFS, Context.MODE_PRIVATE) override fun getString(key: String): String? { From ca89e2633e6a5d4db6ffd8b421e26f1ef1a56b78 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:04:42 +0900 Subject: [PATCH 19/28] Add option to `ofContext` --- .../frontend/repository/UserContextRepository.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt index 4cd019f..03e29a0 100644 --- a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt +++ b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt @@ -1,6 +1,7 @@ package com.example.frontend.repository import android.content.Context +import com.example.frontend.utilities.EncryptedSharedPreferenceKVStore import com.example.frontend.utilities.KVStore import com.example.frontend.utilities.SharedPreferenceKVStore @@ -39,9 +40,12 @@ class UserContextRepository( /* * Returns UserContextRepository instance backed by SharedPreferenceKVStore. */ - fun ofContext(context: Context): UserContextRepository { - val sharedPreferencesKVStore = SharedPreferenceKVStore(context) - return UserContextRepository(sharedPreferencesKVStore) + fun ofContext(context: Context, secure: Boolean = false): UserContextRepository { + val store = if (secure) + EncryptedSharedPreferenceKVStore(context) + else + SharedPreferenceKVStore(context) + return UserContextRepository(store) } private const val USERNAME = "USERNAME" From ca7940705479c39abff0ba6dbe9574b17d38c971 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:04:52 +0900 Subject: [PATCH 20/28] Use repository --- .../frontend/repository/UserContextRepository.kt | 4 ++++ .../example/frontend/usecase/login/LoginUseCase.kt | 11 ++++++++--- .../com/example/frontend/UserContextRepositoryTest.kt | 8 ++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt index 03e29a0..ef11998 100644 --- a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt +++ b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt @@ -25,6 +25,10 @@ class UserContextRepository( return store.getString(AUTH_TOKEN) ?: "" } + fun saveAuthToken(token: String) { + store.putString(AUTH_TOKEN, token) + } + fun saveSelectedPredefinedImage(imageId: Int?) { if (imageId != null && imageId != KVStore.DEFAULT_INT) { store.putInt(SELECTED_PREDEFINED_IMAGE, imageId) diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt index 1db99f6..f26038c 100644 --- a/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt +++ b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt @@ -11,6 +11,7 @@ import com.example.frontend.MapActivity import com.example.frontend.api.AuthService import com.example.frontend.model.AuthResponse import com.example.frontend.model.LoginModel +import com.example.frontend.repository.UserContextRepository import com.example.frontend.utilities.BYPASS_LOGIN import retrofit2.Call import retrofit2.Callback @@ -46,7 +47,7 @@ class LoginUseCase( val userProfile = response.body()?.userProfile if (authToken != null) { - saveAuthToken(authToken, userName, userMail, userProfile?:-1) + saveAuthToken(authToken, userName, userMail, userProfile ?: -1) } result.value = "Logged in successfully" @@ -73,11 +74,14 @@ class LoginUseCase( // To save the auth token securely when logging in - private fun saveAuthToken(authToken: String, userName: String?, userMail: String?, userProfile :Int) { + private fun saveAuthToken(authToken: String, userName: String?, userMail: String?, userProfile: Int) { val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() + val encryptedUserRepo = UserContextRepository.ofContext(context, secure = true) + val userRepo = UserContextRepository.ofContext(context, secure = false) + val sharedPreferences = EncryptedSharedPreferences.create( context, "secure_app_prefs", @@ -86,9 +90,10 @@ class LoginUseCase( EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) + encryptedUserRepo.saveAuthToken(authToken) + // Save auth token securely with(sharedPreferences.edit()) { - putString("AUTH_TOKEN", authToken) putString("USERNAME", userName) putString("USER_MAIL", userMail) putInt("SELECTED_PREDEFINED_IMAGE", userProfile) diff --git a/frontend/app/src/test/java/com/example/frontend/UserContextRepositoryTest.kt b/frontend/app/src/test/java/com/example/frontend/UserContextRepositoryTest.kt index 65a1fad..df24a98 100644 --- a/frontend/app/src/test/java/com/example/frontend/UserContextRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/frontend/UserContextRepositoryTest.kt @@ -64,4 +64,12 @@ class UserContextRepositoryTest { val imageId = userContextRepository.getSelectedPredefinedImage() assertNull(imageId) } + + @Test + fun `saveAuthToken should save token to store`() { + val expectedToken = "testToken" + userContextRepository.saveAuthToken(expectedToken) + val token = userContextRepository.getAuthToken() + assertEquals(expectedToken, token) + } } From 76f740bac21bba1b6f89e79518a3b29814ba6ca3 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:09:05 +0900 Subject: [PATCH 21/28] Refactor using Repository --- .../repository/UserContextRepository.kt | 9 ++++ .../frontend/usecase/login/LoginUseCase.kt | 52 +++++-------------- 2 files changed, 22 insertions(+), 39 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt index ef11998..4b288be 100644 --- a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt +++ b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt @@ -40,6 +40,14 @@ class UserContextRepository( return if (imageId != KVStore.DEFAULT_INT) imageId else null } + fun saveUserMail(userMail: String) { + store.putString(USER_MAIL, userMail) + } + + fun saveIsLoggedIn(isLoggedIn: Boolean) { + store.putBoolean(IS_LOGGED_IN, isLoggedIn) + } + companion object { /* * Returns UserContextRepository instance backed by SharedPreferenceKVStore. @@ -58,5 +66,6 @@ class UserContextRepository( const val DEFAULT_USER_MAIL = "shaf@snu.ac.kr" private const val AUTH_TOKEN = "AUTH_TOKEN" private const val SELECTED_PREDEFINED_IMAGE = "SELECTED_PREDEFINED_IMAGE" + private cosnt val IS_LOGGED_IN = "IS_LOGGED_IN" } } diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt index f26038c..f00bbd2 100644 --- a/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt +++ b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt @@ -5,8 +5,6 @@ import android.content.Context import android.content.Intent import android.widget.Toast import androidx.compose.runtime.MutableState -import androidx.security.crypto.EncryptedSharedPreferences -import androidx.security.crypto.MasterKey import com.example.frontend.MapActivity import com.example.frontend.api.AuthService import com.example.frontend.model.AuthResponse @@ -41,14 +39,12 @@ class LoginUseCase( call!!.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful && response.body() != null) { - val authToken = response.body()?.token - val userName = response.body()?.userName - val userMail = response.body()?.userMail + val authToken = response.body()?.token ?: throw Exception("authToken is null") + val userName = response.body()?.userName ?: throw Exception("userName is null") + val userMail = response.body()?.userMail ?: throw Exception("userMail is null") val userProfile = response.body()?.userProfile - if (authToken != null) { - saveAuthToken(authToken, userName, userMail, userProfile ?: -1) - } + saveAuthToken(authToken, userName, userMail, userProfile ?: -1) result.value = "Logged in successfully" val nextIntent = Intent(context, MapActivity::class.java) @@ -74,38 +70,16 @@ class LoginUseCase( // To save the auth token securely when logging in - private fun saveAuthToken(authToken: String, userName: String?, userMail: String?, userProfile: Int) { - val masterKey = MasterKey.Builder(context) - .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) - .build() - - val encryptedUserRepo = UserContextRepository.ofContext(context, secure = true) - val userRepo = UserContextRepository.ofContext(context, secure = false) - - val sharedPreferences = EncryptedSharedPreferences.create( - context, - "secure_app_prefs", - masterKey, - EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, - EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM - ) - - encryptedUserRepo.saveAuthToken(authToken) - - // Save auth token securely - with(sharedPreferences.edit()) { - putString("USERNAME", userName) - putString("USER_MAIL", userMail) - putInt("SELECTED_PREDEFINED_IMAGE", userProfile) - apply() - } + private fun saveAuthToken(authToken: String, userName: String, userMail: String, userProfile: Int) { + UserContextRepository + .ofContext(context, secure = true) + .saveAuthToken(authToken) - // Update login state - val appPrefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) - with(appPrefs.edit()) { - putBoolean("IS_LOGGED_IN", true) - putString("USERNAME", userName) - apply() + UserContextRepository.ofContext(context, secure = false).apply { + saveUserName(userName) + saveUserMail(userMail) + saveSelectedPredefinedImage(userProfile) + saveIsLoggedIn(true) } } } From c94dc4602d92af23bd34b26571a518b9a3b6db66 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:10:39 +0900 Subject: [PATCH 22/28] Add boolean interface --- .../frontend/repository/UserContextRepository.kt | 2 +- .../com/example/frontend/utilities/InMemoryKVStore.kt | 8 ++++++++ .../java/com/example/frontend/utilities/KVStore.kt | 3 +++ .../frontend/utilities/SharedPreferenceKVStore.kt | 10 ++++++++++ .../java/com/example/frontend/InMemoryKVStoreTest.kt | 11 +++++++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt index 4b288be..6b2eb17 100644 --- a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt +++ b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt @@ -66,6 +66,6 @@ class UserContextRepository( const val DEFAULT_USER_MAIL = "shaf@snu.ac.kr" private const val AUTH_TOKEN = "AUTH_TOKEN" private const val SELECTED_PREDEFINED_IMAGE = "SELECTED_PREDEFINED_IMAGE" - private cosnt val IS_LOGGED_IN = "IS_LOGGED_IN" + private const val IS_LOGGED_IN = "IS_LOGGED_IN" } } diff --git a/frontend/app/src/main/java/com/example/frontend/utilities/InMemoryKVStore.kt b/frontend/app/src/main/java/com/example/frontend/utilities/InMemoryKVStore.kt index 104e799..e3047fa 100644 --- a/frontend/app/src/main/java/com/example/frontend/utilities/InMemoryKVStore.kt +++ b/frontend/app/src/main/java/com/example/frontend/utilities/InMemoryKVStore.kt @@ -18,4 +18,12 @@ class InMemoryKVStore : KVStore { override fun putInt(key: String, value: Int) { store[key] = value } + + override fun getBoolean(key: String): Boolean? { + return store[key] as? Boolean + } + + override fun putBoolean(key: String, value: Boolean) { + store[key] = value + } } diff --git a/frontend/app/src/main/java/com/example/frontend/utilities/KVStore.kt b/frontend/app/src/main/java/com/example/frontend/utilities/KVStore.kt index ac3de7b..c16578f 100644 --- a/frontend/app/src/main/java/com/example/frontend/utilities/KVStore.kt +++ b/frontend/app/src/main/java/com/example/frontend/utilities/KVStore.kt @@ -10,6 +10,9 @@ interface KVStore { fun getInt(key: String): Int? fun putInt(key: String, value: Int) + fun getBoolean(key: String): Boolean? + fun putBoolean(key: String, value: Boolean) + companion object { const val DEFAULT_INT = -1 } diff --git a/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt b/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt index 9026d2a..007e141 100644 --- a/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt +++ b/frontend/app/src/main/java/com/example/frontend/utilities/SharedPreferenceKVStore.kt @@ -30,6 +30,16 @@ open class SharedPreferenceKVStore(context: Context) : KVStore { editor.apply() } + override fun getBoolean(key: String): Boolean? { + return appPrefs.getBoolean(key, false) + } + + override fun putBoolean(key: String, value: Boolean) { + val editor = appPrefs.edit() + editor.putBoolean(key, value) + editor.apply() + } + companion object { const val APP_PREFS = "app_prefs" } diff --git a/frontend/app/src/test/java/com/example/frontend/InMemoryKVStoreTest.kt b/frontend/app/src/test/java/com/example/frontend/InMemoryKVStoreTest.kt index e8f1ed8..351d265 100644 --- a/frontend/app/src/test/java/com/example/frontend/InMemoryKVStoreTest.kt +++ b/frontend/app/src/test/java/com/example/frontend/InMemoryKVStoreTest.kt @@ -48,4 +48,15 @@ class InMemoryKVStoreTest { kvStore.putInt("key", 123) assertEquals(123, kvStore.getInt("key")) } + + @Test + fun `getBoolean returns null when key does not exist`() { + assertNull(kvStore.getBoolean("nonexistentKey")) + } + + @Test + fun `getBoolean returns value when key exists`() { + kvStore.putBoolean("key", true) + assertEquals(true, kvStore.getBoolean("key")) + } } From 080fca0d5e7ae13655abef370596c944be910d2a Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:14:15 +0900 Subject: [PATCH 23/28] UseContextRepo --- .../java/com/example/frontend/SplashScreenActivity.kt | 8 +++----- .../example/frontend/repository/UserContextRepository.kt | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/SplashScreenActivity.kt b/frontend/app/src/main/java/com/example/frontend/SplashScreenActivity.kt index 9096b06..8e1266b 100644 --- a/frontend/app/src/main/java/com/example/frontend/SplashScreenActivity.kt +++ b/frontend/app/src/main/java/com/example/frontend/SplashScreenActivity.kt @@ -1,10 +1,10 @@ package com.example.frontend import android.annotation.SuppressLint -import android.content.Context import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import com.example.frontend.repository.UserContextRepository import com.example.frontend.ui.login.LoginActivity @SuppressLint("CustomSplashScreen") @@ -13,11 +13,9 @@ class SplashScreenActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // Check if the user is already logged in - val sharedPreferences = getSharedPreferences("app_prefs", Context.MODE_PRIVATE) - val isLoggedIn = sharedPreferences.getBoolean("IS_LOGGED_IN", false) + val userContextRepository = UserContextRepository.ofContext(this) - if (isLoggedIn) { + if (userContextRepository.getIsLoggedIn()) { // User is already logged in, skip the login activity startActivity(Intent(this, MapActivity::class.java)) } else { diff --git a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt index 6b2eb17..fbdb2eb 100644 --- a/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt +++ b/frontend/app/src/main/java/com/example/frontend/repository/UserContextRepository.kt @@ -48,6 +48,10 @@ class UserContextRepository( store.putBoolean(IS_LOGGED_IN, isLoggedIn) } + fun getIsLoggedIn(): Boolean { + return store.getBoolean(IS_LOGGED_IN) ?: false + } + companion object { /* * Returns UserContextRepository instance backed by SharedPreferenceKVStore. From 2926de0d441b6dc03020794c2e43bc74f0d1f201 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:28:14 +0900 Subject: [PATCH 24/28] =?UTF-8?q?`AuthResponse`=20=EA=B0=84=EC=86=8C?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/frontend/model/AuthResponse.kt | 8 +------- .../frontend/usecase/login/LoginUseCase.kt | 18 ++++-------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/model/AuthResponse.kt b/frontend/app/src/main/java/com/example/frontend/model/AuthResponse.kt index 504cc8a..c165fdc 100644 --- a/frontend/app/src/main/java/com/example/frontend/model/AuthResponse.kt +++ b/frontend/app/src/main/java/com/example/frontend/model/AuthResponse.kt @@ -1,11 +1,5 @@ package com.example.frontend.model -import com.google.android.gms.maps.model.LatLng - data class AuthResponse( val token: String, - val userName: String, - val userCurrentLocation: LatLng?, - val userMail: String, - val userProfile: Int -) \ No newline at end of file +) diff --git a/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt index f00bbd2..95a909d 100644 --- a/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt +++ b/frontend/app/src/main/java/com/example/frontend/usecase/login/LoginUseCase.kt @@ -27,7 +27,6 @@ class LoginUseCase( ) { fun execute() { val loginModel = LoginModel(email, password) - val call = authService.login(loginModel) if (BYPASS_LOGIN) { // TODO(heka1024): Remove this flag val nextIntent = Intent(context, MapActivity::class.java) @@ -36,15 +35,13 @@ class LoginUseCase( context.finish() } } - call!!.enqueue(object : Callback { + + authService.login(loginModel)!!.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful && response.body() != null) { val authToken = response.body()?.token ?: throw Exception("authToken is null") - val userName = response.body()?.userName ?: throw Exception("userName is null") - val userMail = response.body()?.userMail ?: throw Exception("userMail is null") - val userProfile = response.body()?.userProfile - saveAuthToken(authToken, userName, userMail, userProfile ?: -1) + saveAuthToken(authToken) result.value = "Logged in successfully" val nextIntent = Intent(context, MapActivity::class.java) @@ -70,16 +67,9 @@ class LoginUseCase( // To save the auth token securely when logging in - private fun saveAuthToken(authToken: String, userName: String, userMail: String, userProfile: Int) { + private fun saveAuthToken(authToken: String) { UserContextRepository .ofContext(context, secure = true) .saveAuthToken(authToken) - - UserContextRepository.ofContext(context, secure = false).apply { - saveUserName(userName) - saveUserMail(userMail) - saveSelectedPredefinedImage(userProfile) - saveIsLoggedIn(true) - } } } From 42d0c73c1e424a3fdae11957fa3d88afb8a3bc29 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:32:01 +0900 Subject: [PATCH 25/28] =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/frontend/ui/login/RegisterUI.kt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt index 507bf55..a7d5b99 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/RegisterUI.kt @@ -11,7 +11,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Email import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.OutlinedTextField @@ -37,7 +36,6 @@ import com.example.frontend.usecase.login.RegisterUseCase import com.example.frontend.usecase.login.SendVerificationCodeUseCase import com.example.frontend.utilities.isValidSnuMail -@OptIn(ExperimentalMaterial3Api::class) @Composable fun RegisterUI(onSwitchToLogin: () -> Unit) { val context = LocalContext.current @@ -53,18 +51,6 @@ fun RegisterUI(onSwitchToLogin: () -> Unit) { Column( modifier = Modifier.padding(20.dp) ) { - - // TODO(heka1024): 키보드 입력 창에서 '다음' 버튼 등으로 넘어갈 수 있게 하기 - // TODO(heka1024): 터치할 때 키보드 내려가게 하게 - // 눌러서 내려가는 건 - // 다음을 띄우려면 - // imeAction = ImeAction.Next -// EmailAuthenticationField( -// email = email, -// onEmailChanged = { newEmail -> email = newEmail }, -// onSendClicked = { sendButtonHandler(context, email, response) }, -// ) - OutlinedTextField( value = email, onValueChange = { newEmail -> email = newEmail }, From 1a3a7b65fae42a6c9e21f6635c2f7b7114521721 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:32:41 +0900 Subject: [PATCH 26/28] Change arg --- .../src/main/java/com/example/frontend/ui/login/LoginScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginScreen.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginScreen.kt index b914c4a..4fa0317 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginScreen.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginScreen.kt @@ -80,7 +80,7 @@ fun LoginScreen() { when (currentComponent.value) { LoginComponent.LOGIN -> LoginUI() - LoginComponent.REGISTER -> RegisterUI(onRegisterClick) + LoginComponent.REGISTER -> RegisterUI(onLoginClick) } } } From d65d27050c399da62463082cca1f1c870da100f1 Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:37:51 +0900 Subject: [PATCH 27/28] Add keyboardAction --- .../src/main/java/com/example/frontend/ui/login/LoginUI.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt index 5c2b75a..895e8bd 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height +import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Email @@ -61,6 +62,9 @@ fun LoginUI() { visualTransformation = PasswordVisualTransformation(), keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { LoginUseCase(context, email, password, response).execute() } ) ) From 4024cf0e1b0604cf34c04c4f42585a71777d37ae Mon Sep 17 00:00:00 2001 From: heka1024 Date: Wed, 6 Dec 2023 20:38:05 +0900 Subject: [PATCH 28/28] Code review --- .../src/main/java/com/example/frontend/ui/login/LoginUI.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt index 895e8bd..823411b 100644 --- a/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt +++ b/frontend/app/src/main/java/com/example/frontend/ui/login/LoginUI.kt @@ -34,10 +34,10 @@ import com.example.frontend.usecase.login.LoginUseCase @OptIn(ExperimentalMaterial3Api::class) @Composable fun LoginUI() { - var context = LocalContext.current + val context = LocalContext.current var email by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } - var response = remember { mutableStateOf("") } + val response = remember { mutableStateOf("") } Column( horizontalAlignment = Alignment.CenterHorizontally