Skip to content
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
32 changes: 14 additions & 18 deletions app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,6 @@ class TokenInterceptor @Inject constructor(
return chain.proceed(newRequest)
} else {
/**
*
*
* refreshTokenResponse : Response{protocol=http/1.1, code=401, message=, url=https://prod.eat-ssu.shop/oauths/reissue/token}
* 위 상황에서도 로그아웃
* 리프레쉬도 상한 상태
*/
runBlocking { logoutUseCase() }
Expand Down Expand Up @@ -145,27 +141,27 @@ class TokenInterceptor @Inject constructor(
}

if (response.code == 404) {
runBlocking { logoutUseCase() }
// runBlocking { logoutUseCase() }
Timber.e("404 + 다른 유저!")

Handler(Looper.getMainLooper()).post {
Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show()
val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
context.startActivity(intent)
}
// Handler(Looper.getMainLooper()).post {
// Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show()
// val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
// context.startActivity(intent)
// }
}

if (response.code == 500) {
runBlocking { logoutUseCase() }
// runBlocking { logoutUseCase() }
Timber.e("500 + 다른 유저")

Handler(Looper.getMainLooper()).post {
Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show()
val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
context.startActivity(intent)
}
// Handler(Looper.getMainLooper()).post {
// Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show()
// val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
// context.startActivity(intent)
// }
}

return response
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.eatssu.android.domain.usecase.auth

import com.eatssu.android.data.dto.response.BaseResponse
import com.eatssu.android.domain.repository.UserRepository
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class GetIsAccessTokenValidUseCase @Inject constructor(
private val userRepository: UserRepository,
) {
suspend operator fun invoke(): Flow<BaseResponse<Boolean>> =
userRepository.checkUserNameValidation("qkqh") //todo api 만들어지면 수정
Copy link

Copilot AI Apr 9, 2025

Choose a reason for hiding this comment

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

The use-case currently calls 'checkUserNameValidation', which does not align with token validation. Update the repository method to reflect token validation once the proper API is available.

Copilot uses AI. Check for mistakes.
}
10 changes: 10 additions & 0 deletions app/src/main/java/com/eatssu/android/presentation/UiEvent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.eatssu.android.presentation


/**
* 각 Screen에 공통적인 이벤트 타입입니다.
* 이벤트 타입을 추가하고 싶다면 UiEvent를 상속받아 사용하세요.
*/
interface UiEvent {
data class ShowToast(val message: String) : UiEvent
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/eatssu/android/presentation/UiState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.eatssu.android.presentation

sealed interface UiState<out T> {
object Init : UiState<Nothing>

object Loading : UiState<Nothing>

data class Success<out T>(
val data: T? = null,
) : UiState<T>

object Error : UiState<Nothing>
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.eatssu.android.presentation.login

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.eatssu.android.R
import com.eatssu.android.databinding.ActivityIntroBinding
import com.eatssu.android.presentation.UiEvent
import com.eatssu.android.presentation.UiState
import com.eatssu.android.presentation.main.MainActivity
import com.eatssu.android.presentation.util.showToast
import com.eatssu.android.presentation.util.startActivity
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
Expand All @@ -17,36 +18,39 @@ import kotlinx.coroutines.launch
class IntroActivity : AppCompatActivity() {

private val introViewModel: IntroViewModel by viewModels()
private lateinit var binding: ActivityIntroBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_intro)
binding = ActivityIntroBinding.inflate(layoutInflater)
setContentView(binding.root)

// 일정 시간 지연 이후 실행하기 위한 코드
Handler(Looper.getMainLooper()).postDelayed({

introViewModel.autoLogin()

lifecycleScope.launch {
introViewModel.uiState.collectLatest {
if (it.isAutoLogined) {
lifecycleScope.launch {
introViewModel.uiState.collectLatest { state ->
when (state) {
is UiState.Success -> {
startActivity<MainActivity>()

// 이전 키를 눌렀을 때 스플래스 스크린 화면으로 이동을 방지하기 위해
// 이동한 다음 사용안함으로 finish 처리
finish()
} else {
startActivity<LoginActivity>()
}

// 이전 키를 눌렀을 때 스플래스 스크린 화면으로 이동을 방지하기 위해
// 이동한 다음 사용안함으로 finish 처리
is UiState.Error -> {
// 로그인 액티비티로 이동
startActivity<LoginActivity>()
finish()
}

else -> Unit
}
}

}, 2000) // 시간 2초 이후 실행

introViewModel.uiEvent.collectLatest { event ->
when (event) {
is UiEvent.ShowToast -> {
// 에러 메시지 표시
showToast(event.message)
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,70 @@ package com.eatssu.android.presentation.login
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.eatssu.android.domain.usecase.auth.GetAccessTokenUseCase
import com.eatssu.android.domain.usecase.auth.GetIsAccessTokenValidUseCase
import com.eatssu.android.presentation.UiEvent
import com.eatssu.android.presentation.UiState
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.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class IntroViewModel @Inject constructor(
private val getAccessTokenUseCase: GetAccessTokenUseCase
private val getAccessTokenUseCase: GetAccessTokenUseCase,
private val getIsAccessTokenValidUseCase: GetIsAccessTokenValidUseCase
) : ViewModel() {

private val _uiState: MutableStateFlow<IntroState> = MutableStateFlow(IntroState())
val uiState: StateFlow<IntroState> = _uiState.asStateFlow()
private val _uiState: MutableStateFlow<UiState<IntroState>> = MutableStateFlow(UiState.Init)
val uiState: StateFlow<UiState<IntroState>> = _uiState.asStateFlow()

private val _uiEvent = MutableSharedFlow<UiEvent>()
val uiEvent: SharedFlow<UiEvent> = _uiEvent

init {
autoLogin()
}

fun autoLogin() {
private fun autoLogin() {
viewModelScope.launch {
if (getAccessTokenUseCase().isEmpty()) {
_uiState.update { it.copy(isAutoLogined = false) }
} else {
_uiState.update { it.copy(isAutoLogined = true) }
_uiState.value = UiState.Loading

try {
// 토큰 존재 여부 확인
if (getAccessTokenUseCase().isEmpty()) {
_uiState.value = UiState.Error
_uiEvent.emit(UiEvent.ShowToast("로그인이 필요합니다"))
return@launch
}

checkValid()

} catch (e: Exception) {
_uiState.value = UiState.Error
_uiEvent.emit(UiEvent.ShowToast("오류가 발생했습니다: ${e.message}"))
}
}
}

private fun checkValid() {
viewModelScope.launch {
getIsAccessTokenValidUseCase()
.collect {
if (it.result == true) { //토큰이 있고 유효함
_uiState.value = UiState.Success(IntroState.ValidToken)
} else { //토큰이 있어도 유효하지 않음
_uiState.value = UiState.Error
Copy link
Member

Choose a reason for hiding this comment

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

저도 여기 Error 로 두는 것 좋은 것 같아요~

_uiEvent.emit(UiEvent.ShowToast("로그인이 필요합니다"))
}
}
}
}
}

data class IntroState(
var toastMessage: String = "",
var loading: Boolean = true,
var error: Boolean = false,
var isAutoLogined: Boolean = false,
)
sealed class IntroState {
object ValidToken : IntroState()
}