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

#203 [refact] 로그인 리팩토링 #204

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 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
9 changes: 2 additions & 7 deletions app/src/main/java/hous/release/android/di/RetrofitModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ object RetrofitModule {
): Interceptor = Interceptor { chain ->
if (!context.isNetworkConnected()) {
context.startActivity(
Intent(
context, NetworkErrorActivity::class.java
).apply {
Intent(context, NetworkErrorActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
)
Expand All @@ -71,10 +69,7 @@ object RetrofitModule {
var response = chain.proceed(
request
.newBuilder()
.addHeader(
HEADER_AUTHORIZATION,
BEARER + localPrefTokenDataSource.accessToken
)
.addHeader(HEADER_AUTHORIZATION, BEARER + localPrefTokenDataSource.accessToken)
.addHeader(HEADER_OS_TYPE, OS_TYPE)
.addHeader(HEADER_VERSION, BuildConfig.VERSION_NAME)
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class HousViewModel @Inject constructor(
.onSuccess { response ->
_hous.value = response
_homies.value = response.homies
Timber.e("${hous.value.homies[0].homieId}")
Timber.d("${hous.value.homies[0].homieId}")
}
.onFailure { Timber.d(it.message.toString()) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import hous.release.android.util.binding.BindingActivity
import hous.release.android.util.dialog.ConfirmClickListener
import hous.release.android.util.dialog.WarningDialogFragment
import hous.release.android.util.dialog.WarningType
import hous.release.android.util.extension.EventObserver
import hous.release.android.util.extension.repeatOnStarted
import hous.release.android.util.extension.setOnSingleClickListener
import hous.release.data.service.KakaoLoginService
import timber.log.Timber
import javax.inject.Inject
import kotlin.system.exitProcess

Expand All @@ -30,35 +30,35 @@ class LoginActivity : BindingActivity<ActivityLoginBinding>(R.layout.activity_lo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initKakaoLoginBtnClickListener()
initIsSuccessKakaoLoginObserver()
initIsInitUserInfoObserver()
initBackPressedCallback()
initIsJoiningRoomObserve()
initIsUserObserve()
initIsPermitAccessObserve()
collectIsJoiningRoom()
collectIsSignedUp()
collectIsKakaoLogin()
collectIsMiultipleAccess()
}

private fun initIsUserObserve() {
loginViewModel.isJoiningRoom.observe(this) {
if (loginViewModel.isJoiningRoom.value == true) {
ToastMessageUtil.showToast(this@LoginActivity, getString(R.string.login_toast))
val toMain = Intent(this, MainActivity::class.java)
startActivity(toMain)
finishAffinity()
} else {
val toEnterRoom = Intent(this, EnterRoomActivity::class.java)
startActivity(toEnterRoom)
finishAffinity()
private fun collectIsJoiningRoom() {
repeatOnStarted {
loginViewModel.isJoiningRoom.collect { joiningRoom ->
if (joiningRoom) {
ToastMessageUtil.showToast(this@LoginActivity, getString(R.string.login_toast))
startActivity(Intent(this, MainActivity::class.java))
finishAffinity()
} else {
startActivity(Intent(this@LoginActivity, EnterRoomActivity::class.java))
finishAffinity()
}
}
}
}

private fun initIsJoiningRoomObserve() {
loginViewModel.isUser.observe(this) {
if (loginViewModel.isUser.value == false) {
val toUserInput = Intent(this, UserInputActivity::class.java)
startActivity(toUserInput)
finishAffinity()
private fun collectIsSignedUp() {
repeatOnStarted {
loginViewModel.isSignedUp.collect { signedUp ->
if (!signedUp) {
startActivity(Intent(this@LoginActivity, UserInputActivity::class.java))
finishAffinity()
}
}
}
}
Expand Down Expand Up @@ -89,43 +89,33 @@ class LoginActivity : BindingActivity<ActivityLoginBinding>(R.layout.activity_lo
kakaoLoginService.startKakaoLogin(loginViewModel.kakaoLoginCallback)
}

private fun initIsSuccessKakaoLoginObserver() {
loginViewModel.isSuccessKakaoLogin.observe(
this,
EventObserver { isSuccess ->
if (isSuccess) {
Timber.e("카카오 로그인 성공")
} else {
Timber.e("카카오 로그인 실패")
private fun collectIsKakaoLogin() {
repeatOnStarted {
loginViewModel.isKakaoLogin.collect { success ->
if (success) {
loginViewModel.postLogin()
}
}
)
}

private fun initIsInitUserInfoObserver() {
loginViewModel.isInitUserInfo.observe(
this,
EventObserver { isSuccess ->
if (isSuccess) loginViewModel.postLogin()
}
)
}
}

private fun initIsPermitAccessObserve() {
loginViewModel.isMultipleAccess.observe(this) { isMultipleAccess ->
if (isMultipleAccess == true) {
WarningDialogFragment().apply {
arguments = Bundle().apply {
putSerializable(
WarningDialogFragment.WARNING_TYPE,
WarningType.WARNING_SPLASH
)
putParcelable(
WarningDialogFragment.CONFIRM_ACTION,
ConfirmClickListener(confirmAction = { loginViewModel.initIsPermitAccess() })
)
}
}.show(supportFragmentManager, WarningDialogFragment.DIALOG_WARNING)
private fun collectIsMiultipleAccess() {
repeatOnStarted {
loginViewModel.isMiultipleAccess.collect { accessLogin ->
if (accessLogin) {
WarningDialogFragment().apply {
arguments = Bundle().apply {
putSerializable(
WarningDialogFragment.WARNING_TYPE,
WarningType.WARNING_SPLASH
)
putParcelable(
WarningDialogFragment.CONFIRM_ACTION,
ConfirmClickListener(confirmAction = { loginViewModel.postForceLogin() })
)
}
}.show(supportFragmentManager, WarningDialogFragment.DIALOG_WARNING)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package hous.release.android.presentation.login

import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.model.AuthErrorCause
import dagger.hilt.android.lifecycle.HiltViewModel
import hous.release.android.util.extension.Event
import hous.release.android.util.KakaoLoginCallback
import hous.release.domain.entity.SplashState
import hous.release.domain.usecase.GetFcmTokenUseCase
import hous.release.domain.usecase.InitHousTokenUseCase
import hous.release.domain.usecase.InitTokenUseCase
import hous.release.domain.usecase.InitLoginTokenUseCase
import hous.release.domain.usecase.PostForceLoginUseCase
import hous.release.domain.usecase.PostLoginUseCase
import hous.release.domain.usecase.SetSplashStateUseCase
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import retrofit2.HttpException
import timber.log.Timber
Expand All @@ -24,74 +25,32 @@ import javax.inject.Inject
@HiltViewModel
class LoginViewModel @Inject constructor(
private val postLoginUseCase: PostLoginUseCase,
private val initTokenUseCase: InitTokenUseCase,
private val initHousTokenUseCase: InitHousTokenUseCase,
private val initLoginTokenUseCase: InitLoginTokenUseCase,
private val getFcmTokenUseCase: GetFcmTokenUseCase,
private val postForceLoginUseCase: PostForceLoginUseCase,
private val setSplashStateUseCase: SetSplashStateUseCase
) : ViewModel() {
private val kakaoToken = MutableLiveData<String>()
private val kakaoToken = MutableStateFlow("")
private val fcmToken = MutableStateFlow("")

private val fcmToken = MutableLiveData<String>()
private val _isSignedUp = MutableSharedFlow<Boolean>()
val isSignedUp = _isSignedUp.asSharedFlow()

private val _isSuccessKakaoLogin = MutableLiveData<Event<Boolean>>()
val isSuccessKakaoLogin: LiveData<Event<Boolean>> = _isSuccessKakaoLogin
private val _isJoiningRoom = MutableSharedFlow<Boolean>()
val isJoiningRoom = _isJoiningRoom.asSharedFlow()

private val _isJoiningRoom = MutableLiveData<Boolean>()
val isJoiningRoom: LiveData<Boolean> = _isJoiningRoom
private val _isMultipleAccess = MutableStateFlow(false)
val isMiultipleAccess = _isMultipleAccess.asStateFlow()
Comment on lines +43 to +44
Copy link
Member

Choose a reason for hiding this comment

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

단발성 이벤트인 것 같은데 stateflow를 사용하는 이유가 있을까요?

Copy link
Contributor Author

@2zerozu 2zerozu Apr 9, 2023

Choose a reason for hiding this comment

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

단발성 이벤트인 것 같은데 stateflow를 사용하는 이유가 있을까요?

다이얼로그에서 취소하고, 다시 강제로그인을 재요청할 수 있어서 상태 저장하려고 stateFlow 사용했숨다

Copy link
Member

Choose a reason for hiding this comment

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

오히려 위와 같은 상황이라면 더더욱 sharedFlow를 사용해야되지 않을까요?
[isMutipleAccess : false] -> 첫 강제 로그인 [isMutipleAccess : true] -> 취소 [isMutipleAccess : true] -> 다시 클릭 true 방출

stateFlow 는 같은 값은 수집 안하는 특성이 있어서 오히려 다이얼로그가 안뜰 것 같은 생각이 듭니다..!

그리고 사용 방식도 sharedFlow랑 비슷해보여서 바꾸는 것이 나을 것 같네요.

위에 상황 한번 해보고 후기 알려줘연~ 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오히려 위와 같은 상황이라면 더더욱 sharedFlow를 사용해야되지 않을까요?

[isMutipleAccess : false] -> 첫 강제 로그인 [isMutipleAccess : true] -> 취소 [isMutipleAccess : true] -> 다시 클릭 true 방출

stateFlow 는 같은 값은 수집 안하는 특성이 있어서 오히려 다이얼로그가 안뜰 것 같은 생각이 듭니다..!

그리고 사용 방식도 sharedFlow랑 비슷해보여서 바꾸는 것이 나을 것 같네요.

위에 상황 한번 해보고 후기 알려줘연~ 😄

아 같은 값 수집 안 하는 게 sharedFlow인 줄 알았구만요~ 오케이


private val _isUser = MutableLiveData<Boolean>()
val isUser: LiveData<Boolean> = _isUser

private val _isMultipleAccess = MutableLiveData<Boolean>()
val isMultipleAccess: LiveData<Boolean> = _isMultipleAccess

private val _isInitUserInfo = MediatorLiveData<Event<Boolean>>().apply {
addSource(kakaoToken) { token ->
value = Event(token.isNotBlank() && fcmToken.value != null)
}
addSource(fcmToken) { token ->
value = Event(token.isNotBlank() && kakaoToken.value != null)
}
val isKakaoLogin = combine(kakaoToken, fcmToken) { kakaoToken, fcmToken ->
kakaoToken.isNotBlank() && fcmToken.isNotBlank()
}
val isInitUserInfo: LiveData<Event<Boolean>> = _isInitUserInfo

val kakaoLoginCallback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
when {
error.toString() == AuthErrorCause.AccessDenied.toString() -> {
Timber.e(error, "접근이 거부 됨(동의 취소)")
}
error.toString() == AuthErrorCause.InvalidClient.toString() -> {
Timber.e(error, "유효하지 않은 앱")
}
error.toString() == AuthErrorCause.InvalidGrant.toString() -> {
Timber.e(error, "인증 수단이 유효하지 않아 인증할 수 없는 상태")
}
error.toString() == AuthErrorCause.InvalidRequest.toString() -> {
Timber.e(error, "요청 파라미터 오류")
}
error.toString() == AuthErrorCause.InvalidScope.toString() -> {
Timber.e(error, "유효하지 않은 scope ID")
}
error.toString() == AuthErrorCause.Misconfigured.toString() -> {
Timber.e(error, "설정이 올바르지 않음(android key hash)")
}
error.toString() == AuthErrorCause.ServerError.toString() -> {
Timber.e(error, "서버 내부 에러")
}
error.toString() == AuthErrorCause.Unauthorized.toString() -> {
Timber.e(error, "앱이 요청 권한이 없음")
}
else -> {
Timber.e(error, "기타 에러")
}
}
} else if (token != null) {
Timber.e("카카오 로그인 성공 ${token.accessToken}")
kakaoToken.value = token.accessToken
_isSuccessKakaoLogin.value = Event(true)
}
KakaoLoginCallback { accessToken ->
kakaoToken.value = accessToken
}.handleResult(token, error)
}

init {
Expand All @@ -101,19 +60,12 @@ class LoginViewModel @Inject constructor(
fun postLogin() {
viewModelScope.launch {
postLoginUseCase(
fcmToken = requireNotNull(fcmToken.value),
socialType = "KAKAO",
token = requireNotNull(kakaoToken.value)
fcmToken = fcmToken.value,
socialType = SOCIAL_TYPE,
token = kakaoToken.value
).onSuccess { response ->
initTokenUseCase(
fcmToken = requireNotNull(fcmToken.value),
socialType = SOCIAL_TYPE,
token = requireNotNull(kakaoToken.value)
)
initHousTokenUseCase(
token = response.token
)
_isJoiningRoom.value = response.isJoiningRoom
initHousTokenUseCase(token = response.token)
_isJoiningRoom.emit(response.isJoiningRoom)
setSplashStateUseCase(
if (response.isJoiningRoom) SplashState.MAIN
else SplashState.ENTER_ROOM
Expand All @@ -122,12 +74,12 @@ class LoginViewModel @Inject constructor(
if (throwable is HttpException) {
when (throwable.code()) {
NOT_SIGN_UP -> {
initTokenUseCase(
fcmToken = requireNotNull(fcmToken.value),
initLoginTokenUseCase(
fcmToken = fcmToken.value,
socialType = SOCIAL_TYPE,
token = requireNotNull(kakaoToken.value)
token = kakaoToken.value
)
_isUser.value = false
_isSignedUp.emit(false)
Timber.e(throwable.message)
}
ALREADY_LOGIN -> {
Expand All @@ -142,22 +94,15 @@ class LoginViewModel @Inject constructor(
}
}

fun initIsPermitAccess() {
fun postForceLogin() {
viewModelScope.launch {
postForceLoginUseCase(
fcmToken = requireNotNull(fcmToken.value),
socialType = "KAKAO",
token = requireNotNull(kakaoToken.value)
fcmToken = fcmToken.value,
socialType = SOCIAL_TYPE,
token = kakaoToken.value
).onSuccess { response ->
_isJoiningRoom.value = response.isJoiningRoom
initTokenUseCase(
fcmToken = requireNotNull(fcmToken.value),
socialType = SOCIAL_TYPE,
token = requireNotNull(kakaoToken.value)
)
initHousTokenUseCase(
token = response.token
)
_isJoiningRoom.emit(response.isJoiningRoom)
initHousTokenUseCase(token = response.token)
setSplashStateUseCase(
if (response.isJoiningRoom) SplashState.MAIN
else SplashState.ENTER_ROOM
Expand Down
Loading