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

JmtException 실험용 코드(커스텀 Exeption) #72

Merged
merged 4 commits into from
Sep 16, 2023
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package org.gdsc.data.datasource

import org.gdsc.domain.model.Response
import org.gdsc.domain.model.response.TokenResponse

interface LoginDataSource {
suspend fun postSignUpWithGoogleToken(token: String): TokenResponse
suspend fun postSignUpWithGoogleToken(token: String): Result<Response<TokenResponse>>

suspend fun postAppleToken(email: String, clientId: String): TokenResponse

Expand Down
16 changes: 14 additions & 2 deletions data/src/main/java/org/gdsc/data/datasource/LoginDataSourceImpl.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.gdsc.data.datasource

import org.gdsc.domain.model.Response
import org.gdsc.data.network.LoginAPI
import org.gdsc.domain.exception.JmtException
import org.gdsc.domain.model.request.AppleLoginRequest
import org.gdsc.domain.model.request.GoogleLoginRequest
import org.gdsc.domain.model.response.TokenResponse
Expand All @@ -10,8 +12,18 @@ import javax.inject.Inject
class LoginDataSourceImpl @Inject constructor(
private val loginAPI: LoginAPI
) : LoginDataSource {
override suspend fun postSignUpWithGoogleToken(token: String): TokenResponse {
return loginAPI.postUserGoogleToken(GoogleLoginRequest(token)).data
override suspend fun postSignUpWithGoogleToken(token: String): Result<Response<TokenResponse>> {
return runCatching {
loginAPI.postUserGoogleToken(GoogleLoginRequest(token)).body()
?: throw JmtException.NoneDataException()
}.onFailure {
throw if (it.message != null) {
JmtException.GeneralException(requireNotNull(it.message))
} else {
JmtException.UnKnownException()
}
}

}

override suspend fun postAppleToken(email: String, clientId: String): TokenResponse {
Expand Down
6 changes: 2 additions & 4 deletions data/src/main/java/org/gdsc/data/network/LoginAPI.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package org.gdsc.data.network


import org.gdsc.data.model.Response
import org.gdsc.domain.model.Response
import org.gdsc.domain.model.request.GoogleLoginRequest
import org.gdsc.domain.model.request.AppleLoginRequest
import org.gdsc.domain.model.response.TokenResponse
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.HTTP
import retrofit2.http.POST

interface LoginAPI {
@POST("api/v1/auth/google")
suspend fun postUserGoogleToken(
@Body request: GoogleLoginRequest
): Response<TokenResponse>
): retrofit2.Response<Response<TokenResponse>>

@POST("api/v1/auth/android/apple")
suspend fun postUserAppleToken(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import javax.inject.Inject
class LoginRepositoryImpl @Inject constructor(private val loginDataSource: LoginDataSource) :
LoginRepository {

override suspend fun postSignUpWithGoogleToken(token: String): TokenResponse {
return loginDataSource.postSignUpWithGoogleToken(token)
override suspend fun postSignUpWithGoogleToken(token: String): Result<TokenResponse> {
return kotlin.runCatching {
loginDataSource.postSignUpWithGoogleToken(token).getOrThrow().data
}
}

override suspend fun postAppleToken(email: String, clientId: String): TokenResponse {
Expand Down
15 changes: 15 additions & 0 deletions domain/src/main/java/org/gdsc/domain/exception/JmtException.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.gdsc.domain.exception

import org.gdsc.domain.Empty

sealed class JmtException(
message: String = String.Empty
) : Exception(message) {

data class NetworkException(override val message: String = "네트워크 연결을 확인해주세요.") : JmtException()
data class ServerException(override val message: String = "서버에 문제가 발생했습니다.") : JmtException()
data class NoneDataException(override val message: String = "데이터가 없습니다.") : JmtException()
data class UnKnownException(override val message: String = "알 수 없는 에러입니다.") : JmtException()
data class GeneralException(override val message: String) : JmtException()

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.gdsc.domain.model.response.TokenResponse

interface LoginRepository {

suspend fun postSignUpWithGoogleToken(token: String): TokenResponse
suspend fun postSignUpWithGoogleToken(token: String): Result<TokenResponse>

suspend fun postAppleToken(email: String, clientId: String): TokenResponse

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import javax.inject.Singleton
class PostSignUpWithGoogleTokenUseCase @Inject constructor(
private val loginRepository: LoginRepository
) {
suspend operator fun invoke(token: String): TokenResponse {
suspend operator fun invoke(token: String): Result<TokenResponse> {
return loginRepository.postSignUpWithGoogleToken(token)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import kotlinx.coroutines.launch
import org.gdsc.domain.model.response.UserLoginAction
import org.gdsc.presentation.R
import org.gdsc.presentation.databinding.FragmentLoginBinding
import org.gdsc.presentation.utils.repeatWhenUiStarted
import org.gdsc.presentation.view.LoginManager
import org.gdsc.presentation.view.MainActivity

Expand All @@ -45,6 +46,13 @@ class LoginFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setLoginButton()

repeatWhenUiStarted {
// TODO: specific handling
viewModel.eventFlow.collect {
Toast.makeText(requireContext(), it.message, Toast.LENGTH_SHORT).show()
}
}
}

private fun setLoginButton() {
Expand All @@ -57,7 +65,7 @@ class LoginFragment : Fragment() {
.build()
)
} catch (e: ApiException) {
Log.e("Login","ApiException $e")
Log.e("Login", "ApiException $e")
showGoogleAccountRegistrationPrompt()
} catch (e: Exception) {
Log.e("Login", "setLoginButton Exception $e")
Expand Down Expand Up @@ -96,12 +104,13 @@ class LoginFragment : Fragment() {
val credential = loginManager.oneTapClient.getSignInCredentialFromIntent(intent)
credential.googleIdToken?.let {
viewModel.postSignUpWithGoogleToken(it) { tokenResponse ->
when(tokenResponse.userLoginAction) {
when (tokenResponse.userLoginAction) {
UserLoginAction.SIGN_UP.value -> {
val action =
LoginFragmentDirections.actionLoginFragmentToSignUpNicknameFragment()
findNavController().navigate(action)
}

UserLoginAction.LOG_IN.value -> {
val intent = Intent(requireContext(), MainActivity::class.java)
startActivity(intent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import okhttp3.MultipartBody
import org.gdsc.domain.Empty
import org.gdsc.domain.exception.JmtException
import org.gdsc.domain.model.response.TokenResponse
import org.gdsc.domain.usecase.CheckDuplicatedNicknameUseCase
import org.gdsc.domain.usecase.PostNicknameUseCase
import org.gdsc.domain.usecase.PostSignUpWithGoogleTokenUseCase
import org.gdsc.domain.usecase.token.SaveTokenUseCase
import org.gdsc.domain.usecase.user.PostDefaultProfileImageUseCase
import org.gdsc.domain.usecase.user.PostProfileImageUseCase
import org.gdsc.presentation.utils.MutableEventFlow
import org.gdsc.presentation.utils.asEventFlow
import javax.inject.Inject

@HiltViewModel
Expand All @@ -37,6 +40,9 @@ class LoginViewModel @Inject constructor(
private var _profileImageState = MutableStateFlow(String.Empty)
val profileImageState = _profileImageState.asStateFlow()

private var _eventFlow = MutableEventFlow<JmtException>()
val eventFlow = _eventFlow.asEventFlow()

val isNicknameVerified: StateFlow<Boolean>
get() = nicknameState.map { nickname ->
nickname.isNotBlank()
Expand All @@ -56,9 +62,13 @@ class LoginViewModel @Inject constructor(

fun postSignUpWithGoogleToken(token: String, afterSuccessSignUp: (TokenResponse) -> Unit) {
viewModelScope.launch {
val response = postSignUpWithGoogleTokenUseCase.invoke(token)
saveTokenUseCase.invoke(response)
afterSuccessSignUp(response)
val result = postSignUpWithGoogleTokenUseCase.invoke(token)
result.onSuccess { response ->
saveTokenUseCase.invoke(response)
afterSuccessSignUp(response)
}.onFailure {
_eventFlow.emit(it as JmtException)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.gdsc.domain.usecase.token.GetRefreshTokenUseCase
Expand Down Expand Up @@ -34,7 +33,7 @@ class SplashActivity : AppCompatActivity() {
setContentView(R.layout.activity_splash)
setToFullPage()

lifecycleScope.launch(Dispatchers.Main) {
lifecycleScope.launch {

val accessible = validateToken()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.gdsc.presentation.utils

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableSharedFlow
import org.gdsc.presentation.utils.EventFlow.Companion.DEFAULT_REPLAY
import java.util.concurrent.atomic.AtomicBoolean

interface EventFlow<out T> : Flow<T> {

companion object {
const val DEFAULT_REPLAY = 2
}
}

interface MutableEventFlow<T> : EventFlow<T>, FlowCollector<T>

private class EventFlowSlot<T>(val value: T) {

private val consumed = AtomicBoolean(false)

fun markConsumed() = consumed.getAndSet(true)
}

private class EventFlowImpl<T>(replay: Int) : MutableEventFlow<T> {

private val flow: MutableSharedFlow<EventFlowSlot<T>> = MutableSharedFlow(replay)

override suspend fun collect(collector: FlowCollector<T>) =
flow.collect { slot ->
if (slot.markConsumed().not()) {
collector.emit(slot.value)
}
}

override suspend fun emit(value: T) {
flow.emit(EventFlowSlot(value))
}
}

private class ReadOnlyEventFlow<T>(flow: EventFlow<T>) : EventFlow<T> by flow

fun <T> MutableEventFlow(replay: Int = DEFAULT_REPLAY): MutableEventFlow<T> = EventFlowImpl(replay)

fun <T> MutableEventFlow<T>.asEventFlow(): EventFlow<T> = ReadOnlyEventFlow(this)
Loading