Skip to content
Open
Show file tree
Hide file tree
Changes from 13 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
4 changes: 3 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ android {
}
buildFeatures {
viewBinding = true
dataBinding = true

//사용할 객체 가져오기 (base_url 감추는 작업)
buildConfig = true
Expand Down Expand Up @@ -81,5 +82,6 @@ dependencies {
//이미지 로드
implementation 'io.coil-kt:coil:2.4.0'


//코루틴
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.sopt.dosopttemplate.data.dataclass

object UserInfo {
var userInfoList = User(
nick = "",
self_description = "",
id = "",
pw = "",
mbti = "",
Comment on lines +5 to +9
Copy link
Contributor

Choose a reason for hiding this comment

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

디폴트 값으로 ""를 준 이유를 한 번 생각해보시면 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

디폴드 값을 주긴줘야되는데 디폴트값으로 넣을만한 값을 딱히 모르겠어서 ""로 퉁친건데 보통 일반적으로 사용되는 디폴드값이 있을까요??

Copy link
Contributor

Choose a reason for hiding this comment

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

왜 꼭 디폴트 값을 주어야 할지 nonNull을 주면 안되는지 생각해보면 좋을 것 같아서요 답은 프로젝트의 성격에 따라 다릅니다 string의 기본값은 ""을 대부분 사용해요

)
}
Copy link
Member

Choose a reason for hiding this comment

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

여기서 mapping함수를 추가하면 좋습니다!

Copy link
Contributor Author

@codingmy codingmy Jan 2, 2024

Choose a reason for hiding this comment

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

매핑함수를 공부한지 얼마 안돼서 일단 object에 mapping 함수를 만들어서 반영해봤는데...data class에서 정의하는게 더 적절한거겠죠...? 다시 옮겨보겠습니당 0489e44 아니다 일단 여기에서 매핑함수를 제대로 쓴게 맞나요?? 뭔가 다시 펼쳐보니까 잘쓴건지 긴가민가 하네용...!

Copy link
Member

Choose a reason for hiding this comment

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

제가쓴 mapping함수랑 클린아키텍쳐나 ob들이 사용했던 map함수의 목적이 달라서,,
ob들 코드를 따라가는게 맞는 것 같습니다! 전 단순 초기화랑 placeable를 용이하게 하기 위한 용도 였어요.

Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import kotlinx.serialization.Serializable
@Serializable
data class RequestLoginDto (
@SerialName("username")
val username: String,
var username: String,

@SerialName("password")
val password: String,
var password: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

왜 val에서 var로 변경하였나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

코드 짜는 중간에 다른거랑 헷갈려서 잘못 바꿨던거 같은데 다시 원상복구를 안시켰었던거같아요! 다시 원상복구시키겠습니당

Copy link
Contributor

Choose a reason for hiding this comment

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

확인했습니당

)
11 changes: 6 additions & 5 deletions app/src/main/java/org/sopt/dosopttemplate/module/AuthService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.sopt.dosopttemplate.data.dto.request.RequestUserDataDto
import org.sopt.dosopttemplate.data.dto.response.ResponseLoginDto
import retrofit2.Call
import org.sopt.dosopttemplate.data.dto.response.ResponseUserDataDto
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
Expand All @@ -14,17 +15,17 @@ import retrofit2.http.Path
interface AuthService {

@POST("api/v1/members/sign-in")
fun postLogin(
fun postLogin(
@Body request: RequestLoginDto,
): Call<ResponseLoginDto>
): Response<ResponseLoginDto>

@POST("api/v1/members")
fun signUp(
fun postSignUp(
@Body request: RequestSignUpDto,
): Call<Unit>
): Response<Unit>

@GET("api/v1/members/{memberId}")
fun getUserInfo(
@Path("memberId") memberId: Int
): Call<ResponseUserDataDto>
): Response<ResponseUserDataDto>
Copy link
Contributor

Choose a reason for hiding this comment

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

코루틴이 아직 적용이 안되었는데 다음에 적용해봅시다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이제는 적용 제대로 됐죠....????? 이번 커밋에 뷰모델 안 가져와있던거 제대로 가져와서 아마 된거 같은데.....된거 맞겠....죠?!?!???

Copy link
Contributor

Choose a reason for hiding this comment

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

suspend가 안붙었는데 적용 안한거 같은데

Copy link
Contributor Author

Choose a reason for hiding this comment

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

어라 이거 진짜 엄청 삽질하면서 다 바꾸고 커밋 다 올렸는데??????안스가 또????? 집가서 함 확인해봐야겠네영...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

확인해봤는데 일단 안스에서는 다 누락없이 푸시하고 깃헙에도 올라간거 같은데 이 코리 창에서는 변경된 부분이 안보이네요...! 저번엔 됐었던거 같은데... 🤔🤔 혹시 깃헙 pr 올린 뒤에 커밋 올리면 이미 이전에 코리한 코드창에는 반영이 안되던가요...?일단 0ed0212 요 커밋을 봐주시죠~~!~! 코루틴 이렇게하면 이번엔 진짜로 적용된거 맞죠...???!

Copy link
Contributor

Choose a reason for hiding this comment

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

잘 됬습니당

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ package org.sopt.dosopttemplate.presentation.login
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import org.sopt.dosopttemplate.databinding.ActivityLoginBinding
import org.sopt.dosopttemplate.presentation.mainhome.MainHomeActivity
import org.sopt.dosopttemplate.module.ServicePool.authService
import org.sopt.dosopttemplate.presentation.mainhome.MainHomeViewModel
import org.sopt.dosopttemplate.presentation.signUp.SignUpActivity
import org.sopt.dosopttemplate.databinding.ActivityLoginBinding
import org.sopt.dosopttemplate.data.dto.request.RequestLoginDto
import org.sopt.dosopttemplate.data.dto.response.ResponseLoginDto
import org.sopt.dosopttemplate.utils.toast
import org.sopt.dosopttemplate.utils.snackbar
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response


class LoginActivity : AppCompatActivity() {

private lateinit var binding: ActivityLoginBinding
private lateinit var loginViewModel: LoginViewModel

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java)


initLoginClickListener()
Expand Down Expand Up @@ -73,12 +73,37 @@ class LoginActivity : AppCompatActivity() {
val id = binding.etLoginId.text.toString()
val password = binding.etLoginPw.text.toString()
binding.btLogin.setOnClickListener {
checkLoginAvailableFromServer(id, password)
loginViewModel.checkLoginAvailableFromServer(id, password)
checkLoginAvailableFromServer()
}
}
}

private fun checkLoginAvailableFromServer() {
lifecycleScope.launch {
loginViewModel.loginState.collect { loginState ->
when (loginState) {
is LoginState.Success -> {
toast("로그인 성공")
val intent = Intent(this@LoginActivity, MainHomeActivity::class.java)
startActivity(intent)
}

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

is LoginState.Loading -> {
toast("로그인 중")
}
}
}
}
}

private fun checkLoginAvailableFromServer(id: String, password: String) {
/*


Copy link
Contributor

Choose a reason for hiding this comment

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

불 필요한 공백은 지워주도록 합시다

authService.postLogin(RequestLoginDto(id, password))
.enqueue(object : Callback<ResponseLoginDto> {
override fun onResponse(
Expand All @@ -88,7 +113,7 @@ class LoginActivity : AppCompatActivity() {
if (response.isSuccessful) {
val data: ResponseLoginDto = requireNotNull(response.body()!!)
val userId: Int = data.id
toast("로그인 성공, 유저의 ID는 $userId 입니다")
toast("로그인 성공")
val intent = Intent(this@LoginActivity, MainHomeActivity::class.java)
intent.putExtra("id", userId)
startActivity(intent)
Expand All @@ -101,7 +126,7 @@ class LoginActivity : AppCompatActivity() {
toast("서버 에러 발생")
}
})
}
*/
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.sopt.dosopttemplate.presentation.login

import org.sopt.dosopttemplate.data.dto.response.ResponseLoginDto

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

import androidx.lifecycle.LiveData
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.data.dataclass.UserInfo
import org.sopt.dosopttemplate.data.dto.request.RequestLoginDto
import org.sopt.dosopttemplate.module.ApiFactory
import org.sopt.dosopttemplate.module.AuthService

class LoginViewModel() : ViewModel() {
private val _loginSuccess: MutableLiveData<Boolean> = MutableLiveData()
var loginSuccess: LiveData<Boolean> = _loginSuccess

private val _loginState = MutableStateFlow<LoginState>(LoginState.Loading)
val loginState: StateFlow<LoginState> = _loginState.asStateFlow()
Copy link
Contributor

Choose a reason for hiding this comment

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

찬우형 코드리뷰에서도 똑같은 리뷰를 달았는데 Ui State의 기본값을 init이나 loading 말고 다른 것을 주는 것이 어떨까요? 아래는 찬우형한테 해준 코리 복사해왔습니다!

처음 UiState의 기본 상태를 Loading으로 두는 것 같은데 init State상태를 추가해주시는 것이 좋을 것 같아요
loading State 은 실제로 서버와 통신을 진행하는 동안 스캘레톤 로딩을 보여주거나 로딩 화면을 보여줄 때를 주로 정의합니다.

Copy link
Contributor Author

@codingmy codingmy Jan 2, 2024

Choose a reason for hiding this comment

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

f237bd4 에서 Unstarted 상태를 추가해서 기본값은 Unstarted으로, 서버통신 시작시에 Loading으로 수정하도록해서 실제 서버통신 동안만 Loading값을 갖도록 수정해봤습니다!



fun checkLoginAvailableFromServer(id: String, password: String) {
Copy link
Contributor

Choose a reason for hiding this comment

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

개인 취향이지만 Available은 빼도 되지 않을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

안그래도 네이밍이 너무 길다고 느껴졌는데 그게 좋은거 같아요!!

viewModelScope.launch {
val loginService = ApiFactory.create<AuthService>()
kotlin.runCatching {
loginService.postLogin(RequestLoginDto(id, password))
}.onSuccess {
val body = it.body()
if (it.body() != null) {
_loginState.value = LoginState.Success(body!!)
UserInfo.userInfoList.id = id
UserInfo.userInfoList.pw = password

} else {
_loginState.value = LoginState.Error
}
}.onFailure {
_loginState.value = LoginState.Error
}

///*
// ServicePool.authService.postLogin(RequestLoginDto(id, password))
// .enqueue(object : Callback<ResponseLoginDto> {
// override fun onResponse(
// call: Call<ResponseLoginDto>,
// response: Response<ResponseLoginDto>,
// ) {
// if (response.isSuccessful) {
// val data: ResponseLoginDto = requireNotNull(response.body()!!)
//
//
// val userId: Int = data.id
// loginSuccess.value = true
// toast("로그인 성공")
// val intent = Intent(context, MainHomeActivity::class.java)
// intent.putExtra("id", userId)
//
//
// startActivity(intent)
// } else {
Comment on lines +43 to +62
Copy link
Member

Choose a reason for hiding this comment

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

심화과제하고 추후에 주석은 지워주세요!

Copy link
Contributor

Choose a reason for hiding this comment

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

동의합니당!

// toast("아이디와 패스워드가 일치 하지 않습니다.")
// }
// }
//
// override fun onFailure(call: Call<ResponseLoginDto>, t: Throwable) {
// toast("서버 에러 발생")
// }
// })
//*/

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class MainHomeActivity : AppCompatActivity() {
private fun clickBottomNavigation() {
var userId = intent.getIntExtra("id", -1)

mainHomeViewModel.userId=userId
// mainHomeViewModel.userId=userId
Copy link
Contributor

Choose a reason for hiding this comment

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

사용하지 않는 코드는 지워주세요!

binding.bnvHome.setOnItemSelectedListener {
mainHomeViewModel.clickBottomNavigation(it.itemId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import org.sopt.dosopttemplate.MyApplication
import org.sopt.dosopttemplate.data.dataclass.Friend
import org.sopt.dosopttemplate.R
import org.sopt.dosopttemplate.data.dataclass.User
import org.sopt.dosopttemplate.data.dataclass.UserInfo
import org.sopt.dosopttemplate.data.dto.request.RequestUserDataDto
import org.sopt.dosopttemplate.data.dto.response.ResponseUserDataDto
import org.sopt.dosopttemplate.module.ServicePool.authService
Expand All @@ -19,10 +22,13 @@ import retrofit2.Response

class MainHomeViewModel : ViewModel() {
private val _navigateTo = MutableLiveData<Fragment>()
val navigateTo: LiveData<Fragment>
get() = _navigateTo
val navigateTo: LiveData<Fragment> get() = _navigateTo
Comment on lines 24 to +25
Copy link
Contributor

Choose a reason for hiding this comment

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

혹시 이 코드는 어떤 목적으로 사용 되는 것 일까요??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이 친구는 아마 하단 네비게이션 부분이 터치 인식됐을 때, viewModel에서 어떤 fragment를 보여줘야되는지 naviagetTo에 저장하고, activity에서 navigateTo값을 observe해서 fragment를 바꾸는 목적으로 사용했습니다!

Copy link
Contributor

Choose a reason for hiding this comment

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

viewModel에서 어떤 프레그먼트로 이동할지 알 필요가 있을까요?
프레그먼트 전환은 view랑 viewModel중에 누가 책임을 가지고 있어야할까요? MVVM에 대해서 공부해보시면 좋을 것 같습니다.


private var _userId: MutableLiveData<String> = MutableLiveData<String>()
val userId: LiveData<String> = _userId
val userPw: MutableLiveData<String> = MutableLiveData<String>()


var userId: Int = 0
fun clickBottomNavigation(itemId: Int): Boolean {

when (itemId) {
Expand All @@ -37,7 +43,7 @@ class MainHomeViewModel : ViewModel() {
}

R.id.menu_mypage -> {
myPageUserInfo(userId)
myPageUserInfo()
_navigateTo.value = MyPageFragment()
return true
}
Expand All @@ -52,29 +58,9 @@ class MainHomeViewModel : ViewModel() {
}


private fun myPageUserInfo(userId: Int) {
authService.getUserInfo(userId)
.enqueue(object : retrofit2.Callback<ResponseUserDataDto> {
override fun onResponse(
call: Call<ResponseUserDataDto>,
response: Response<ResponseUserDataDto>,
) {
if (response.isSuccessful) {
val data: ResponseUserDataDto = requireNotNull(response.body())
val userNickname = data.nickname
val userUsername = data.username

//sharedpreference로 넘기기
MyApplication.prefs.setString("nick", userNickname)
MyApplication.prefs.setString("username", userUsername)
MyApplication.prefs.setString("id", userId.toString())
}
}

override fun onFailure(call: Call<ResponseUserDataDto>, t: Throwable) {
_errorMsg.value = "서버 에러 발생"
}
})
private fun myPageUserInfo() {
_userId.value = UserInfo.userInfoList.id
userPw.value = UserInfo.userInfoList.pw
Copy link
Contributor

Choose a reason for hiding this comment

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

얘도 _userPw 만들어서 처리하면 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

근데 userPw는 이 뷰모델에서 User로 값 복붙 해주는거 밖에 안하는데 그래도 _userPw 만들어 놓는게 나을까요??

Copy link
Contributor

Choose a reason for hiding this comment

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

복붙밖에 안한다면 private로 만드는게 좋지 않을까요?

}

private var _errorMsg = MutableLiveData<String>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import org.sopt.dosopttemplate.MyApplication
import org.sopt.dosopttemplate.databinding.FragmentMypageBinding
import org.sopt.dosopttemplate.presentation.mainhome.MainHomeViewModel

class MyPageFragment : Fragment() {
private var _binding: FragmentMypageBinding? = null
private val binding: FragmentMypageBinding get() = requireNotNull(_binding!!)
private val binding: FragmentMypageBinding get() = requireNotNull(_binding)
private val viewModel by viewModels<MainHomeViewModel>()

override fun onCreateView(
inflater: LayoutInflater,
Expand All @@ -38,6 +41,7 @@ class MyPageFragment : Fragment() {
}

override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
Loading