From 05ffb5dfa36cdfe57d3affb5f031edd2ee2debb9 Mon Sep 17 00:00:00 2001 From: flash159483 Date: Tue, 16 Jul 2024 23:17:56 +0900 Subject: [PATCH] =?UTF-8?q?[FEAT]#30:=20=ED=95=99=EA=B5=90=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/danggeun/common/di/CoroutineModule.kt | 20 ++++++ .../com/bff/wespot/model/auth/School.kt | 8 +++ feature/auth/build.gradle.kts | 1 + .../com/bff/wespot/auth/AuthActivity.kt | 2 + .../bff/wespot/auth/screen/SchoolScreen.kt | 4 +- .../com/bff/wespot/auth/state/AuthAction.kt | 4 +- .../com/bff/wespot/auth/state/AuthUiState.kt | 7 +-- .../wespot/auth/viewmodel/AuthViewModel.kt | 62 ++++++++++++++++--- 8 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 core/common/src/main/kotlin/com/danggeun/common/di/CoroutineModule.kt create mode 100644 core/model/src/main/kotlin/com/bff/wespot/model/auth/School.kt diff --git a/core/common/src/main/kotlin/com/danggeun/common/di/CoroutineModule.kt b/core/common/src/main/kotlin/com/danggeun/common/di/CoroutineModule.kt new file mode 100644 index 00000000..f9c1a795 --- /dev/null +++ b/core/common/src/main/kotlin/com/danggeun/common/di/CoroutineModule.kt @@ -0,0 +1,20 @@ +package com.danggeun.common.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.Dispatchers +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object CoroutineModule { + @Provides + @Singleton + fun provideIoDispatcher() = Dispatchers.IO + + @Provides + @Singleton + fun provideMainDispatcher() = Dispatchers.Main +} \ No newline at end of file diff --git a/core/model/src/main/kotlin/com/bff/wespot/model/auth/School.kt b/core/model/src/main/kotlin/com/bff/wespot/model/auth/School.kt new file mode 100644 index 00000000..8b7decf9 --- /dev/null +++ b/core/model/src/main/kotlin/com/bff/wespot/model/auth/School.kt @@ -0,0 +1,8 @@ +package com.bff.wespot.model.auth + +data class School( + val id: Int, + val name: String, + val address: String, + val type: String, +) diff --git a/feature/auth/build.gradle.kts b/feature/auth/build.gradle.kts index c75025e8..ebaacb46 100644 --- a/feature/auth/build.gradle.kts +++ b/feature/auth/build.gradle.kts @@ -18,4 +18,5 @@ dependencies { implementation(libs.bundles.orbit) implementation(libs.junit) implementation(libs.androidx.junit) + implementation(libs.timber) } diff --git a/feature/auth/src/main/kotlin/com/bff/wespot/auth/AuthActivity.kt b/feature/auth/src/main/kotlin/com/bff/wespot/auth/AuthActivity.kt index 960b0f8e..86a7ce81 100644 --- a/feature/auth/src/main/kotlin/com/bff/wespot/auth/AuthActivity.kt +++ b/feature/auth/src/main/kotlin/com/bff/wespot/auth/AuthActivity.kt @@ -23,8 +23,10 @@ import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.navigation.dependency import com.ramcosta.composedestinations.navigation.navigate import com.ramcosta.composedestinations.rememberNavHostEngine +import dagger.hilt.android.AndroidEntryPoint import org.orbitmvi.orbit.compose.collectSideEffect +@AndroidEntryPoint class AuthActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/feature/auth/src/main/kotlin/com/bff/wespot/auth/screen/SchoolScreen.kt b/feature/auth/src/main/kotlin/com/bff/wespot/auth/screen/SchoolScreen.kt index dc741115..b7df9f4f 100644 --- a/feature/auth/src/main/kotlin/com/bff/wespot/auth/screen/SchoolScreen.kt +++ b/feature/auth/src/main/kotlin/com/bff/wespot/auth/screen/SchoolScreen.kt @@ -102,7 +102,7 @@ fun SchoolScreen( ) } - if (state.schoolSearchList.isEmpty()) { + if (state.schoolList.isEmpty()) { Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { WSTextButton( text = stringResource(id = R.string.no_school_found), @@ -113,7 +113,7 @@ fun SchoolScreen( } LazyColumn { - items(state.schoolSearchList, key = { school -> + items(state.schoolList, key = { school -> school.id }) { school -> SchoolListItem( diff --git a/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthAction.kt b/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthAction.kt index 6ff5d05b..c494e642 100644 --- a/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthAction.kt +++ b/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthAction.kt @@ -1,11 +1,11 @@ package com.bff.wespot.auth.state -import com.bff.wespot.model.SchoolItem +import com.bff.wespot.model.auth.School sealed class AuthAction { data class OnSchoolSearchChanged(val text: String) : AuthAction() - data class OnSchoolSelected(val school: SchoolItem) : AuthAction() + data class OnSchoolSelected(val school: School) : AuthAction() data class OnGradeChanged(val grade: Int) : AuthAction() diff --git a/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthUiState.kt b/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthUiState.kt index 69d81023..855f8004 100644 --- a/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthUiState.kt +++ b/feature/auth/src/main/kotlin/com/bff/wespot/auth/state/AuthUiState.kt @@ -1,12 +1,11 @@ package com.bff.wespot.auth.state -import com.bff.wespot.model.SchoolItem +import com.bff.wespot.model.auth.School data class AuthUiState( val schoolName: String = "", - val schoolList: List = listOf(SchoolItem("1", "2", "3")), - val schoolSearchList: List = listOf(SchoolItem("1", "2", "3")), - val selectedSchool: SchoolItem? = null, + val schoolList: List = emptyList(), + val selectedSchool: School? = null, val grade: Int = -1, val gradeBottomSheet: Boolean = true, val classNumber: Int = -1, diff --git a/feature/auth/src/main/kotlin/com/bff/wespot/auth/viewmodel/AuthViewModel.kt b/feature/auth/src/main/kotlin/com/bff/wespot/auth/viewmodel/AuthViewModel.kt index d1a9d7f1..b1f9132f 100644 --- a/feature/auth/src/main/kotlin/com/bff/wespot/auth/viewmodel/AuthViewModel.kt +++ b/feature/auth/src/main/kotlin/com/bff/wespot/auth/viewmodel/AuthViewModel.kt @@ -6,23 +6,37 @@ import com.bff.wespot.auth.state.AuthAction import com.bff.wespot.auth.state.AuthSideEffect import com.bff.wespot.auth.state.AuthUiState import com.bff.wespot.auth.state.NavigationAction +import com.bff.wespot.domain.repository.auth.AuthRepository import com.bff.wespot.domain.usecase.KakaoLoginUseCase -import com.bff.wespot.model.SchoolItem +import com.bff.wespot.model.auth.School import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import org.orbitmvi.orbit.ContainerHost import org.orbitmvi.orbit.syntax.simple.intent import org.orbitmvi.orbit.syntax.simple.postSideEffect import org.orbitmvi.orbit.syntax.simple.reduce import org.orbitmvi.orbit.viewmodel.container +import timber.log.Timber import javax.inject.Inject @HiltViewModel class AuthViewModel @Inject constructor( private val kakaoLoginUseCase: KakaoLoginUseCase, + private val authRepository: AuthRepository, + private val dispatcher: CoroutineDispatcher, ) : ViewModel(), ContainerHost { override val container = container(AuthUiState()) + private val userInput = MutableStateFlow("") + + init { + monitorUserInput() + } + fun onAction(action: AuthAction) { when (action) { is AuthAction.OnSchoolSearchChanged -> handleSchoolSearchChanged(action.text) @@ -45,19 +59,42 @@ class AuthViewModel @Inject constructor( private fun handleSchoolSearchChanged(text: String) = intent { reduce { + userInput.value = text state.copy( schoolName = text, - schoolSearchList = state.schoolList.filter { - it.name.contains( - text, - ignoreCase = true, - ) - }, ) } } - private fun handleSchoolSelected(school: SchoolItem) = intent { + private fun monitorUserInput() { + viewModelScope.launch { + userInput + .debounce(INPUT_DEBOUNCE_TIME) + .distinctUntilChanged() + .collect { + fetchSchoolList(it) + } + } + } + + private fun fetchSchoolList(search: String) = intent { + viewModelScope.launch(dispatcher) { + Timber.d("enter") + authRepository.getSchoolList(search) + .onSuccess { + reduce { + state.copy( + schoolList = it, + ) + } + } + .onFailure { + Timber.e(it) + } + } + } + + private fun handleSchoolSelected(school: School) = intent { reduce { state.copy( selectedSchool = school, @@ -111,21 +148,30 @@ class AuthViewModel @Inject constructor( is NavigationAction.NavigateToGradeScreen -> AuthSideEffect.NavigateToGradeScreen( navigate.edit, ) + is NavigationAction.NavigateToSchoolScreen -> AuthSideEffect.NavigateToSchoolScreen( navigate.edit, ) + is NavigationAction.NavigateToClassScreen -> AuthSideEffect.NavigateToClassScreen( navigate.edit, ) + is NavigationAction.NavigateToGenderScreen -> AuthSideEffect.NavigateToGenderScreen( navigate.edit, ) + is NavigationAction.NavigateToNameScreen -> AuthSideEffect.NavigateToNameScreen( navigate.edit, ) + NavigationAction.NavigateToEditScreen -> AuthSideEffect.NavigateToEditScreen NavigationAction.NavigateToCompleteScreen -> AuthSideEffect.NavigateToCompleteScreen } postSideEffect(sideEffect) } + + companion object { + private const val INPUT_DEBOUNCE_TIME = 500L + } }