Skip to content

Commit 17406d0

Browse files
authored
Merge pull request #163 from YAPP-Github/refactor/#138-apply_orbit
[Refactor/#138] MviViewModel 사용 부분을 Orbit으로 교체
2 parents bb7a181 + ef9a971 commit 17406d0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1064
-1747
lines changed

presentation/src/main/java/com/threegap/bitnagil/presentation/common/mviviewmodel/MviIntent.kt

Lines changed: 0 additions & 3 deletions
This file was deleted.

presentation/src/main/java/com/threegap/bitnagil/presentation/common/mviviewmodel/MviSideEffect.kt

Lines changed: 0 additions & 3 deletions
This file was deleted.

presentation/src/main/java/com/threegap/bitnagil/presentation/common/mviviewmodel/MviState.kt

Lines changed: 0 additions & 5 deletions
This file was deleted.

presentation/src/main/java/com/threegap/bitnagil/presentation/common/mviviewmodel/MviViewModel.kt

Lines changed: 0 additions & 31 deletions
This file was deleted.

presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,33 @@ import androidx.activity.compose.BackHandler
44
import androidx.compose.foundation.layout.BoxWithConstraints
55
import androidx.compose.foundation.layout.fillMaxWidth
66
import androidx.compose.runtime.Composable
7-
import androidx.compose.runtime.collectAsState
87
import androidx.compose.runtime.getValue
98
import androidx.compose.runtime.remember
109
import androidx.compose.ui.Modifier
1110
import androidx.compose.ui.unit.dp
1211
import androidx.hilt.navigation.compose.hiltViewModel
1312
import com.threegap.bitnagil.presentation.common.dimension.pxToDp
14-
import com.threegap.bitnagil.presentation.common.flow.collectAsEffect
1513
import com.threegap.bitnagil.presentation.common.toast.GlobalBitnagilToast
1614
import com.threegap.bitnagil.presentation.emotion.component.template.EmotionRecommendRoutineScreen
1715
import com.threegap.bitnagil.presentation.emotion.component.template.SimpleEmotionSelectionScreen
1816
import com.threegap.bitnagil.presentation.emotion.component.template.SwipeEmotionSelectionScreen
1917
import com.threegap.bitnagil.presentation.emotion.model.EmotionScreenStep
2018
import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionSideEffect
19+
import org.orbitmvi.orbit.compose.collectAsState
20+
import org.orbitmvi.orbit.compose.collectSideEffect
2121

2222
@Composable
2323
fun EmotionScreenContainer(
2424
viewModel: EmotionViewModel = hiltViewModel(),
2525
navigateToBack: () -> Unit,
2626
) {
27-
val state by viewModel.stateFlow.collectAsState()
27+
val state by viewModel.collectAsState()
2828

2929
BackHandler {
3030
viewModel.moveToPrev()
3131
}
3232

33-
viewModel.sideEffectFlow.collectAsEffect { sideEffect ->
33+
viewModel.collectSideEffect { sideEffect ->
3434
when (sideEffect) {
3535
EmotionSideEffect.NavigateToBack -> navigateToBack()
3636
is EmotionSideEffect.ShowToast -> GlobalBitnagilToast.showWarning(sideEffect.message)
Lines changed: 82 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,135 @@
11
package com.threegap.bitnagil.presentation.emotion
22

33
import androidx.lifecycle.SavedStateHandle
4+
import androidx.lifecycle.ViewModel
45
import androidx.lifecycle.viewModelScope
56
import com.threegap.bitnagil.domain.emotion.usecase.GetEmotionsUseCase
67
import com.threegap.bitnagil.domain.emotion.usecase.RegisterEmotionUseCase
78
import com.threegap.bitnagil.domain.onboarding.usecase.RegisterRecommendOnBoardingRoutinesUseCase
8-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviViewModel
99
import com.threegap.bitnagil.presentation.emotion.model.EmotionRecommendRoutineUiModel
1010
import com.threegap.bitnagil.presentation.emotion.model.EmotionScreenStep
1111
import com.threegap.bitnagil.presentation.emotion.model.EmotionUiModel
12-
import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionIntent
1312
import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionSideEffect
1413
import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionState
1514
import dagger.hilt.android.lifecycle.HiltViewModel
1615
import kotlinx.coroutines.delay
1716
import kotlinx.coroutines.launch
18-
import org.orbitmvi.orbit.syntax.Syntax
17+
import org.orbitmvi.orbit.Container
18+
import org.orbitmvi.orbit.ContainerHost
19+
import org.orbitmvi.orbit.viewmodel.container
1920
import javax.inject.Inject
2021

2122
@HiltViewModel
2223
class EmotionViewModel @Inject constructor(
23-
savedStateHandle: SavedStateHandle,
2424
private val getEmotionsUseCase: GetEmotionsUseCase,
2525
private val registerEmotionUseCase: RegisterEmotionUseCase,
2626
private val registerRecommendOnBoardingRoutinesUseCase: RegisterRecommendOnBoardingRoutinesUseCase,
27-
) : MviViewModel<EmotionState, EmotionSideEffect, EmotionIntent>(
28-
savedStateHandle = savedStateHandle,
29-
initState = EmotionState.Init,
30-
) {
27+
savedStateHandle: SavedStateHandle,
28+
) : ContainerHost<EmotionState, EmotionSideEffect>, ViewModel() {
29+
30+
override val container: Container<EmotionState, EmotionSideEffect> = container(initialState = EmotionState.Init, savedStateHandle = savedStateHandle)
31+
3132
init {
3233
loadEmotions()
3334
}
3435

35-
private fun loadEmotions() {
36-
viewModelScope.launch {
36+
private fun loadEmotions() =
37+
intent {
3738
getEmotionsUseCase().fold(
3839
onSuccess = { emotions ->
39-
sendIntent(
40-
EmotionIntent.EmotionListLoadSuccess(emotionTypeUiModels = emotions.map { EmotionUiModel.fromDomain(it) }),
41-
)
40+
reduce {
41+
state.copy(
42+
emotionTypeUiModels = emotions.map { EmotionUiModel.fromDomain(it) },
43+
isLoading = false,
44+
)
45+
}
4246
},
4347
onFailure = {
4448
// todo 실패 케이스 정의되면 처리
4549
},
4650
)
4751
}
48-
}
4952

50-
override suspend fun Syntax<EmotionState, EmotionSideEffect>.reduceState(intent: EmotionIntent, state: EmotionState): EmotionState? {
51-
when (intent) {
52-
is EmotionIntent.EmotionListLoadSuccess -> {
53-
return state.copy(
54-
emotionTypeUiModels = intent.emotionTypeUiModels,
55-
isLoading = false,
56-
)
57-
}
58-
is EmotionIntent.RegisterEmotionSuccess -> {
59-
return state.copy(
60-
recommendRoutines = intent.recommendRoutines,
61-
step = EmotionScreenStep.RecommendRoutines,
62-
isLoading = false,
63-
showLoadingView = false,
64-
)
65-
}
66-
EmotionIntent.RegisterEmotionLoading -> {
67-
return state.copy(
53+
fun selectEmotion(emotionType: String, minimumDelay: Long = 0) =
54+
intent {
55+
val isLoading = state.isLoading
56+
if (isLoading) return@intent
57+
58+
reduce {
59+
state.copy(
6860
isLoading = true,
6961
showLoadingView = true,
7062
)
7163
}
72-
EmotionIntent.RegisterRecommendRoutinesLoading -> {
73-
return state.copy(
74-
isLoading = true,
75-
)
76-
}
77-
EmotionIntent.RegisterRecommendRoutinesFailure -> {
78-
return state.copy(
79-
isLoading = false,
80-
)
81-
}
82-
EmotionIntent.RegisterRecommendRoutinesSuccess -> {
83-
sendSideEffect(EmotionSideEffect.NavigateToBack)
84-
return null
85-
}
86-
EmotionIntent.BackToSelectEmotionStep -> {
87-
return state.copy(
88-
recommendRoutines = listOf(),
89-
step = EmotionScreenStep.Emotion,
90-
isLoading = false,
91-
)
92-
}
9364

94-
is EmotionIntent.SelectRecommendRoutine -> {
95-
val selectChangedRecommendRoutines = state.recommendRoutines.map {
96-
if (it.id == intent.recommendRoutineId) {
97-
it.copy(selected = !it.selected)
98-
} else {
99-
it
100-
}
65+
viewModelScope.launch {
66+
if (minimumDelay > 0) {
67+
delay(minimumDelay)
10168
}
102-
return state.copy(recommendRoutines = selectChangedRecommendRoutines)
103-
}
104-
105-
EmotionIntent.NavigateToBack -> {
106-
sendSideEffect(EmotionSideEffect.NavigateToBack)
107-
return null
108-
}
10969

110-
is EmotionIntent.RegisterEmotionFailure -> {
111-
sendSideEffect(EmotionSideEffect.ShowToast(intent.message))
112-
sendSideEffect(EmotionSideEffect.NavigateToBack)
113-
return null
70+
registerEmotionUseCase(emotionType = emotionType).fold(
71+
onSuccess = { emotionRecommendRoutines ->
72+
val recommendRoutines = emotionRecommendRoutines.map { EmotionRecommendRoutineUiModel.fromEmotionRecommendRoutine(it) }
73+
reduce {
74+
state.copy(
75+
recommendRoutines = recommendRoutines,
76+
step = EmotionScreenStep.RecommendRoutines,
77+
isLoading = false,
78+
showLoadingView = false,
79+
)
80+
}
81+
},
82+
onFailure = {
83+
postSideEffect(EmotionSideEffect.ShowToast(message = it.message ?: "에러가 발생했습니다. 잠시 후 시도해주세요."))
84+
postSideEffect(EmotionSideEffect.NavigateToBack)
85+
},
86+
)
11487
}
11588
}
116-
}
11789

118-
fun selectEmotion(emotionType: String, minimumDelay: Long = 0) {
119-
val isLoading = stateFlow.value.isLoading
120-
if (isLoading) return
121-
122-
viewModelScope.launch {
123-
sendIntent(EmotionIntent.RegisterEmotionLoading)
124-
125-
if (minimumDelay > 0) {
126-
delay(minimumDelay)
90+
fun selectRecommendRoutine(recommendRoutineId: String) =
91+
intent {
92+
val selectChangedRecommendRoutines = state.recommendRoutines.map {
93+
if (it.id == recommendRoutineId) {
94+
it.copy(selected = !it.selected)
95+
} else {
96+
it
97+
}
12798
}
128-
129-
registerEmotionUseCase(emotionType = emotionType).fold(
130-
onSuccess = { emotionRecommendRoutines ->
131-
val recommendRoutines = emotionRecommendRoutines.map { EmotionRecommendRoutineUiModel.fromEmotionRecommendRoutine(it) }
132-
sendIntent(EmotionIntent.RegisterEmotionSuccess(recommendRoutines))
133-
},
134-
onFailure = {
135-
sendIntent(
136-
EmotionIntent.RegisterEmotionFailure(message = it.message ?: "에러가 발생했습니다. 잠시 후 시도해주세요."),
137-
)
138-
},
139-
)
140-
}
141-
}
142-
143-
fun selectRecommendRoutine(recommendRoutineId: String) {
144-
viewModelScope.launch {
145-
sendIntent(EmotionIntent.SelectRecommendRoutine(recommendRoutineId))
99+
reduce { state.copy(recommendRoutines = selectChangedRecommendRoutines) }
146100
}
147-
}
148101

149-
fun moveToPrev() {
150-
viewModelScope.launch {
151-
val currentState = stateFlow.value
152-
153-
when (currentState.step) {
154-
EmotionScreenStep.Emotion -> sendIntent(EmotionIntent.NavigateToBack)
155-
EmotionScreenStep.RecommendRoutines -> sendIntent(EmotionIntent.BackToSelectEmotionStep)
102+
fun moveToPrev() =
103+
intent {
104+
when (state.step) {
105+
EmotionScreenStep.Emotion -> postSideEffect(EmotionSideEffect.NavigateToBack)
106+
EmotionScreenStep.RecommendRoutines -> reduce {
107+
state.copy(
108+
recommendRoutines = listOf(),
109+
step = EmotionScreenStep.Emotion,
110+
isLoading = false,
111+
)
112+
}
156113
}
157114
}
158-
}
159115

160-
fun registerRecommendRoutines() {
161-
val isLoading = stateFlow.value.isLoading
162-
if (isLoading) return
163-
164-
viewModelScope.launch {
165-
sendIntent(EmotionIntent.RegisterRecommendRoutinesLoading)
166-
167-
val currentState = stateFlow.value
168-
val selectedRecommendRoutineIds = currentState.recommendRoutines.filter { it.selected }.map { it.id }
169-
registerRecommendOnBoardingRoutinesUseCase(selectedRecommendRoutineIds).fold(
170-
onSuccess = {
171-
sendIntent(EmotionIntent.RegisterRecommendRoutinesSuccess)
172-
},
173-
onFailure = {
174-
sendIntent(EmotionIntent.RegisterRecommendRoutinesFailure)
175-
},
176-
)
116+
fun registerRecommendRoutines() =
117+
intent {
118+
val isLoading = state.isLoading
119+
if (isLoading) return@intent
120+
121+
viewModelScope.launch {
122+
reduce { state.copy(isLoading = true) }
123+
124+
val selectedRecommendRoutineIds = state.recommendRoutines.filter { it.selected }.map { it.id }
125+
registerRecommendOnBoardingRoutinesUseCase(selectedRecommendRoutineIds).fold(
126+
onSuccess = {
127+
postSideEffect(EmotionSideEffect.NavigateToBack)
128+
},
129+
onFailure = {
130+
reduce { state.copy(isLoading = false) }
131+
},
132+
)
133+
}
177134
}
178-
}
179135
}

presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.threegap.bitnagil.presentation.emotion.model.mvi
22

3-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviSideEffect
4-
5-
sealed class EmotionSideEffect : MviSideEffect {
3+
sealed class EmotionSideEffect {
64
data object NavigateToBack : EmotionSideEffect()
75
data class ShowToast(val message: String) : EmotionSideEffect()
86
}

presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.threegap.bitnagil.presentation.emotion.model.mvi
22

3+
import android.os.Parcelable
34
import androidx.compose.runtime.Immutable
4-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviState
55
import com.threegap.bitnagil.presentation.emotion.model.EmotionRecommendRoutineUiModel
66
import com.threegap.bitnagil.presentation.emotion.model.EmotionScreenStep
77
import com.threegap.bitnagil.presentation.emotion.model.EmotionUiModel
@@ -15,7 +15,7 @@ data class EmotionState(
1515
val recommendRoutines: List<EmotionRecommendRoutineUiModel>,
1616
val step: EmotionScreenStep,
1717
val showLoadingView: Boolean,
18-
) : MviState {
18+
) : Parcelable {
1919
companion object {
2020
val Init = EmotionState(
2121
emotionTypeUiModels = emptyList(),

0 commit comments

Comments
 (0)