Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import org.sopt.dosopttemplate.databinding.ActivityLoginBinding
import org.sopt.dosopttemplate.presentation.auth.signUp.SignUpActivity
import org.sopt.dosopttemplate.presentation.main.HomeActivity
Expand Down Expand Up @@ -31,21 +33,31 @@ class LoginActivity : AppCompatActivity() {
}

private fun observeLoginResult() {
loginViewModel.loginSuccess.observe(this) {
if (it) {
val userId = loginViewModel.loginResult.value?.id
val userName = loginViewModel.loginResult.value?.username
val userNickname = loginViewModel.loginResult.value?.nickname
binding.root.makeToast("로그인 성공! userId: {$userId}")
lifecycleScope.launch {
loginViewModel.loginState.collect { loginState ->
when (loginState) {
is LoginState.Success -> {
val userId = loginState.data.id
val userName = loginState.data.username
val userNickname = loginState.data.nickname
binding.root.makeToast("로그인 성공! userId: {$userId}")

val intent = Intent(this, HomeActivity::class.java).apply {
putExtra("UserId", userId)
putExtra("UserName", userName)
putExtra("UserNickname", userNickname)
val intent = Intent(this@LoginActivity, HomeActivity::class.java).apply {
putExtra("UserId", userId)
putExtra("UserName", userName)
putExtra("UserNickname", userNickname)
}
startActivity(intent)
}

is LoginState.Error -> {
binding.root.makeToast("로그인 실패")
}

is LoginState.Loading -> {
binding.root.makeToast("로그인 중")
}
}
startActivity(intent)
} else {
binding.root.makeToast("로그인 실패")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.sopt.dosopttemplate.presentation.auth.login

import org.sopt.dosopttemplate.server.auth.response.ResponseLoginDto

sealed class LoginState {
object Loading : LoginState()
data class Success(val data: ResponseLoginDto) : LoginState()
object Error : LoginState()
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
package org.sopt.dosopttemplate.presentation.auth.login

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import org.sopt.dosopttemplate.server.ServicePool.authService
import org.sopt.dosopttemplate.server.auth.request.RequestLoginDto
import org.sopt.dosopttemplate.server.auth.response.ResponseLoginDto

class LoginViewModel : ViewModel() {
private val _loginResult: MutableLiveData<ResponseLoginDto> = MutableLiveData()
val loginResult: MutableLiveData<ResponseLoginDto> = _loginResult

private val _loginSuccess: MutableLiveData<Boolean> = MutableLiveData()
val loginSuccess: MutableLiveData<Boolean> = _loginSuccess
private val _loginState = MutableStateFlow<LoginState>(LoginState.Loading)
val loginState: StateFlow<LoginState> = _loginState.asStateFlow()

fun login(id: String, password: String) {
viewModelScope.launch {
kotlin.runCatching {
authService.login(RequestLoginDto(id, password))
}.onSuccess {
if (it.isSuccessful) {
_loginResult.value = it.body()
loginSuccess.value = true
} else {
loginSuccess.value = false
if (it.body() != null) {
_loginState.value = LoginState.Success(it.body()!!)
}
}.onFailure {
// 에러 처리 로직
_loginState.value = LoginState.Error
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import android.text.Editable
import android.text.TextWatcher
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import org.sopt.dosopttemplate.databinding.ActivitySignUpBinding
import org.sopt.dosopttemplate.presentation.auth.login.LoginActivity
import org.sopt.dosopttemplate.util.makeToast
Expand Down Expand Up @@ -35,17 +37,27 @@ class SignUpActivity : AppCompatActivity() {
}

private fun observeSignUpResult() {
signUpViewModel.signUpSuccess.observe(this) {
if (it) {
binding.root.makeToast("회원가입 성공!")
startActivity(
Intent(
this@SignUpActivity,
LoginActivity::class.java
)
)
} else {
binding.root.makeToast("회원가입 실패")
lifecycleScope.launch {
signUpViewModel.signUpState.collect { signUpState ->
when (signUpState) {
is SignUpState.Success -> {
binding.root.makeToast("회원가입 성공!")
startActivity(
Intent(
this@SignUpActivity,
LoginActivity::class.java
)
)
}

is SignUpState.Error -> {
binding.root.makeToast("회원가입 실패")
}

is SignUpState.Loading -> {
binding.root.makeToast("회원가입 중")
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.sopt.dosopttemplate.presentation.auth.signUp

sealed class SignUpState {
object Loading : SignUpState()
data class Success(val data: Unit) : SignUpState()
object Error : SignUpState()
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
package org.sopt.dosopttemplate.presentation.auth.signUp

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import org.sopt.dosopttemplate.server.ServicePool.authService
import org.sopt.dosopttemplate.server.auth.request.RequestSignUpDto
import java.util.regex.Pattern

class SignUpViewModel : ViewModel() {
private val _signUpSuccess: MutableLiveData<Boolean> = MutableLiveData()
val signUpSuccess: MutableLiveData<Boolean> = _signUpSuccess
private val _signUpState = MutableStateFlow<SignUpState>(SignUpState.Loading)
val signUpState: StateFlow<SignUpState> = _signUpState.asStateFlow()
Comment on lines +14 to +15

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sharedFlow가 아닌 stateFlow를 사용한 이유는 무엇일까요~?


fun signUp(id: String, name: String, password: String) {
viewModelScope.launch {
kotlin.runCatching {
authService.signUp(RequestSignUpDto(id, name, password))
}.onSuccess {
signUpSuccess.value = it.isSuccessful
_signUpState.value = SignUpState.Success(it.body()!!)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!!(Non-null assertion operator)를 사용하신 이유는 무엇인가요?!
현재 it.body()에 null값이 들어오면 NullPointerException을 발생하는데요, !!(Non-null assertion operator)을 사용하지 않고 null 타입 체크를 해보면 좋을 것 같습니다!

}.onFailure {
// 에러 처리 로직
_signUpState.value = SignUpState.Error
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import org.sopt.dosopttemplate.data.adaptor.UserAdaptor
import org.sopt.dosopttemplate.databinding.FragmentHomeBinding
import org.sopt.dosopttemplate.util.makeToast
Expand Down Expand Up @@ -49,16 +51,21 @@ class HomeFragment : Fragment() {

private fun getUserList() {
userViewModel.getUserList(2)
userViewModel.userSuccess.observe(viewLifecycleOwner) {
if (it) {
val userList = userViewModel.userResult.value?.data
if (userList != null) {
Log.e("서버 통신", "성공")

userAdapter.setUserList(userList)
lifecycleScope.launch {
userViewModel.userState.collect { userState ->
Copy link

@sohyun127 sohyun127 Jan 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flowWithLifecycle에 대해서 공부해보면 좋을 것 같아요!
(힌트는 StateFlow는 lifecycle을 자동으로 처리하지 않아서 수동으로 flow의 collect 중지시켜주어야해요!)

when (userState) {
is UserState.Success -> {
val userList = userState.data.data
userAdapter.setUserList(userList)
binding.root.makeToast("유저 서버 통신 성공")
}
is UserState.Error -> {
binding.root.makeToast("유저 받아오기 실패")
}
is UserState.Loading -> {
binding.root.makeToast("유저 받아오는 중")
}
}
} else {
binding.root.makeToast("유저 받아오기 실패")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.sopt.dosopttemplate.presentation.main.home

import org.sopt.dosopttemplate.server.auth.response.ResponseUserListDto

sealed class UserState {
object Loading : UserState()
data class Success(val data: ResponseUserListDto) : UserState()
object Error : UserState()
}
Comment on lines +5 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 만들어진 코드만 보았을 때는 LoginState, SignUpState, UserState에서 처리하는 상태들이 동일합니다!
통합해서 관리하는 방법도 있지 않을까요?

Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
package org.sopt.dosopttemplate.presentation.main.home

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import org.sopt.dosopttemplate.server.ServicePool.userService
import org.sopt.dosopttemplate.server.auth.response.ResponseUserListDto

class UserViewModel : ViewModel() {
private val _userResult: MutableLiveData<ResponseUserListDto> = MutableLiveData()
val userResult: MutableLiveData<ResponseUserListDto> = _userResult

private val _userSuccess: MutableLiveData<Boolean> = MutableLiveData()
val userSuccess: MutableLiveData<Boolean> = _userSuccess
private val _userState = MutableStateFlow<UserState>(UserState.Loading)
val userState: StateFlow<UserState> = _userState.asStateFlow()

fun getUserList(page: Int) {
viewModelScope.launch {
kotlin.runCatching {
userService.getUserList(page)
}.onSuccess {
if (it.isSuccessful) {
userResult.value = it.body()
userSuccess.value = true
} else {
userSuccess.value = false
if (it.body() != null) {
_userState.value = UserState.Success(it.body()!!)
}
Comment on lines +20 to 22

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null일 때의 분기 처리는 어딨죠?!
추가적으로

!!은 어떤 값이든 널이 될 수 없는 타입으로 (강제로) 바꾸는 단순하면서도 무딘 도구다.
라고 Kotlin in Action에서는 표현하였는데요!

위에서 설명했듯이 !!(Non-null assertion operator)를 사용하지 않고 null 타입 체크를 해보면 좋을 것 같습니다!

}.onFailure {
// 에러 처리 로직
_userState.value = UserState.Error
}
}
}
Expand Down