Skip to content

Commit

Permalink
[feat/#8] 유저 로그인 api 연동
Browse files Browse the repository at this point in the history
  • Loading branch information
hwidung committed Nov 12, 2024
1 parent d582891 commit 5d1a2b7
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 96 deletions.
6 changes: 6 additions & 0 deletions app/src/main/java/org/sopt/and/data/api/ApiFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,10 @@ object ApiFactory {
return retrofit.create(UserRegistrationService::class.java)
}

@Provides
@Singleton
fun provideLoginService(retrofit: Retrofit): LoginService {
return retrofit.create(LoginService::class.java)
}

}
27 changes: 27 additions & 0 deletions app/src/main/java/org/sopt/and/data/api/AuthService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.sopt.and.data.api

import org.sopt.and.data.dto.RequestLoginData
import org.sopt.and.data.dto.RequestUserRegistrationData
import org.sopt.and.data.dto.ResponseLogin
import org.sopt.and.data.dto.ResponseUserRegistration
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST


interface UserRegistrationService {
@POST("/user")
suspend fun postUserRegistration(
@Body userRequest: RequestUserRegistrationData
): Response<ResponseUserRegistration>
}

interface LoginService {
@POST("/login")
suspend fun postLogin(
@Body loginRequeset: RequestLoginData
): Response<ResponseLogin>
}



