Skip to content

Commit

Permalink
Merge pull request #118 from snuhcs-course/refactor/strategy
Browse files Browse the repository at this point in the history
Strategy 패턴 적용
  • Loading branch information
JH747 authored Dec 9, 2023
2 parents c96d552 + b9ed38e commit d048056
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.speechbuddy.R
import com.example.speechbuddy.data.remote.requests.AuthSendCodeRequest
import com.example.speechbuddy.data.remote.requests.AuthVerifyEmailRequest
import com.example.speechbuddy.domain.SessionManager
import com.example.speechbuddy.domain.models.AuthToken
Expand All @@ -19,6 +18,7 @@ import com.example.speechbuddy.utils.ResponseHandler
import com.example.speechbuddy.utils.Status
import com.example.speechbuddy.utils.isValidCode
import com.example.speechbuddy.utils.isValidEmail
import com.example.speechbuddy.viewmodel.strategy.NavigationSendCode
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand Down Expand Up @@ -59,7 +59,7 @@ class EmailVerificationViewModel @Inject internal constructor(
if (_uiState.value.error?.type == EmailVerificationErrorType.CODE) validateCode()
}

private fun changeLoadingState() {
fun changeLoadingState() {
_uiState.update { currentState ->
currentState.copy(
loading = !currentState.loading,
Expand Down Expand Up @@ -112,147 +112,54 @@ class EmailVerificationViewModel @Inject internal constructor(
)
}
} else {
if (source.value == "signup") sendCodeForSignup()
if (source.value == "reset_password") sendCodeForResetPassword()
else _uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.UNKNOWN,
messageId = R.string.unknown_error
)
)
}
val navigationSendCode = NavigationSendCode()
navigationSendCode.setSource(source.value!!)
navigationSendCode.sendCode(this, repository, responseHandler)
}
}

private fun sendCodeForSignup() {
changeLoadingState()
viewModelScope.launch {
repository.sendCodeForSignup(
AuthSendCodeRequest(
email = emailInput
)
).collect { result ->
changeLoadingState()
when (result.code()) {
ResponseCode.SUCCESS.value -> {
_uiState.update { currentState ->
currentState.copy(
isCodeSuccessfullySent = true,
error = null
)
}
}

ResponseCode.BAD_REQUEST.value -> {
val errorMessageId =
when (responseHandler.parseErrorResponse(result.errorBody()!!).key) {
"email" -> R.string.wrong_email
"already_taken" -> R.string.email_already_taken
else -> R.string.unknown_error
}
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.EMAIL,
messageId = errorMessageId
)
)
}
}

ResponseCode.NO_INTERNET_CONNECTION.value -> {
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.CONNECTION,
messageId = R.string.connection_error
)
)
}
}

else -> {
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.UNKNOWN,
messageId = R.string.unknown_error
)
)
}
}
}
}
fun handleSendCodeSuccess() {
_uiState.update { currentState ->
currentState.copy(
isCodeSuccessfullySent = true,
error = null
)
}
}

private fun sendCodeForResetPassword() {
changeLoadingState()
viewModelScope.launch {
repository.sendCodeForResetPassword(
AuthSendCodeRequest(
email = emailInput
fun handleSendCodeBadRequest(errorMessageId: Int) {
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.EMAIL,
messageId = errorMessageId
)
).collect { result ->
changeLoadingState()
when (result.code()) {
ResponseCode.SUCCESS.value -> {
_uiState.update { currentState ->
currentState.copy(
isCodeSuccessfullySent = true,
error = null
)
}
}

ResponseCode.BAD_REQUEST.value -> {
val errorMessageId =
when (responseHandler.parseErrorResponse(result.errorBody()!!).key) {
"email" -> R.string.wrong_email
"no_user" -> R.string.unregistered_email
else -> R.string.unknown_error
}
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.EMAIL,
messageId = errorMessageId
)
)
}
}
)
}
}

ResponseCode.NO_INTERNET_CONNECTION.value -> {
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.CONNECTION,
messageId = R.string.connection_error
)
)
}
}
fun handleSendCodeNoInternetConnection() {
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.CONNECTION,
messageId = R.string.connection_error
)
)
}
}

