Skip to content

Commit

Permalink
[MERGE] #349 -> develop
Browse files Browse the repository at this point in the history
[REFACTOR/#349] 3차 스프린트 진입 전 코드 정리
  • Loading branch information
Marchbreeze authored Jan 26, 2024
2 parents c4e6972 + 5778944 commit f578265
Show file tree
Hide file tree
Showing 38 changed files with 591 additions and 769 deletions.
2 changes: 0 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>

<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

<queries>
<package android:name="com.instagram.android" />
</queries>
Expand Down
18 changes: 17 additions & 1 deletion app/src/main/java/com/el/yello/di/RetrofitModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import retrofit2.Converter
import retrofit2.Retrofit
import timber.log.Timber
import javax.inject.Singleton

@Module
Expand All @@ -45,7 +47,21 @@ object RetrofitModule {
@Provides
@Singleton
@Logger
fun provideHttpLoggingInterceptor(): Interceptor = HttpLoggingInterceptor().apply {
fun provideHttpLoggingInterceptor(): Interceptor = HttpLoggingInterceptor { message ->
when {
message.startsWith("{") && message.endsWith("}") -> {
Timber.tag("okhttp").d(JSONObject(message).toString(4))
}

message.startsWith("[") && message.endsWith("]") -> {
Timber.tag("okhttp").d(JSONObject(message).toString(4))
}

else -> {
Timber.tag("okhttp").d("CONNECTION INFO -> $message")
}
}
}.apply {
level = HttpLoggingInterceptor.Level.BODY
}

Expand Down
99 changes: 28 additions & 71 deletions app/src/main/java/com/el/yello/presentation/auth/SignInActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,23 @@ class SignInActivity : BindingActivity<ActivitySignInBinding>(R.layout.activity_

private var checkNameDialog: CheckNameDialog? = null

private var userKakaoId: Long = 0
private var userName: String = String()
private var userGender: String = String()
private var userEmail: String = String()
private var userImage: String = String()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initSignInBtnListener()
viewModel.initLoginState()
viewModel.getDeviceToken()
observeDeviceTokenError()
observeAppLoginError()
observeKakaoUserInfoState()
observeKakaoUserInfoResult()
observeFriendsListValidState()
observeChangeTokenState()
observeChangeTokenResult()
observeUserDataState()
}

// 카카오톡 앱 설치 유무에 따라 로그인 진행
private fun initSignInBtnListener() {
binding.btnSignIn.setOnSingleClickListener {
AmplitudeUtils.trackEventWithProperties("click_onboarding_kakao")
viewModel.startKakaoLogIn(this)
viewModel.startLogInWithKakao(this)
}
}

Expand All @@ -65,61 +57,25 @@ class SignInActivity : BindingActivity<ActivitySignInBinding>(R.layout.activity_
}.launchIn(lifecycleScope)
}

// 카카오통 앱 로그인에 실패한 경우 웹 로그인 시도
private fun observeAppLoginError() {
viewModel.isAppLoginAvailable.flowWithLifecycle(lifecycle).onEach { available ->
if (!available) viewModel.startKakaoLogIn(this)
if (!available) viewModel.startLogInWithKakao(this)
}.launchIn(lifecycleScope)
}

// 서비스 토큰 교체 서버 통신 결과에 따라서 분기 처리 진행
private fun observeChangeTokenState() {
viewModel.postChangeTokenState.flowWithLifecycle(lifecycle).onEach { state ->
when (state) {
is UiState.Success -> {
// 200(가입된 아이디): 온보딩 뷰 생략하고 바로 메인 화면으로 이동 위해 유저 정보 받기
viewModel.getUserDataFromServer()
}

is UiState.Failure -> {
if (state.msg == CODE_NOT_SIGNED_IN || state.msg == CODE_NO_UUID) {
// 403, 404 : 온보딩 뷰로 이동 위해 카카오 유저 정보 얻기
viewModel.getKakaoInfo()
} else {
// 나머지 : 에러 발생
toast(getString(R.string.sign_in_error_connection))
}
}

is UiState.Loading -> return@onEach

is UiState.Empty -> return@onEach
}
private fun observeChangeTokenResult() {
viewModel.postChangeTokenResult.flowWithLifecycle(lifecycle).onEach { result ->
if (!result) toast(getString(R.string.sign_in_error_connection))
}.launchIn(lifecycleScope)
}

// Failure -> 카카오에 등록된 유저 정보 받아온 후 친구목록 동의 화면으로 이동
private fun observeKakaoUserInfoState() {
viewModel.getKakaoInfoState.flowWithLifecycle(lifecycle).onEach { state ->
when (state) {
is UiState.Success -> {
userKakaoId = state.data?.id ?: 0
userName = state.data?.kakaoAccount?.name.toString()
userGender = state.data?.kakaoAccount?.gender.toString()
userEmail = state.data?.kakaoAccount?.email.toString()
userImage = state.data?.kakaoAccount?.profile?.profileImageUrl.toString()
viewModel.checkFriendsListValid()
}

is UiState.Failure -> yelloSnackbar(binding.root, getString(R.string.msg_error))

is UiState.Empty -> return@onEach

is UiState.Loading -> return@onEach
}
private fun observeKakaoUserInfoResult() {
viewModel.getKakaoInfoResult.flowWithLifecycle(lifecycle).onEach { result ->
if (!result) yelloSnackbar(binding.root, getString(R.string.msg_error))
}.launchIn(lifecycleScope)
}

// ChangeToken Failure -> 카카오에 등록된 유저 정보 받아온 후 친구목록 동의 or 온보딩 화면으로 이동
private fun observeFriendsListValidState() {
viewModel.getKakaoValidState.flowWithLifecycle(lifecycle).onEach { state ->
when (state) {
Expand All @@ -141,7 +97,7 @@ class SignInActivity : BindingActivity<ActivitySignInBinding>(R.layout.activity_
}.launchIn(lifecycleScope)
}

// Success -> 서버에 등록된 유저 정보가 있는지 확인 후 메인 액티비티로 이동
// ChangeToken Success -> 서버에 등록된 유저 정보가 있는지 확인 후 메인 액티비티로 이동
private fun observeUserDataState() {
viewModel.getUserProfileState.flowWithLifecycle(lifecycle).onEach { state ->
when (state) {
Expand Down Expand Up @@ -185,7 +141,7 @@ class SignInActivity : BindingActivity<ActivitySignInBinding>(R.layout.activity_

private fun startCheckNameDialog() {
val bundle = Bundle().apply { addPutExtra() }
if (userName.isBlank() || userName.isEmpty()) {
if (viewModel.isUserNameBlank()) {
Intent(SignInActivity(), EditNameActivity::class.java).apply {
putExtras(bundle)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
Expand All @@ -205,21 +161,24 @@ class SignInActivity : BindingActivity<ActivitySignInBinding>(R.layout.activity_
}

private fun Intent.addPutExtra() {
putExtra(EXTRA_KAKAO_ID, userKakaoId)
putExtra(EXTRA_NAME, userName)
putExtra(EXTRA_GENDER, userGender)
putExtra(EXTRA_EMAIL, userEmail)
putExtra(EXTRA_PROFILE_IMAGE, userImage)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
if (viewModel.checkKakaoUserInfoStored()) {
putExtra(EXTRA_KAKAO_ID, viewModel.kakaoUserInfo.id)
putExtra(EXTRA_NAME, viewModel.kakaoUserInfo.kakaoAccount?.name.orEmpty())
putExtra(EXTRA_GENDER, viewModel.kakaoUserInfo.kakaoAccount?.gender.toString())
putExtra(EXTRA_EMAIL, viewModel.kakaoUserInfo.kakaoAccount?.email.orEmpty())
putExtra(EXTRA_PROFILE_IMAGE, viewModel.kakaoUserInfo.kakaoAccount?.profile?.profileImageUrl.orEmpty())
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
}


private fun Bundle.addPutExtra() {
putLong(EXTRA_KAKAO_ID, userKakaoId)
putString(EXTRA_NAME, userName)
putString(EXTRA_GENDER, userGender)
putString(EXTRA_EMAIL, userEmail)
putString(EXTRA_PROFILE_IMAGE, userImage)
if (viewModel.checkKakaoUserInfoStored()) {
putLong(EXTRA_KAKAO_ID, viewModel.kakaoUserInfo.id ?: 0)
putString(EXTRA_NAME, viewModel.kakaoUserInfo.kakaoAccount?.name.orEmpty())
putString(EXTRA_GENDER, viewModel.kakaoUserInfo.kakaoAccount?.gender.toString())
putString(EXTRA_EMAIL, viewModel.kakaoUserInfo.kakaoAccount?.email.orEmpty())
putString(EXTRA_PROFILE_IMAGE, viewModel.kakaoUserInfo.kakaoAccount?.profile?.profileImageUrl.orEmpty())
}
}

override fun onDestroy() {
Expand All @@ -233,8 +192,6 @@ class SignInActivity : BindingActivity<ActivitySignInBinding>(R.layout.activity_
const val EXTRA_PROFILE_IMAGE = "PROFILE_IMAGE"
const val EXTRA_NAME = "NAME"
const val EXTRA_GENDER = "GENDER"
const val CODE_NOT_SIGNED_IN = "403"
const val CODE_NO_UUID = "404"
const val CHECK_NAME_DIALOG = "CHECK_NAME_DIALOG"
}
}
62 changes: 30 additions & 32 deletions app/src/main/java/com/el/yello/presentation/auth/SignInViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ package com.el.yello.presentation.auth
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.el.yello.presentation.auth.SignInActivity.Companion.CODE_NOT_SIGNED_IN
import com.el.yello.presentation.auth.SignInActivity.Companion.CODE_NO_UUID
import com.example.domain.entity.AuthTokenModel
import com.example.domain.entity.AuthTokenRequestModel
import com.example.domain.entity.ProfileUserModel
import com.example.domain.repository.AuthRepository
Expand All @@ -20,7 +17,9 @@ import com.kakao.sdk.user.UserApiClient
import com.kakao.sdk.user.model.Scope
import com.kakao.sdk.user.model.User
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import retrofit2.HttpException
Expand All @@ -33,14 +32,16 @@ class SignInViewModel @Inject constructor(
private val profileRepository: ProfileRepository
) : ViewModel() {

private val _postChangeTokenState = MutableStateFlow<UiState<AuthTokenModel>>(UiState.Empty)
val postChangeTokenState: StateFlow<UiState<AuthTokenModel?>> = _postChangeTokenState
private val _postChangeTokenResult = MutableSharedFlow<Boolean>()
val postChangeTokenResult: SharedFlow<Boolean> = _postChangeTokenResult

private val _getUserProfileState = MutableStateFlow<UiState<ProfileUserModel>>(UiState.Empty)
val getUserProfileState: StateFlow<UiState<ProfileUserModel>> = _getUserProfileState

private val _getKakaoInfoState = MutableStateFlow<UiState<User>>(UiState.Empty)
val getKakaoInfoState: StateFlow<UiState<User?>> = _getKakaoInfoState
private val _getKakaoInfoResult = MutableSharedFlow<Boolean>()
val getKakaoInfoResult: SharedFlow<Boolean> = _getKakaoInfoResult

lateinit var kakaoUserInfo: User

private val _getKakaoValidState = MutableStateFlow<UiState<List<Scope>>>(UiState.Empty)
val getKakaoValidState: StateFlow<UiState<List<Scope>>> = _getKakaoValidState
Expand Down Expand Up @@ -69,7 +70,6 @@ class SignInViewModel @Inject constructor(

private var appLoginCallback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
// 뒤로가기 경우 예외 처리
if (!(error is ClientError && error.reason == ClientErrorCause.Cancelled)) {
_isAppLoginAvailable.value = false
}
Expand All @@ -81,12 +81,7 @@ class SignInViewModel @Inject constructor(
}
}

fun initLoginState() {
_isAppLoginAvailable.value = true
_getDeviceTokenError.value = false
}

fun startKakaoLogIn(context: Context) {
fun startLogInWithKakao(context: Context) {
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context) && isAppLoginAvailable.value) {
UserApiClient.instance.loginWithKakaoTalk(
context = context,
Expand All @@ -102,22 +97,27 @@ class SignInViewModel @Inject constructor(
}
}

// 카카오 통신 - 카카오 유저 정보 받아오기
fun getKakaoInfo() {
private fun getUserInfoFromKakao() {
UserApiClient.instance.me { user, _ ->
_getKakaoInfoState.value = UiState.Loading
try {
if (user != null) {
_getKakaoInfoState.value = UiState.Success(user)
return@me
kakaoUserInfo = user
checkFriendsListValidFromKakao()
}
} catch (e: IllegalArgumentException) {
_getKakaoInfoState.value = UiState.Failure(e.message.toString())
viewModelScope.launch {
_getKakaoInfoResult.emit(false)
}
}
}
}

fun checkFriendsListValid() {
fun checkKakaoUserInfoStored() = ::kakaoUserInfo.isInitialized

fun isUserNameBlank() =
!::kakaoUserInfo.isInitialized || kakaoUserInfo.kakaoAccount?.name.isNullOrEmpty()

private fun checkFriendsListValidFromKakao() {
val scopes = mutableListOf(FRIEND_LIST)
_getKakaoValidState.value = UiState.Loading
UserApiClient.instance.scopes(scopes) { scopeInfo, error ->
Expand All @@ -131,39 +131,37 @@ class SignInViewModel @Inject constructor(
}
}

// 서버통신 - 카카오 토큰 보내서 서비스 토큰 받아오기
private fun changeTokenFromServer(
accessToken: String,
social: String = KAKAO,
deviceToken: String
) {
_postChangeTokenState.value = UiState.Loading
viewModelScope.launch {
onboardingRepository.postTokenToServiceToken(
AuthTokenRequestModel(accessToken, social, deviceToken),
)
.onSuccess {
// 200(가입된 아이디): 온보딩 뷰 생략하고 바로 메인 화면으로 이동 위해 유저 정보 받기
if (it == null) {
_postChangeTokenState.value = UiState.Empty
_postChangeTokenResult.emit(false)
return@launch
}
authRepository.setAutoLogin(it.accessToken, it.refreshToken)
isResigned = it.isResigned
_postChangeTokenState.value = UiState.Success(it)
getUserDataFromServer()
}
.onFailure {
val errorMessage = when {
it is HttpException && it.code() == 403 -> CODE_NOT_SIGNED_IN
it is HttpException && it.code() == 404 -> CODE_NO_UUID
else -> ERROR
// 403, 404 : 온보딩 뷰로 이동 위해 카카오 유저 정보 얻기
if (it is HttpException && (it.code() == 403 || it.code() == 404)) {
getUserInfoFromKakao()
} else {
_postChangeTokenResult.emit(false)
}
_postChangeTokenState.value = UiState.Failure(errorMessage)
}
}
}

// 서버통신 - (가입되어 있는) 유저 정보 가져오기
fun getUserDataFromServer() {
private fun getUserDataFromServer() {
_getUserProfileState.value = UiState.Loading
viewModelScope.launch {
profileRepository.getUserData()
Expand Down
Loading

0 comments on commit f578265

Please sign in to comment.