15 changes: 0 additions & 15 deletions app/src/main/java/org/sopt/and/data/api/UserRegistrationService.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package org.sopt.and.data.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/* 유저 등록 */
@Serializable
data class RequestUserRegistration(
data class RequestUserRegistrationData(
@SerialName("username")
val userName: String,
@SerialName("password")
Expand All @@ -16,11 +17,32 @@ data class RequestUserRegistration(
@Serializable
data class ResponseUserRegistration(
@SerialName("result")
val result: ResultUserNo?
val result: ResultUserNo
)

@Serializable
data class ResultUserNo(
@SerialName("no")
val no: Int
)

/* 로그인 */
@Serializable
data class RequestLoginData(
@SerialName("username")
val userName: String,
@SerialName("password")
val password: String
)

@Serializable
data class ResponseLogin(
@SerialName("result")
val result: ResultToken
)

@Serializable
data class ResultToken(
@SerialName("token")
val token: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.sopt.and.data.repository.Auth

import org.sopt.and.data.api.LoginService
import org.sopt.and.data.dto.RequestLoginData
import org.sopt.and.data.dto.ResponseLogin
import javax.inject.Inject

class LoginRepository @Inject constructor(
private val apiService: LoginService
) {
suspend fun postLogin(requestData: RequestLoginData): Result<ResponseLogin> {
return try {
val response = apiService.postLogin(requestData)
if (response.isSuccessful) {
Result.success(response.body()!!)
} else {
val errorCode = response.errorBody()?.string() ?: "알수없슴"
Result.failure(Exception("Error code : ${response.code()}, 에러 코드 : $errorCode"))
}
} catch (e: Exception) {
Result.failure(e)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package org.sopt.and.data.repository
package org.sopt.and.data.repository.Auth

import org.sopt.and.data.api.UserRegistrationService
import org.sopt.and.data.dto.RequestUserRegistration
import org.sopt.and.data.dto.RequestUserRegistrationData
import org.sopt.and.data.dto.ResponseUserRegistration
import javax.inject.Inject

class UserRegistrationRepository @Inject constructor(
private val apiService: UserRegistrationService
) {
suspend fun registerUser(userRequest: RequestUserRegistration): Result<ResponseUserRegistration> {
suspend fun postUserRegistration(requestData: RequestUserRegistrationData): Result<ResponseUserRegistration> {
return try {
val response = apiService.registerUser(userRequest)
val response = apiService.postUserRegistration(requestData)
if (response.isSuccessful) {
Result.success(response.body()!!)
} else {
Expand Down
63 changes: 30 additions & 33 deletions app/src/main/java/org/sopt/and/presentation/ui/auth/SignInScreen.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.sopt.and.presentation.ui.auth

import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -15,6 +16,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
Expand All @@ -28,7 +30,6 @@ import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import kotlinx.coroutines.launch
Expand All @@ -39,26 +40,18 @@ import org.sopt.and.presentation.ui.auth.component.AuthTextField
import org.sopt.and.presentation.ui.auth.component.ServiceIconRow
import org.sopt.and.presentation.ui.auth.component.TextFieldValidateResult
import org.sopt.and.presentation.viewmodel.SignInViewModel
import org.sopt.and.presentation.viewmodel.SignInViewModelFactory
import org.sopt.and.presentation.viewmodel.SignUpViewModel


@Composable
fun SignInScreen(
signUpViewModel: SignUpViewModel = hiltViewModel(),
signInViewModel: SignInViewModel = hiltViewModel(),
navController: NavHostController
) {

val factory = SignInViewModelFactory(signUpViewModel)
val signInViewModel: SignInViewModel = viewModel(factory = factory)
val signInResult by signInViewModel.loginResult.observeAsState()

var isPasswordVisible by remember { mutableStateOf(false) }

val snackbarHostState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()



Column(
modifier = Modifier
.background(color = Color.Black)
Expand Down Expand Up @@ -98,14 +91,14 @@ fun SignInScreen(
) {

AuthTextField(
value = signInViewModel.emailLogin,
onValueChange = { signInViewModel.updateEmailLogin(it) },
value = signInViewModel.username,
onValueChange = { signInViewModel.updateUsernameLogin(it) },
placeholder = "이메일 주소 또는 아이디",
validateState = TextFieldValidateResult.Basic
)
Spacer(modifier = Modifier.height(20.dp))
AuthTextField(
value = signInViewModel.passwordLogin,
value = signInViewModel.password,
onValueChange = { signInViewModel.updatePasswordLogin(it) },
placeholder = "비밀번호",
validateState = TextFieldValidateResult.Basic,
Expand All @@ -127,32 +120,36 @@ fun SignInScreen(
AuthButton(
text = "로그인",
onClick = {
if (signInViewModel.validateSignIn()
) {
coroutineScope.launch {
snackbarHostState.showSnackbar("로그인 성공!")
}
navController.navigate(AuthNavItem.Main.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
}
} else {
coroutineScope.launch {
snackbarHostState.showSnackbar("로그인 실패!")
signInViewModel.postLogin(
signInViewModel.username,
signInViewModel.password
)
}
)
signInResult?.let { result ->
if (result.isSuccess) {
// 토큰 받아와서 저장
coroutineScope.launch {
snackbarHostState.showSnackbar("로그인 성공!")
}
navController.navigate(AuthNavItem.Main.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
}
} else {
coroutineScope.launch {
snackbarHostState.showSnackbar("로그인 실패!")
}
val errorMessage = result.exceptionOrNull()?.message ?: "로그인 실패!!"
Log.e("signInScreen", errorMessage)
}
)

}
AuthServiceDescription()
ServiceIconRow()

}
}


}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,47 @@ package org.sopt.and.presentation.viewmodel
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class SignInViewModel(
private val signUpViewModel: SignUpViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import org.sopt.and.data.dto.RequestLoginData
import org.sopt.and.data.dto.ResponseLogin
import org.sopt.and.data.repository.Auth.LoginRepository
import javax.inject.Inject

@HiltViewModel
class SignInViewModel @Inject constructor(
private val loginRepository: LoginRepository
) : ViewModel() {

private var _emailLogin by mutableStateOf("")
val emailLogin: String
get() = _emailLogin

private var _passwordLogin by mutableStateOf("")
val passwordLogin: String
get() = _passwordLogin

var emailError by mutableStateOf("")
var passwordError by mutableStateOf("")
private val _loginResult = MutableLiveData<Result<ResponseLogin>>()
val loginResult: LiveData<Result<ResponseLogin>> get() = _loginResult

fun updateEmailLogin(newEmail: String) {
_emailLogin = newEmail
validateEmail()
fun postLogin(username: String, password: String) {
viewModelScope.launch {
val loginRequest = RequestLoginData(username, password)
val result = loginRepository.postLogin(loginRequest)
_loginResult.postValue(result)
}
}

fun updatePasswordLogin(newPassword: String) {
_passwordLogin = newPassword
validatePassword()
}
private var _username by mutableStateOf("")
val username: String
get() = _username

fun validateEmail() {
emailError = if (emailLogin.isEmpty()) "이메일을 입력하세요." else ""
}
private var _password by mutableStateOf("")
val password: String
get() = _password

fun validatePassword() {
passwordError = if (passwordLogin.isEmpty()) "비밀번호를 입력하세요." else ""
fun updateUsernameLogin(username: String) {
_username = username
}

fun validateSignIn(): Boolean =
emailLogin == signUpViewModel.username && passwordLogin == signUpViewModel.password
fun updatePasswordLogin(password: String) {
_password = password
}

}

class SignInViewModelFactory(private val signUpViewmodel: SignUpViewModel) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(SignInViewModel::class.java)) {
return SignInViewModel(signUpViewmodel) as T
}
throw IllegalArgumentException("알 수 없는 뷰 모델 클래스")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import org.sopt.and.data.dto.RequestUserRegistration
import org.sopt.and.data.dto.RequestUserRegistrationData
import org.sopt.and.data.dto.ResponseUserRegistration
import org.sopt.and.data.repository.UserRegistrationRepository
import org.sopt.and.data.repository.Auth.UserRegistrationRepository
import javax.inject.Inject

@HiltViewModel
Expand All @@ -24,8 +24,8 @@ class SignUpViewModel @Inject constructor(

fun registerUser(username: String, password: String, hobby: String) {
viewModelScope.launch {
val userRequest = RequestUserRegistration(username, password, hobby)
val result = userRegistrationRepository.registerUser(userRequest)
val userRequest = RequestUserRegistrationData(username, password, hobby)
val result = userRegistrationRepository.postUserRegistration(userRequest)
_userRegistrationResult.postValue(result)
}
}
Expand Down

0 comments on commit 5d1a2b7

Please sign in to comment.