else -> {
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.UNKNOWN,
messageId = R.string.unknown_error
)
)
}
}
}
}
fun handleSendCodeUnknownError() {
_uiState.update { currentState ->
currentState.copy(
isValidEmail = false,
error = EmailVerificationError(
type = EmailVerificationErrorType.UNKNOWN,
messageId = R.string.unknown_error
)
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.speechbuddy.viewmodel.strategy

import com.example.speechbuddy.repository.AuthRepository
import com.example.speechbuddy.utils.ResponseHandler
import com.example.speechbuddy.viewmodel.EmailVerificationViewModel

class NavigationSendCode {
private lateinit var sendCodeStrategy: SendCodeStrategy
private lateinit var source : String

fun setSource(source: String) {
this.source = source
if(source=="signup") {
sendCodeStrategy = SendCodeForSignupStrategy()
} else if(source=="reset_password") {
sendCodeStrategy = SendCodeForResetPasswordStrategy()
}
}

fun sendCode(viewModel: EmailVerificationViewModel, repository: AuthRepository, responseHandler: ResponseHandler) {
sendCodeStrategy.sendCode(viewModel, repository, responseHandler)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.example.speechbuddy.viewmodel.strategy

import androidx.lifecycle.viewModelScope
import com.example.speechbuddy.R
import com.example.speechbuddy.data.remote.requests.AuthSendCodeRequest
import com.example.speechbuddy.repository.AuthRepository
import com.example.speechbuddy.utils.ResponseCode
import com.example.speechbuddy.utils.ResponseHandler
import com.example.speechbuddy.viewmodel.EmailVerificationViewModel
import kotlinx.coroutines.launch

class SendCodeForResetPasswordStrategy: SendCodeStrategy {
override fun sendCode(viewModel: EmailVerificationViewModel, repository: AuthRepository, responseHandler: ResponseHandler) {
viewModel.changeLoadingState()
viewModel.viewModelScope.launch {
repository.sendCodeForResetPassword(
AuthSendCodeRequest(
email = viewModel.emailInput
)
).collect { result ->
viewModel.changeLoadingState()
when (result.code()) {
ResponseCode.SUCCESS.value -> {
viewModel.handleSendCodeSuccess()
}

ResponseCode.BAD_REQUEST.value -> {
val errorMessageId =
when (responseHandler.parseErrorResponse(result.errorBody()!!).key) {
"email" -> R.string.wrong_email
"no_user" -> R.string.unregistered_email
else -> R.string.unknown_error
}
viewModel.handleSendCodeBadRequest(errorMessageId)
}

ResponseCode.NO_INTERNET_CONNECTION.value -> {
viewModel.handleSendCodeNoInternetConnection()
}

else -> {
viewModel.handleSendCodeUnknownError()
}
}
}
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.speechbuddy.viewmodel.strategy

import androidx.lifecycle.viewModelScope
import com.example.speechbuddy.R
import com.example.speechbuddy.data.remote.requests.AuthSendCodeRequest
import com.example.speechbuddy.repository.AuthRepository
import com.example.speechbuddy.utils.ResponseCode
import com.example.speechbuddy.utils.ResponseHandler
import com.example.speechbuddy.viewmodel.EmailVerificationViewModel
import kotlinx.coroutines.launch

class SendCodeForSignupStrategy: SendCodeStrategy {
override fun sendCode(viewModel: EmailVerificationViewModel, repository: AuthRepository, responseHandler: ResponseHandler) {
viewModel.changeLoadingState()
viewModel.viewModelScope.launch {
repository.sendCodeForSignup(
AuthSendCodeRequest(
email = viewModel.emailInput
)
).collect { result ->
viewModel.changeLoadingState()
when (result.code()) {
ResponseCode.SUCCESS.value -> {
viewModel.handleSendCodeSuccess()
}

ResponseCode.BAD_REQUEST.value -> {
val errorMessageId =
when (responseHandler.parseErrorResponse(result.errorBody()!!).key) {
"email" -> R.string.wrong_email
"already_taken" -> R.string.email_already_taken
else -> R.string.unknown_error
}
viewModel.handleSendCodeBadRequest(errorMessageId)
}

ResponseCode.NO_INTERNET_CONNECTION.value -> {
viewModel.handleSendCodeNoInternetConnection()
}

else -> {
viewModel.handleSendCodeUnknownError()
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.speechbuddy.viewmodel.strategy

import com.example.speechbuddy.repository.AuthRepository
import com.example.speechbuddy.utils.ResponseHandler
import com.example.speechbuddy.viewmodel.EmailVerificationViewModel

interface SendCodeStrategy {
fun sendCode(viewModel: EmailVerificationViewModel, repository: AuthRepository, responseHandler: ResponseHandler)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.newSingleThreadContext
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import okhttp3.ResponseBody.Companion.toResponseBody
Expand Down Expand Up @@ -312,18 +313,6 @@ class EmailVerificationViewModelTest {

coVerify { navigateCallback("reset_password") }
}

@Test
fun `should fail code send when source is invalid`() {
viewModel.setSource("invalid source")
viewModel.setEmail(validEmail)
viewModel.sendCode()

assertEquals(viewModel.uiState.value.error?.type, EmailVerificationErrorType.UNKNOWN)
assertEquals(viewModel.uiState.value.error?.messageId, R.string.unknown_error)
assertEquals(viewModel.uiState.value.isCodeSuccessfullySent, false)
}

@Test
fun `should fail code send when bad request occurs`() {
val sendCodeRequest = AuthSendCodeRequest(wrongEmail)
Expand Down

0 comments on commit d048056

Please sign in to comment.