From 2b47925d9734815186e924135302c4f768940009 Mon Sep 17 00:00:00 2001 From: boiledegg Date: Fri, 13 Dec 2024 00:53:54 +0900 Subject: [PATCH] =?UTF-8?q?feat/#14:=20SignIn=20MVI=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../and/presentation/signin/SignInScreen.kt | 36 ++++++++---- .../presentation/signin/SignInSideEffect.kt | 11 ---- .../presentation/signin/SignInViewModel.kt | 56 ++++++++++--------- .../signin/contract/SignInEvent.kt | 10 ++++ .../signin/contract/SignInSideEffect.kt | 10 ++++ .../signin/contract/SignInUiState.kt | 9 +++ .../signin/state/SignInUiState.kt | 6 -- 7 files changed, 82 insertions(+), 56 deletions(-) delete mode 100644 app/src/main/java/org/sopt/and/presentation/signin/SignInSideEffect.kt create mode 100644 app/src/main/java/org/sopt/and/presentation/signin/contract/SignInEvent.kt create mode 100644 app/src/main/java/org/sopt/and/presentation/signin/contract/SignInSideEffect.kt create mode 100644 app/src/main/java/org/sopt/and/presentation/signin/contract/SignInUiState.kt delete mode 100644 app/src/main/java/org/sopt/and/presentation/signin/state/SignInUiState.kt diff --git a/app/src/main/java/org/sopt/and/presentation/signin/SignInScreen.kt b/app/src/main/java/org/sopt/and/presentation/signin/SignInScreen.kt index f4cc3b7..70e5682 100644 --- a/app/src/main/java/org/sopt/and/presentation/signin/SignInScreen.kt +++ b/app/src/main/java/org/sopt/and/presentation/signin/SignInScreen.kt @@ -40,7 +40,9 @@ import org.sopt.and.core.extension.showWavveSnackBar import org.sopt.and.core.extension.toast import org.sopt.and.core.preference.PreferenceUtil.Companion.LocalPreference import org.sopt.and.presentation.signin.component.SignInExtraServiceGroup -import org.sopt.and.presentation.signin.state.SignInUiState +import org.sopt.and.presentation.signin.contract.SignInEvent +import org.sopt.and.presentation.signin.contract.SignInSideEffect +import org.sopt.and.presentation.signin.contract.SignInUiState @Composable fun SignInRoute( @@ -61,14 +63,16 @@ fun SignInRoute( viewModel.sideEffect.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle) .collect { sideEffect -> when (sideEffect) { - is SignInSideEffect.Toast -> context.toast( - context.getString(sideEffect.message) - ) + is SignInSideEffect.ShowToast -> { + context.toast(sideEffect.message) + } - is SignInSideEffect.SnackBar -> snackBarHost.showWavveSnackBar( - context = context, - message = sideEffect.message - ) + is SignInSideEffect.ShowSnackBar -> { + snackBarHost.showWavveSnackBar( + context = context, + message = sideEffect.message + ) + } is SignInSideEffect.NavigateToHome -> { with(preference) { @@ -88,10 +92,18 @@ fun SignInRoute( SignInScreen( uiState = uiState, snackBarHost = snackBarHost, - onIdChange = viewModel::updateId, - onPasswordChange = viewModel::updatePassword, - onLoginClick = viewModel::onSignInButtonClick, - onSignUpClick = viewModel::onSignUpButtonClick, + onIdChange = { newValue -> + viewModel.setEvent(SignInEvent.OnIdTextFieldChanged(newValue)) + }, + onPasswordChange = { newValue -> + viewModel.setEvent(SignInEvent.OnPasswordTextFieldChanged(newValue)) + }, + onLoginClick = { + viewModel.setEvent(SignInEvent.OnSignInButtonClicked) + }, + onSignUpClick = { + viewModel.setEvent(SignInEvent.OnSignUpButtonClicked) + }, modifier = modifier ) } diff --git a/app/src/main/java/org/sopt/and/presentation/signin/SignInSideEffect.kt b/app/src/main/java/org/sopt/and/presentation/signin/SignInSideEffect.kt deleted file mode 100644 index 70271d1..0000000 --- a/app/src/main/java/org/sopt/and/presentation/signin/SignInSideEffect.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.sopt.and.presentation.signin - -import androidx.annotation.StringRes - -sealed class SignInSideEffect { - data class Toast(@StringRes val message: Int) : SignInSideEffect() - data class SnackBar( val message: String) : SignInSideEffect() - data class NavigateToHome(val token: String) : SignInSideEffect() - data object NavigateToSignUp : SignInSideEffect() - -} diff --git a/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt b/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt index 4639b7d..3e766e4 100644 --- a/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt +++ b/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt @@ -1,55 +1,57 @@ package org.sopt.and.presentation.signin -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import org.sopt.and.core.viewmodel.BaseViewModel import org.sopt.and.domain.entity.User import org.sopt.and.domain.usecase.SignInUseCase -import org.sopt.and.presentation.signin.state.SignInUiState +import org.sopt.and.presentation.signin.contract.SignInEvent +import org.sopt.and.presentation.signin.contract.SignInSideEffect +import org.sopt.and.presentation.signin.contract.SignInUiState import javax.inject.Inject @HiltViewModel class SignInViewModel @Inject constructor( private val signInUseCase: SignInUseCase -) : ViewModel() { - private var _uiState = MutableStateFlow(SignInUiState()) - val uiState = _uiState.asStateFlow() +) : BaseViewModel() { - private var _sideEffect = MutableSharedFlow() - val sideEffect = _sideEffect.asSharedFlow() + override fun createInitialState(): SignInUiState = SignInUiState() - fun updateId(id: String) = _uiState.update { currentState -> - currentState.copy( - id = id - ) - } + override suspend fun handleEvent(event: SignInEvent) { + when (event) { + is SignInEvent.OnIdTextFieldChanged -> { + setState { copy(id = event.id) } + } + + is SignInEvent.OnPasswordTextFieldChanged -> { + setState { copy(password = event.password) } + } - fun updatePassword(password: String) = _uiState.update { currentState -> - currentState.copy( - password = password - ) + SignInEvent.OnSignInButtonClicked -> { + postSignIn() + } + + SignInEvent.OnSignUpButtonClicked -> { + navigateToSignUp() + } + } } - fun onSignUpButtonClick() { + private fun navigateToSignUp() { viewModelScope.launch { - _sideEffect.emit(SignInSideEffect.NavigateToSignUp) + setSideEffect(SignInSideEffect.NavigateToSignUp) } } - fun onSignInButtonClick() = viewModelScope.launch { - val user = with(_uiState.value) { User(id, password, "") } + private fun postSignIn() = viewModelScope.launch { + val user = with(currentState) { User(id, password, "") } signInUseCase.invoke(user).onSuccess { response -> response.token?.run { - _sideEffect.emit(SignInSideEffect.NavigateToHome(this)) + setSideEffect(SignInSideEffect.NavigateToHome(this)) } }.onFailure { throwable -> - _sideEffect.emit(SignInSideEffect.SnackBar(throwable.message.orEmpty())) + setSideEffect(SignInSideEffect.ShowSnackBar(throwable.message.orEmpty())) } } } \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInEvent.kt b/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInEvent.kt new file mode 100644 index 0000000..c690c3b --- /dev/null +++ b/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInEvent.kt @@ -0,0 +1,10 @@ +package org.sopt.and.presentation.signin.contract + +import org.sopt.and.core.viewmodel.UiEvent + +sealed class SignInEvent: UiEvent { + data class OnIdTextFieldChanged(val id: String): SignInEvent() + data class OnPasswordTextFieldChanged(val password: String): SignInEvent() + data object OnSignInButtonClicked: SignInEvent() + data object OnSignUpButtonClicked: SignInEvent() +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInSideEffect.kt b/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInSideEffect.kt new file mode 100644 index 0000000..9a1cdb8 --- /dev/null +++ b/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInSideEffect.kt @@ -0,0 +1,10 @@ +package org.sopt.and.presentation.signin.contract + +import org.sopt.and.core.viewmodel.UiSideEffect + +sealed interface SignInSideEffect: UiSideEffect { + data class ShowToast(val message: String) : SignInSideEffect + data class ShowSnackBar(val message: String) : SignInSideEffect + data class NavigateToHome(val token: String) : SignInSideEffect + data object NavigateToSignUp : SignInSideEffect +} diff --git a/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInUiState.kt b/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInUiState.kt new file mode 100644 index 0000000..13f273a --- /dev/null +++ b/app/src/main/java/org/sopt/and/presentation/signin/contract/SignInUiState.kt @@ -0,0 +1,9 @@ +package org.sopt.and.presentation.signin.contract + +import org.sopt.and.core.viewmodel.UiState + + +data class SignInUiState( + val id: String = "", + val password: String = "" +): UiState \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/signin/state/SignInUiState.kt b/app/src/main/java/org/sopt/and/presentation/signin/state/SignInUiState.kt deleted file mode 100644 index 9dbd1d7..0000000 --- a/app/src/main/java/org/sopt/and/presentation/signin/state/SignInUiState.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.sopt.and.presentation.signin.state - -data class SignInUiState( - val id: String = "", - val password: String = "" -) \ No newline at end of file