Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔀 :: (#51) Connect Auth Login API #60

Merged
merged 6 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions app/src/main/java/com/msg/bitgoeul_android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
com.msg.design_system.theme.BitgoeulAndroidTheme { colors, typography ->
// A surface container using the 'background' color from the theme
BitgoeulAndroidTheme { colors, typography ->
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
}
Expand All @@ -40,7 +38,7 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
com.msg.design_system.theme.BitgoeulAndroidTheme { colors, typography ->
BitgoeulAndroidTheme { colors, typography ->
Greeting("Android")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.msg.domain.exception

class BadRequestException(
override val message: String?
) : RuntimeException()

class UnauthorizedException(
override val message: String?
) : RuntimeException()

class ForBiddenException(
override val message: String?
) : RuntimeException()

class NotFoundException(
override val message: String?
) : RuntimeException()

class NotAcceptableException(
override val message: String?
) : RuntimeException()

class ConflictException(
override val message: String?
) : RuntimeException()

class TimeOutException(
override val message: String?
) : RuntimeException()

class ServerException(
override val message: String?
) : RuntimeException()

class OtherException(
override val message: String?,
val code: Int
) : RuntimeException()

class UnknownException(
override val message: String?
) : RuntimeException()
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.msg.domain.exception

import java.io.IOException

class NeedLoginException: IOException() {
override val message: String
get() = "토큰이 만료되었습니다. 다시 로그인 해주세요"
}
24 changes: 19 additions & 5 deletions feature/login/src/main/java/com/bitgoeul/login/LoginScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,26 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import com.bitgoeul.login.viewmodel.AuthViewModel
import com.msg.design_system.R
import com.msg.design_system.component.button.BitgoeulButton
import com.msg.design_system.component.button.ButtonState
import com.msg.design_system.component.textfield.DefaultTextField
import com.msg.design_system.component.textfield.LinkText
import com.msg.design_system.component.textfield.PasswordTextField
import com.msg.design_system.theme.BitgoeulAndroidTheme
import com.msg.model.remote.request.auth.LoginRequest

@Composable
fun LoginScreen() {
val isEmailErrorStatus = remember { mutableStateOf(false)}
val isPasswordErrorStatus = remember { mutableStateOf(false)}
val isEmailErrorStatus = remember { mutableStateOf(false) }
val isPasswordErrorStatus = remember { mutableStateOf(false) }
val isErrorTextShow = remember { mutableStateOf(false) }
var isTextStatus = ""
var emailState = remember { mutableStateOf("") }
val passwordState = remember { mutableStateOf("") }
val authViewModel: AuthViewModel = hiltViewModel()
BitgoeulAndroidTheme { color, type ->
Box {
Column(
Expand Down Expand Up @@ -71,6 +77,7 @@ fun LoginScreen() {
errorText = stringResource(id = R.string.error_text_email),
onValueChange = {
isTextStatus = it
emailState.value = it
},
isError = isEmailErrorStatus.value,
onClickButton = {
Expand Down Expand Up @@ -101,7 +108,9 @@ fun LoginScreen() {
.height(54.dp),
placeholder = stringResource(id = R.string.password),
errorText = stringResource(id = R.string.wrong_password),
onValueChange = {},
onValueChange = {
passwordState.value = it
},
onClickLink = {},
isError = isPasswordErrorStatus.value,
isLinked = true,
Expand All @@ -124,7 +133,12 @@ fun LoginScreen() {
.height(52.dp),
state = ButtonState.Disable,
) {
// Action
authViewModel.login(
body = LoginRequest(
email = emailState.value,
password = passwordState.value
)
)
}
}

Expand All @@ -136,7 +150,7 @@ fun LoginScreen() {
style = type.labelMedium,
color = color.G1,
fontSize = 14.sp,
)
)

Spacer(modifier = Modifier.height(2.dp))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.bitgoeul.login.viewmodel

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bitgoeul.login.viewmodel.util.Event
import com.bitgoeul.login.viewmodel.util.errorHandling
import com.msg.domain.auth.LoginUseCase
import com.msg.domain.auth.LogoutUseCase
import com.msg.domain.auth.SaveTokenUseCase
import com.msg.domain.auth.WithdrawUseCase
import com.msg.model.remote.model.auth.AuthTokenModel
import com.msg.model.remote.request.auth.LoginRequest
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class AuthViewModel @Inject constructor(
private val loginUseCase: LoginUseCase,
private val logoutUseCase: LogoutUseCase,
private val saveTokenUseCase: SaveTokenUseCase,
private val withdrawUseCase: WithdrawUseCase,
) : ViewModel() {
private val _saveTokenRequest = MutableLiveData<Event<Nothing>>()
val saveTokenRequest: LiveData<Event<Nothing>> get() = _saveTokenRequest

private val _loginRequest = MutableLiveData<Event<AuthTokenModel>>()
val loginRequest: LiveData<Event<AuthTokenModel>> get() = _loginRequest

fun login(body: LoginRequest) = viewModelScope.launch {
loginUseCase(
body = body
).onSuccess {
it.catch { remoteError ->
_loginRequest.value = remoteError.errorHandling()
}.collect { response ->
_loginRequest.value = Event.Success(data = response)
}
}.onFailure {
_loginRequest.value = it.errorHandling()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.bitgoeul.login.viewmodel.util

sealed class Event<out T>(
val data: T? = null
) {

object Loading : Event<Nothing>()

/**
* 성공
*/
class Success<T>(data: T? = null) : Event<T>(data = data)

/**
* 400번 요청이 올바르지 않은 경우
*/
object BadRequest : Event<Nothing>()

/**
* 401번 비인증 요청
*/
object Unauthorized : Event<Nothing>()

/**
* 403번 권한이 없음
*/
object ForBidden : Event<Nothing>()

/**
* 404 찾을 수 없는 경우
*/
object NotFound : Event<Nothing>()

/**
* 406 맞는 규격이 없는 경우
*/
object NotAcceptable : Event<Nothing>()

/**
* 408 요청이 너무 오래 걸리는 경우
*/
object TimeOut : Event<Nothing>()

/**
* 409 권한이 없을 때
*/
object Conflict : Event<Nothing>()

/**
* 50X 서버에러
*/
object Server : Event<Nothing>()

/**
* 예상치 못한 에러
*/
object UnKnown : Event<Nothing>()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.bitgoeul.login.viewmodel.util

import android.util.Log
import com.msg.domain.exception.*

suspend fun <T> Throwable.errorHandling(
badRequestAction: suspend () -> Unit = {},
unauthorizedAction: suspend () -> Unit = {},
forBiddenAction: suspend () -> Unit = {},
notFoundAction: suspend () -> Unit = {},
notAcceptableAction: suspend () -> Unit = {},
timeOutAction: suspend () -> Unit = {},
conflictAction: suspend () -> Unit = {},
serverAction: suspend () -> Unit = {},
unknownAction: suspend () -> Unit = {},
): Event<T> =
when (this) {
is BadRequestException -> {
errorLog("BadRequestException", message)
badRequestAction()
Event.BadRequest
}
is UnauthorizedException, is NeedLoginException -> {
errorLog("UnauthorizedException", message)
unauthorizedAction()
Event.Unauthorized
}
is ForBiddenException -> {
errorLog("ForBiddenException", message)
forBiddenAction()
Event.ForBidden
}
is NotFoundException -> {
errorLog("NotFoundException", message)
notFoundAction()
Event.NotFound
}
is NotAcceptableException -> {
errorLog("NotAcceptableException", message)
notAcceptableAction()
Event.NotAcceptable
}
is TimeOutException -> {
errorLog("TimeOutException", message)
timeOutAction()
Event.TimeOut
}
is ConflictException -> {
errorLog("ConflictException", message)
conflictAction()
Event.Conflict
}
is ServerException -> {
errorLog("ServerException", message)
serverAction()
Event.Server
}
else -> {
errorLog("UnKnownException", message)
unknownAction()
Event.UnKnown
}
}

private fun errorLog(tag: String, msg: String?) {
Log.d("ErrorHandling-$tag", msg ?: "알 수 없는 오류")
}