Skip to content

Commit a972d3f

Browse files
authored
Merge pull request #159 from YAPP-Github/refactor/#138-apply-orbit-dh
[Refactor/#138] 추상 mviviewmodel 클래스를 걷어내고 orbit-mvi 기반의 스타일로 변경합니다.
2 parents ace38ff + 3efaf09 commit a972d3f

30 files changed

Lines changed: 451 additions & 681 deletions

presentation/src/main/java/com/threegap/bitnagil/presentation/guide/GuideScreen.kt

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.threegap.bitnagil.presentation.guide
22

3-
import androidx.compose.foundation.background
43
import androidx.compose.foundation.layout.Column
54
import androidx.compose.foundation.layout.Spacer
65
import androidx.compose.foundation.layout.fillMaxSize
@@ -14,24 +13,22 @@ import androidx.compose.ui.Modifier
1413
import androidx.compose.ui.tooling.preview.Preview
1514
import androidx.compose.ui.unit.dp
1615
import androidx.hilt.navigation.compose.hiltViewModel
17-
import androidx.lifecycle.compose.collectAsStateWithLifecycle
18-
import com.threegap.bitnagil.designsystem.BitnagilTheme
1916
import com.threegap.bitnagil.designsystem.component.block.BitnagilTopBar
20-
import com.threegap.bitnagil.presentation.common.flow.collectAsEffect
2117
import com.threegap.bitnagil.presentation.guide.component.atom.GuideButton
2218
import com.threegap.bitnagil.presentation.guide.component.template.GuideBottomSheet
23-
import com.threegap.bitnagil.presentation.guide.model.GuideIntent
2419
import com.threegap.bitnagil.presentation.guide.model.GuideSideEffect
2520
import com.threegap.bitnagil.presentation.guide.model.GuideType
21+
import org.orbitmvi.orbit.compose.collectAsState
22+
import org.orbitmvi.orbit.compose.collectSideEffect
2623

2724
@Composable
2825
fun GuideScreenContainer(
2926
navigateToBack: () -> Unit,
3027
viewModel: GuideViewModel = hiltViewModel(),
3128
) {
32-
val uiState by viewModel.container.stateFlow.collectAsStateWithLifecycle()
29+
val uiState by viewModel.collectAsState()
3330

34-
viewModel.sideEffectFlow.collectAsEffect { sideEffect ->
31+
viewModel.collectSideEffect { sideEffect ->
3532
when (sideEffect) {
3633
is GuideSideEffect.NavigateToBack -> navigateToBack()
3734
}
@@ -41,27 +38,25 @@ fun GuideScreenContainer(
4138
uiState.guideType?.let { guideType ->
4239
GuideBottomSheet(
4340
guideType = guideType,
44-
onDismissRequest = { viewModel.sendIntent(GuideIntent.OnHideGuideBottomSheet) },
41+
onDismissRequest = viewModel::onHideGuideBottomSheet,
4542
)
4643
}
4744
}
4845

4946
GuideScreen(
50-
onClickGuideButton = { viewModel.sendIntent(GuideIntent.OnClickGuideButton(it)) },
51-
onBackClick = { viewModel.sendIntent(GuideIntent.OnBackClick) },
47+
onClickGuideButton = viewModel::onShowGuideBottomSheet,
48+
onBackClick = viewModel::navigateToBack,
5249
)
5350
}
5451

5552
@Composable
5653
private fun GuideScreen(
5754
onClickGuideButton: (GuideType) -> Unit,
5855
onBackClick: () -> Unit,
59-
modifier: Modifier = Modifier,
6056
) {
6157
Column(
62-
modifier = modifier
58+
modifier = Modifier
6359
.fillMaxSize()
64-
.background(BitnagilTheme.colors.white)
6560
.statusBarsPadding(),
6661
) {
6762
BitnagilTopBar(
@@ -85,7 +80,7 @@ private fun GuideScreen(
8580
}
8681
}
8782

88-
@Preview
83+
@Preview(showBackground = true)
8984
@Composable
9085
private fun GuideScreenPreview() {
9186
GuideScreen(
Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,39 @@
11
package com.threegap.bitnagil.presentation.guide
22

3-
import androidx.lifecycle.SavedStateHandle
4-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviViewModel
5-
import com.threegap.bitnagil.presentation.guide.model.GuideIntent
3+
import androidx.lifecycle.ViewModel
64
import com.threegap.bitnagil.presentation.guide.model.GuideSideEffect
75
import com.threegap.bitnagil.presentation.guide.model.GuideState
6+
import com.threegap.bitnagil.presentation.guide.model.GuideType
87
import dagger.hilt.android.lifecycle.HiltViewModel
9-
import org.orbitmvi.orbit.syntax.Syntax
8+
import org.orbitmvi.orbit.Container
9+
import org.orbitmvi.orbit.ContainerHost
10+
import org.orbitmvi.orbit.viewmodel.container
1011
import javax.inject.Inject
1112

1213
@HiltViewModel
13-
class GuideViewModel @Inject constructor(
14-
savedStateHandle: SavedStateHandle,
15-
) : MviViewModel<GuideState, GuideSideEffect, GuideIntent>(
16-
initState = GuideState(),
17-
savedStateHandle = savedStateHandle,
18-
) {
19-
override suspend fun Syntax<GuideState, GuideSideEffect>.reduceState(
20-
intent: GuideIntent,
21-
state: GuideState,
22-
): GuideState? {
23-
val newState = when (intent) {
24-
is GuideIntent.OnClickGuideButton -> {
25-
state.copy(
26-
guideType = intent.guideType,
27-
guideBottomSheetVisible = true,
28-
)
29-
}
14+
class GuideViewModel @Inject constructor() : ContainerHost<GuideState, GuideSideEffect>, ViewModel() {
15+
16+
override val container: Container<GuideState, GuideSideEffect> = container(initialState = GuideState.INIT)
3017

31-
is GuideIntent.OnHideGuideBottomSheet -> {
32-
state.copy(
33-
guideType = null,
34-
guideBottomSheetVisible = false,
35-
)
18+
fun onShowGuideBottomSheet(guideType: GuideType) {
19+
intent {
20+
reduce {
21+
state.copy(guideType = guideType, guideBottomSheetVisible = true)
3622
}
23+
}
24+
}
3725

38-
is GuideIntent.OnBackClick -> {
39-
sendSideEffect(GuideSideEffect.NavigateToBack)
40-
null
26+
fun onHideGuideBottomSheet() {
27+
intent {
28+
reduce {
29+
state.copy(guideType = null, guideBottomSheetVisible = false)
4130
}
4231
}
32+
}
4333

44-
return newState
34+
fun navigateToBack() {
35+
intent {
36+
postSideEffect(GuideSideEffect.NavigateToBack)
37+
}
4538
}
4639
}

presentation/src/main/java/com/threegap/bitnagil/presentation/guide/model/GuideIntent.kt

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.threegap.bitnagil.presentation.guide.model
22

3-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviSideEffect
4-
5-
sealed interface GuideSideEffect : MviSideEffect {
3+
sealed interface GuideSideEffect {
64
data object NavigateToBack : GuideSideEffect
75
}
Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.threegap.bitnagil.presentation.guide.model
22

3-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviState
4-
import kotlinx.parcelize.Parcelize
5-
6-
@Parcelize
73
data class GuideState(
8-
val guideType: GuideType? = null,
9-
val guideBottomSheetVisible: Boolean = false,
10-
) : MviState
4+
val guideType: GuideType?,
5+
val guideBottomSheetVisible: Boolean,
6+
) {
7+
companion object {
8+
val INIT = GuideState(
9+
guideType = null,
10+
guideBottomSheetVisible = false,
11+
)
12+
}
13+
}

presentation/src/main/java/com/threegap/bitnagil/presentation/login/LoginScreen.kt

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,16 @@ import org.orbitmvi.orbit.compose.collectSideEffect
3737

3838
@Composable
3939
fun LoginScreenContainer(
40+
viewModel: LoginViewModel = hiltViewModel(),
4041
navigateToHome: () -> Unit,
4142
navigateToTermsAgreement: () -> Unit,
42-
viewModel: LoginViewModel = hiltViewModel(),
4343
) {
4444
val context = LocalContext.current
4545

4646
viewModel.collectSideEffect { sideEffect ->
4747
when (sideEffect) {
48-
is LoginSideEffect.NavigateToHome -> {
49-
navigateToHome()
50-
}
51-
52-
is LoginSideEffect.NavigateToTermsAgreement -> {
53-
navigateToTermsAgreement()
54-
}
48+
is LoginSideEffect.NavigateToHome -> navigateToHome()
49+
is LoginSideEffect.NavigateToTermsAgreement -> navigateToTermsAgreement()
5550
}
5651
}
5752

@@ -82,7 +77,6 @@ private fun LoginScreen(
8277
horizontalAlignment = Alignment.CenterHorizontally,
8378
modifier = modifier
8479
.fillMaxSize()
85-
.background(BitnagilTheme.colors.white)
8680
.statusBarsPadding(),
8781
) {
8882
Spacer(modifier = Modifier.height(screenHeight * 0.114f))
@@ -136,7 +130,7 @@ private fun LoginScreen(
136130
}
137131
}
138132

139-
@Preview
133+
@Preview(showBackground = true)
140134
@Composable
141135
private fun LoginScreenPreview() {
142136
BitnagilTheme {
Lines changed: 31 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,59 @@
11
package com.threegap.bitnagil.presentation.login
22

33
import android.util.Log
4-
import androidx.lifecycle.SavedStateHandle
5-
import androidx.lifecycle.viewModelScope
4+
import androidx.lifecycle.ViewModel
65
import com.kakao.sdk.auth.model.OAuthToken
76
import com.threegap.bitnagil.domain.auth.usecase.LoginUseCase
8-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviViewModel
9-
import com.threegap.bitnagil.presentation.login.model.LoginIntent
107
import com.threegap.bitnagil.presentation.login.model.LoginSideEffect
118
import com.threegap.bitnagil.presentation.login.model.LoginState
129
import dagger.hilt.android.lifecycle.HiltViewModel
13-
import kotlinx.coroutines.launch
14-
import org.orbitmvi.orbit.syntax.Syntax
10+
import org.orbitmvi.orbit.Container
11+
import org.orbitmvi.orbit.ContainerHost
12+
import org.orbitmvi.orbit.viewmodel.container
1513
import javax.inject.Inject
1614

1715
@HiltViewModel
1816
class LoginViewModel @Inject constructor(
19-
savedStateHandle: SavedStateHandle,
2017
private val loginUseCase: LoginUseCase,
21-
) : MviViewModel<LoginState, LoginSideEffect, LoginIntent>(
22-
initState = LoginState(),
23-
savedStateHandle = savedStateHandle,
24-
) {
25-
override suspend fun Syntax<LoginState, LoginSideEffect>.reduceState(
26-
intent: LoginIntent,
27-
state: LoginState,
28-
): LoginState? =
29-
when (intent) {
30-
is LoginIntent.SetLoading -> {
31-
state.copy(isLoading = intent.isLoading)
32-
}
18+
) : ContainerHost<LoginState, LoginSideEffect>, ViewModel() {
3319

34-
is LoginIntent.LoginSuccess -> {
35-
sendSideEffect(
36-
if (intent.isGuest) {
37-
LoginSideEffect.NavigateToTermsAgreement
38-
} else {
39-
LoginSideEffect.NavigateToHome
40-
},
41-
)
42-
state.copy(
43-
isGuest = intent.isGuest,
44-
isLoading = false,
45-
)
46-
}
47-
48-
is LoginIntent.KakaoTalkLoginCancel -> {
49-
state.copy(isLoading = false)
50-
}
51-
52-
is LoginIntent.LoginFailure -> {
53-
state.copy(isLoading = false)
54-
}
55-
}
20+
override val container: Container<LoginState, LoginSideEffect> = container(initialState = LoginState.INIT)
5621

5722
fun kakaoLogin(token: OAuthToken?, error: Throwable?) {
58-
viewModelScope.launch {
59-
sendIntent(LoginIntent.SetLoading(true))
23+
intent {
24+
reduce { state.copy(isLoading = true) }
6025
when {
61-
token != null -> {
62-
processKakaoLoginSuccess(token)
63-
}
26+
token != null -> processKakaoLoginSuccess(token)
6427

6528
error != null -> {
29+
reduce { state.copy(isLoading = false) }
6630
Log.e("KakaoLogin", "카카오 로그인 실패", error)
67-
sendIntent(LoginIntent.LoginFailure)
6831
}
6932
}
7033
}
7134
}
7235

7336
private suspend fun processKakaoLoginSuccess(token: OAuthToken) {
74-
loginUseCase(
75-
socialAccessToken = token.accessToken,
76-
socialType = "KAKAO",
77-
).fold(
78-
onSuccess = {
79-
val isGuest = it.role.isGuest()
80-
sendIntent(LoginIntent.LoginSuccess(isGuest = isGuest))
81-
},
82-
onFailure = { e ->
83-
sendIntent(LoginIntent.LoginFailure)
84-
Log.e("Login", "${e.message}")
85-
},
86-
)
37+
subIntent {
38+
loginUseCase(socialAccessToken = token.accessToken, socialType = KAKAO).fold(
39+
onSuccess = {
40+
val isGuest = it.role.isGuest()
41+
if (isGuest) {
42+
postSideEffect(LoginSideEffect.NavigateToTermsAgreement)
43+
} else {
44+
postSideEffect(LoginSideEffect.NavigateToHome)
45+
}
46+
reduce { state.copy(isLoading = false) }
47+
},
48+
onFailure = { e ->
49+
reduce { state.copy(isLoading = false) }
50+
Log.e("Login", "${e.message}")
51+
},
52+
)
53+
}
54+
}
55+
56+
companion object {
57+
private const val KAKAO = "KAKAO"
8758
}
8859
}

presentation/src/main/java/com/threegap/bitnagil/presentation/login/model/LoginIntent.kt

Lines changed: 0 additions & 10 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.login.model
22

3-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviSideEffect
4-
5-
sealed interface LoginSideEffect : MviSideEffect {
3+
sealed interface LoginSideEffect {
64
data object NavigateToHome : LoginSideEffect
75
data object NavigateToTermsAgreement : LoginSideEffect
86
}
Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.threegap.bitnagil.presentation.login.model
22

3-
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviState
4-
import kotlinx.parcelize.Parcelize
5-
6-
@Parcelize
73
data class LoginState(
8-
val isLoading: Boolean = false,
9-
val isGuest: Boolean = false,
10-
) : MviState
4+
val isLoading: Boolean,
5+
val isGuest: Boolean,
6+
) {
7+
companion object {
8+
val INIT = LoginState(
9+
isLoading = false,
10+
isGuest = false,
11+
)
12+
}
13+
}

0 commit comments

Comments
 (0)