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

[FEAT/#95] 설정뷰 / 로그아웃, 탈퇴 API 구현 #96

Merged
merged 6 commits into from
Jul 31, 2024
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
4 changes: 4 additions & 0 deletions data/src/main/java/kr/genti/data/dataSource/InfoDataSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ import kr.genti.data.dto.request.SignupRequestDto

interface InfoDataSource {
suspend fun postSignupData(request: SignupRequestDto): BaseResponse<Boolean>

suspend fun postUserLogout(): BaseResponse<Boolean>

suspend fun deleteUser(): BaseResponse<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ data class InfoDataSourceImpl
private val infoService: InfoService,
) : InfoDataSource {
override suspend fun postSignupData(request: SignupRequestDto): BaseResponse<Boolean> = infoService.postSignupData(request)

override suspend fun postUserLogout(): BaseResponse<Boolean> = infoService.postUserLogout()

override suspend fun deleteUser(): BaseResponse<Boolean> = infoService.deleteUser()
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,14 @@ class InfoRepositoryImpl
runCatching {
infoDataSource.postSignupData(request.toDto()).response
}

override suspend fun postUserLogout(): Result<Boolean> =
runCatching {
infoDataSource.postUserLogout().response
}

override suspend fun deleteUser(): Result<Boolean> =
runCatching {
infoDataSource.deleteUser().response
}
}
7 changes: 7 additions & 0 deletions data/src/main/java/kr/genti/data/service/InfoService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ package kr.genti.data.service
import kr.genti.data.dto.BaseResponse
import kr.genti.data.dto.request.SignupRequestDto
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.POST

interface InfoService {
@POST("api/v1/users/signup")
suspend fun postSignupData(
@Body request: SignupRequestDto,
): BaseResponse<Boolean>

@POST("api/v1/users/logout")
suspend fun postUserLogout(): BaseResponse<Boolean>

@DELETE("api/v1/users")
suspend fun deleteUser(): BaseResponse<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ import kr.genti.domain.entity.request.SignupRequestModel

interface InfoRepository {
suspend fun postSignupData(request: SignupRequestModel): Result<Boolean>

suspend fun postUserLogout(): Result<Boolean>

suspend fun deleteUser(): Result<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(R.layout.activity_spl

setSystemWindowsTransparent()
observeAutoLoginState()
observeReissueTokenResult()
}

private fun setSystemWindowsTransparent() {
Expand All @@ -44,19 +45,35 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(R.layout.activity_spl
viewModel.isAutoLogined.flowWithLifecycle(lifecycle).distinctUntilChanged()
.onEach { isAutoLogined ->
if (isAutoLogined) {
viewModel.postToReissueToken()
} else {
navigateToLoginView()
}
}.launchIn(lifecycleScope)
}

private fun observeReissueTokenResult() {
viewModel.reissueTokenResult.flowWithLifecycle(lifecycle).distinctUntilChanged()
.onEach { isSuccess ->
if (isSuccess) {
Intent(this, MainActivity::class.java).apply {
startActivity(this)
}
finish()
} else {
Intent(this, LoginActivity::class.java).apply {
startActivity(
this,
ActivityOptions.makeCustomAnimation(this@SplashActivity, 0, 0)
.toBundle(),
)
}
navigateToLoginView()
}
finish()
}.launchIn(lifecycleScope)
}

private fun navigateToLoginView() {
Intent(this, LoginActivity::class.java).apply {
startActivity(
this,
ActivityOptions.makeCustomAnimation(this@SplashActivity, 0, 0)
.toBundle(),
)
}
finish()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import kr.genti.domain.entity.request.ReissueRequestModel
import kr.genti.domain.repository.AuthRepository
import kr.genti.domain.repository.UserRepository
import javax.inject.Inject

Expand All @@ -15,10 +17,14 @@ class SplashViewModel
@Inject
constructor(
private val userRepository: UserRepository,
private val authRepository: AuthRepository,
) : ViewModel() {
private val _isAutoLogined = MutableSharedFlow<Boolean>()
val isAutoLogined: SharedFlow<Boolean> = _isAutoLogined

private val _reissueTokenResult = MutableSharedFlow<Boolean>()
val reissueTokenResult: SharedFlow<Boolean> = _reissueTokenResult

init {
getAutoLoginState()
}
Expand All @@ -34,6 +40,22 @@ class SplashViewModel
}
}

fun postToReissueToken() {
viewModelScope.launch {
authRepository.postReissueTokens(
ReissueRequestModel(
userRepository.getAccessToken(),
userRepository.getRefreshToken(),
),
).onSuccess {
userRepository.setTokens(it.accessToken, it.refreshToken)
_reissueTokenResult.emit(true)
}.onFailure {
_reissueTokenResult.emit(false)
}
}
}

companion object {
private const val DELAY_SPLASH = 1500L
private const val ROLE_USER = "USER"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ class MainActivity : BaseActivity<ActivityMainBinding>(R.layout.activity_main) {
observeResetResult()
}

override fun onResume() {
super.onResume()
viewModel.getGenerateStatusFromServer()
}

fun initBnvItemIconTintList() {
with(binding.bnvMain) {
itemIconTintList = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ class MainViewModel
var currentStatus: GenerateStatus = GenerateStatus.NEW_REQUEST_AVAILABLE
lateinit var newPicture: GenerateStatusModel

init {
getGenerateStatusFromServer()
}

private fun getGenerateStatusFromServer() {
fun getGenerateStatusFromServer() {
viewModelScope.launch {
generateRepository.getGenerateStatus()
.onSuccess {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ import android.os.Bundle
import android.view.View
import android.view.WindowManager
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseDialog
import kr.genti.core.extension.setGusianBlur
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.stringOf
import kr.genti.core.extension.toast
import kr.genti.core.state.UiState
import kr.genti.core.util.RestartUtil.restartApp
import kr.genti.presentation.R
import kr.genti.presentation.databinding.DialogSettingLogoutBinding
Expand Down Expand Up @@ -39,22 +45,34 @@ class SettingLogoutDialog :

initReturnBtnListener()
initLogoutBtnListener()
observeUserLogoutState()
}

private fun initReturnBtnListener() {
binding.btnReturn.setOnSingleClickListener { dismiss() }
}

private fun initLogoutBtnListener() {
// TODO : 토큰 설정 이후 로그아웃 설정
binding.btnLogout.setOnSingleClickListener {
lifecycleScope.launch {
delay(500)
restartApp(binding.root.context, null)
}
viewModel.logoutFromKakao()
}
}

private fun observeUserLogoutState() {
viewModel.userLogoutState.flowWithLifecycle(lifecycle).distinctUntilChanged()
.onEach { state ->
when (state) {
is UiState.Success -> {
delay(500)
restartApp(binding.root.context, null)
}

is UiState.Failure -> toast(stringOf(R.string.error_msg))
else -> return@onEach
}
}.launchIn(lifecycleScope)
}

override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
requireActivity().window.decorView.rootView.setGusianBlur(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ import android.os.Bundle
import android.view.View
import android.view.WindowManager
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseDialog
import kr.genti.core.extension.setGusianBlur
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.util.RestartUtil
import kr.genti.core.extension.stringOf
import kr.genti.core.extension.toast
import kr.genti.core.state.UiState
import kr.genti.core.util.RestartUtil.restartApp
import kr.genti.presentation.R
import kr.genti.presentation.databinding.DialogSettingQuitBinding

Expand Down Expand Up @@ -39,22 +45,34 @@ class SettingQuitDialog :

initReturnBtnListener()
initLogoutBtnListener()
observeUserQuitState()
}

private fun initReturnBtnListener() {
binding.btnReturn.setOnSingleClickListener { dismiss() }
}

private fun initLogoutBtnListener() {
// TODO : 토큰 설정 이후 탈퇴 설정
binding.btnLogout.setOnSingleClickListener {
lifecycleScope.launch {
delay(500)
RestartUtil.restartApp(binding.root.context, null)
}
viewModel.quitFromKakao()
}
}

private fun observeUserQuitState() {
viewModel.userDeleteState.flowWithLifecycle(lifecycle).distinctUntilChanged()
.onEach { state ->
when (state) {
is UiState.Success -> {
delay(500)
restartApp(binding.root.context, null)
}

is UiState.Failure -> toast(stringOf(R.string.error_msg))
else -> return@onEach
}
}.launchIn(lifecycleScope)
}

override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
requireActivity().window.decorView.rootView.setGusianBlur(null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,73 @@
package kr.genti.presentation.setting

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kakao.sdk.user.UserApiClient
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kr.genti.core.state.UiState
import kr.genti.domain.repository.InfoRepository
import kr.genti.domain.repository.UserRepository
import javax.inject.Inject

@HiltViewModel
class SettingViewModel
@Inject
constructor(
// private val authRepository: AuthRepository
private val infoRepository: InfoRepository,
private val userRepository: UserRepository,
) : ViewModel() {
private fun clearLocalInfo() {
// authRepository.clearLocalPref()
private val _userLogoutState = MutableStateFlow<UiState<Boolean>>(UiState.Empty)
val userLogoutState: StateFlow<UiState<Boolean>> = _userLogoutState

private val _userDeleteState = MutableStateFlow<UiState<Boolean>>(UiState.Empty)
val userDeleteState: StateFlow<UiState<Boolean>> = _userDeleteState

fun logoutFromKakao() {
_userLogoutState.value = UiState.Loading
UserApiClient.instance.logout { error ->
if (error == null) {
logoutFromServer()
} else {
_userLogoutState.value = UiState.Failure(error.toString())
}
}
}

private fun logoutFromServer() {
viewModelScope.launch {
infoRepository.postUserLogout()
.onSuccess {
userRepository.clearInfo()
_userLogoutState.value = UiState.Success(it)
}.onFailure {
_userLogoutState.value = UiState.Failure(it.message.toString())
}
}
}

fun quitFromKakao() {
_userDeleteState.value = UiState.Loading
UserApiClient.instance.unlink { error ->
if (error == null) {
quitFromServer()
} else {
_userDeleteState.value = UiState.Failure(error.toString())
}
}
}

private fun quitFromServer() {
viewModelScope.launch {
infoRepository.deleteUser()
.onSuccess {
userRepository.clearInfo()
_userDeleteState.value = UiState.Success(it)
}.onFailure {
_userDeleteState.value = UiState.Failure(it.message.toString())
}
}
}
}
4 changes: 2 additions & 2 deletions presentation/src/main/res/layout/fragment_define.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@
android:id="@+id/btn_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="11dp"
android:layout_marginEnd="21dp"
android:background="#D9D9D9"
android:padding="12dp"
android:padding="9dp"
android:src="@drawable/ic_refresh"
app:layout_constraintBottom_toBottomOf="@id/tv_create_random_example"
app:layout_constraintEnd_toEndOf="parent"
Expand Down
Loading