From 6e8c5ee2763832c1725509da7528ae77953555a5 Mon Sep 17 00:00:00 2001 From: yunsehwan Date: Wed, 30 Jul 2025 17:41:02 +0900 Subject: [PATCH 1/6] =?UTF-8?q?FIX:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EC=97=AC=EB=B6=80=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?Nav=20=EC=9D=B8=EC=9E=90=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D/=EC=88=98=EC=A0=95=20=EC=97=AC=EB=B6=80?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=ED=83=80=EC=9D=B4=ED=8B=80,?= =?UTF-8?q?=20=EC=B6=94=EC=B2=9C=20=EB=A3=A8=ED=8B=B4=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=EA=B0=80=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EB=90=98=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/threegap/bitnagil/MainNavHost.kt | 20 ++++++++++-- .../main/java/com/threegap/bitnagil/Route.kt | 4 ++- .../component/atom/BitnagilSelectButton.kt | 18 +++++++---- .../onboarding/OnBoardingScreen.kt | 21 +++++++++--- .../onboarding/OnBoardingViewModel.kt | 16 ++++++++-- .../template/OnBoardingSelectTemplate.kt | 8 +++-- .../onboarding/model/OnBoardingSetType.kt | 32 +++++++++++++++++++ .../onboarding/model/mvi/OnBoardingState.kt | 2 ++ .../model/navarg/OnBoardingScreenArg.kt | 6 ++++ 9 files changed, 107 insertions(+), 20 deletions(-) create mode 100644 presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt create mode 100644 presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/navarg/OnBoardingScreenArg.kt diff --git a/app/src/main/java/com/threegap/bitnagil/MainNavHost.kt b/app/src/main/java/com/threegap/bitnagil/MainNavHost.kt index 6e1fdc00..64162060 100644 --- a/app/src/main/java/com/threegap/bitnagil/MainNavHost.kt +++ b/app/src/main/java/com/threegap/bitnagil/MainNavHost.kt @@ -11,6 +11,8 @@ import com.threegap.bitnagil.presentation.emotion.EmotionScreenContainer import com.threegap.bitnagil.presentation.intro.IntroScreenContainer import com.threegap.bitnagil.presentation.login.LoginScreenContainer import com.threegap.bitnagil.presentation.onboarding.OnBoardingScreenContainer +import com.threegap.bitnagil.presentation.onboarding.OnBoardingViewModel +import com.threegap.bitnagil.presentation.onboarding.model.navarg.OnBoardingScreenArg import com.threegap.bitnagil.presentation.setting.SettingScreenContainer import com.threegap.bitnagil.presentation.splash.SplashScreenContainer import com.threegap.bitnagil.presentation.terms.TermsAgreementScreenContainer @@ -80,7 +82,7 @@ fun MainNavHost( ) }, navigateToOnBoarding = { - navigator.navController.navigate(Route.OnBoarding) + navigator.navController.navigate(Route.OnBoarding()) }, navigateToBack = { navigator.navController.popBackStack() }, ) @@ -92,7 +94,7 @@ fun MainNavHost( navigator.navController.navigate(Route.Setting) }, navigateToOnBoarding = { - navigator.navController.navigate(Route.OnBoarding) + navigator.navController.navigate(Route.OnBoarding(isNew = false)) }, navigateToNotice = { }, @@ -150,8 +152,20 @@ fun MainNavHost( ) } - composable { + composable { navBackStackEntry -> + val arg = navBackStackEntry.toRoute() + val onBoardingScreenArg = if (arg.isNew) { + OnBoardingScreenArg.NEW + } else { + OnBoardingScreenArg.RESET + } + + val viewModel = hiltViewModel { factory -> + factory.create(onBoardingScreenArg) + } + OnBoardingScreenContainer( + onBoardingViewModel = viewModel, navigateToHome = { navigator.navController.navigate(Route.Home) { popUpTo(navigator.navController.graph.startDestinationId) { diff --git a/app/src/main/java/com/threegap/bitnagil/Route.kt b/app/src/main/java/com/threegap/bitnagil/Route.kt index c94979a3..dc540dd8 100644 --- a/app/src/main/java/com/threegap/bitnagil/Route.kt +++ b/app/src/main/java/com/threegap/bitnagil/Route.kt @@ -29,7 +29,9 @@ sealed interface Route { data object Setting : Route @Serializable - data object OnBoarding : Route + data class OnBoarding( + val isNew: Boolean = true, + ) : Route @Serializable data class WriteRoutine( diff --git a/core/designsystem/src/main/java/com/threegap/bitnagil/designsystem/component/atom/BitnagilSelectButton.kt b/core/designsystem/src/main/java/com/threegap/bitnagil/designsystem/component/atom/BitnagilSelectButton.kt index 85167f5a..dabf3fad 100644 --- a/core/designsystem/src/main/java/com/threegap/bitnagil/designsystem/component/atom/BitnagilSelectButton.kt +++ b/core/designsystem/src/main/java/com/threegap/bitnagil/designsystem/component/atom/BitnagilSelectButton.kt @@ -30,7 +30,7 @@ import com.threegap.bitnagil.designsystem.BitnagilTheme @Composable fun BitnagilSelectButton( title: String, - onClick: () -> Unit, + onClick: (() -> Unit)?, modifier: Modifier = Modifier, description: String? = null, selected: Boolean = false, @@ -57,11 +57,17 @@ fun BitnagilSelectButton( .fillMaxWidth() .clip(shape) .background(backgroundColor) - .clickable( - interactionSource = interactionSource, - indication = null, - onClick = onClick, - ) + .let { + if (onClick != null) { + it.clickable( + interactionSource = interactionSource, + indication = null, + onClick = onClick, + ) + } else { + it + } + } .padding(horizontal = 20.dp, vertical = 16.dp) .semantics { role = Role.Button diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt index 69c623ef..f5c8e753 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt @@ -14,7 +14,9 @@ import com.threegap.bitnagil.designsystem.component.block.BitnagilProgressTopBar import com.threegap.bitnagil.presentation.common.flow.collectAsEffect import com.threegap.bitnagil.presentation.onboarding.component.template.OnBoardingAbstractTemplate import com.threegap.bitnagil.presentation.onboarding.component.template.OnBoardingSelectTemplate +import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingItem import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingPageInfo +import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingSetType import com.threegap.bitnagil.presentation.onboarding.model.mvi.OnBoardingSideEffect import com.threegap.bitnagil.presentation.onboarding.model.mvi.OnBoardingState @@ -87,12 +89,20 @@ private fun OnBoardingScreen( OnBoardingSelectTemplate( modifier = Modifier.weight(1f), title = "당신만의 추천 루틴이\n생성되었어요!", - subText = "당신의 생활 패턴과 목표에 맞춰 구성된 맞춤 루틴이에요.\n지금부터 가볍게 시작해보세요.", + subText = state.onBoardingSetType.subText, items = currentOnBoardingPageInfo.routines, nextButtonEnable = state.nextButtonEnable, onClickNextButton = onClickRegister, - onClickItem = onClickRoutine, - onClickSkip = onClickSkip, + onClickItem = if (state.onBoardingSetType.canSelectRoutine) { + onClickRoutine + } else { + null + }, + onClickSkip = if (state.onBoardingSetType.canSkip) { + onClickSkip + } else { + null + }, ) } is OnBoardingPageInfo.SelectOnBoarding -> { @@ -121,9 +131,12 @@ fun OnBoardingScreenPreview() { OnBoardingScreen( state = OnBoardingState.Idle( nextButtonEnable = false, - currentOnBoardingPageInfo = OnBoardingPageInfo.SelectOnBoarding(id = "id", title = "title", description = "description"), + currentOnBoardingPageInfo = OnBoardingPageInfo.RecommendRoutines(listOf( + OnBoardingItem("1", "루틴명", "세부 루틴 한 줄 설명", null), + )), totalStep = 5, currentStep = 1, + onBoardingSetType = OnBoardingSetType.RESET, ), onClickNext = {}, onClickPreviousInSelectOnBoarding = {}, diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt index 3b409dd6..2ef84fd3 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt @@ -10,9 +10,14 @@ import com.threegap.bitnagil.presentation.common.mviviewmodel.MviViewModel import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingAbstractTextItem import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingItem import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingPageInfo +import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingSetType import com.threegap.bitnagil.presentation.onboarding.model.mvi.OnBoardingIntent import com.threegap.bitnagil.presentation.onboarding.model.mvi.OnBoardingSideEffect import com.threegap.bitnagil.presentation.onboarding.model.mvi.OnBoardingState +import com.threegap.bitnagil.presentation.onboarding.model.navarg.OnBoardingScreenArg +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.async @@ -20,19 +25,23 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import org.orbitmvi.orbit.syntax.simple.SimpleSyntax -import javax.inject.Inject -@HiltViewModel -class OnBoardingViewModel @Inject constructor( +@HiltViewModel(assistedFactory = OnBoardingViewModel.Factory::class) +class OnBoardingViewModel @AssistedInject constructor( savedStateHandle: SavedStateHandle, private val getOnBoardingsUseCase: GetOnBoardingsUseCase, private val getRecommendOnBoardingRoutinesUseCase: GetRecommendOnBoardingRoutinesUseCase, private val getOnBoardingAbstractUseCase: GetOnBoardingAbstractUseCase, private val registerRecommendOnBoardingRoutinesUseCase: RegisterRecommendOnBoardingRoutinesUseCase, + @Assisted private val onBoardingArg: OnBoardingScreenArg, ) : MviViewModel( initState = OnBoardingState.Loading, savedStateHandle = savedStateHandle, ) { + @AssistedFactory interface Factory { + fun create(onBoardingArg: OnBoardingScreenArg): OnBoardingViewModel + } + // 내부에 전체 온보딩 항목 저장 private val onBoardingPageInfos = mutableListOf() @@ -68,6 +77,7 @@ class OnBoardingViewModel @Inject constructor( currentOnBoardingPageInfo = onBoardingPageInfos.first(), totalStep = onBoardingPageInfos.size + 2, currentStep = 1, + onBoardingSetType = OnBoardingSetType.fromOnBoardingScreenArg(onBoardingArg), ) } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/component/template/OnBoardingSelectTemplate.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/component/template/OnBoardingSelectTemplate.kt index 634dbf5c..9c84e45d 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/component/template/OnBoardingSelectTemplate.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/component/template/OnBoardingSelectTemplate.kt @@ -25,7 +25,7 @@ fun OnBoardingSelectTemplate( items: List, nextButtonEnable: Boolean = false, onClickNextButton: () -> Unit, - onClickItem: (String) -> Unit, + onClickItem: ((String) -> Unit)?, onClickSkip: (() -> Unit)? = null, ) { Column( @@ -59,8 +59,10 @@ fun OnBoardingSelectTemplate( BitnagilSelectButton( title = item.title, description = item.description, - onClick = { - onClickItem(item.id) + onClick = if (onClickItem != null) { + { onClickItem(item.id) } + } else { + null }, selected = item.selected, modifier = Modifier.padding(bottom = 12.dp), diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt new file mode 100644 index 00000000..6881669b --- /dev/null +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt @@ -0,0 +1,32 @@ +package com.threegap.bitnagil.presentation.onboarding.model + +import com.threegap.bitnagil.presentation.onboarding.model.navarg.OnBoardingScreenArg + +enum class OnBoardingSetType( + val subText: String, + val canSkip: Boolean, + val canSelectRoutine: Boolean, +) { + NEW( + subText = "당신의 생활 패턴과 목표에 맞춰 구성된 맞춤 루틴이에요.\n지금부터 가볍게 시작해보세요.", + canSkip = true, + canSelectRoutine = false, + ), + RESET( + subText = "생활 패턴과 목표에 맞춰 다시 구성된 맞춤 루틴이에요.\n원하는 루틴을 선택해서 가볍게 시작해보세요.", + canSkip = false, + canSelectRoutine = true, + ), + ; + + companion object { + fun fromOnBoardingScreenArg( + onBoardingScreenArg: OnBoardingScreenArg, + ): OnBoardingSetType { + return when (onBoardingScreenArg) { + OnBoardingScreenArg.NEW -> NEW + OnBoardingScreenArg.RESET -> RESET + } + } + } +} diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/mvi/OnBoardingState.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/mvi/OnBoardingState.kt index 5baecc4c..75910ffe 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/mvi/OnBoardingState.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/mvi/OnBoardingState.kt @@ -3,6 +3,7 @@ package com.threegap.bitnagil.presentation.onboarding.model.mvi import android.os.Parcelable import com.threegap.bitnagil.presentation.common.mviviewmodel.MviState import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingPageInfo +import com.threegap.bitnagil.presentation.onboarding.model.OnBoardingSetType import kotlinx.parcelize.Parcelize @Parcelize @@ -17,5 +18,6 @@ sealed class OnBoardingState(val progress: Float) : Parcelable, MviState { val currentOnBoardingPageInfo: OnBoardingPageInfo, val totalStep: Int, val currentStep: Int, + val onBoardingSetType: OnBoardingSetType, ) : OnBoardingState(progress = currentStep.toFloat() / totalStep.toFloat()) } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/navarg/OnBoardingScreenArg.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/navarg/OnBoardingScreenArg.kt new file mode 100644 index 00000000..6d485070 --- /dev/null +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/navarg/OnBoardingScreenArg.kt @@ -0,0 +1,6 @@ +package com.threegap.bitnagil.presentation.onboarding.model.navarg + +enum class OnBoardingScreenArg { + NEW, RESET, + ; +} From 38e82846510fa490a521f59b2192174420c84230 Mon Sep 17 00:00:00 2001 From: yunsehwan Date: Wed, 30 Jul 2025 19:19:39 +0900 Subject: [PATCH 2/6] =?UTF-8?q?FIX:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=8B=9C=20=EB=A3=A8=ED=8B=B4=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EB=B6=88=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95,=20=EC=98=A8=EB=B3=B4=EB=94=A9?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20API=EC=9D=98=20request=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/onboarding/model/dto/OnBoardingItemDto.kt | 14 +++++++------- .../presentation/onboarding/OnBoardingViewModel.kt | 2 +- .../onboarding/model/OnBoardingSetType.kt | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/data/src/main/java/com/threegap/bitnagil/data/onboarding/model/dto/OnBoardingItemDto.kt b/data/src/main/java/com/threegap/bitnagil/data/onboarding/model/dto/OnBoardingItemDto.kt index 6146011b..308b9e28 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/onboarding/model/dto/OnBoardingItemDto.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/onboarding/model/dto/OnBoardingItemDto.kt @@ -35,25 +35,25 @@ data class OnBoardingItemDto( ) val RealOutingZeroPerWeek = OnBoardingItemDto( - id = "ZERO_PER_WEEK", + id = "NEVER", title = "밖에 나가지 않고 집에서만 지냈어요", description = null, ) val RealOutingOneToTwoPerWeek = OnBoardingItemDto( - id = "ONE_TO_TWO_PER_WEEK", + id = "SHORT", title = "잠깐 외출했어요", description = null, ) val RealOutingThreeToFourPerWeek = OnBoardingItemDto( - id = "THREE_TO_FOUR_PER_WEEK", + id = "SOMETIMES", title = "가끔 나가요", description = null, ) val RealOutingMoreThanFivePerWeek = OnBoardingItemDto( - id = "MORE_THAN_FIVE_PER_WEEK", + id = "OFTEN", title = "자주 외출해요", description = null, ) @@ -83,19 +83,19 @@ data class OnBoardingItemDto( ) val TargetOutingOneToTwoPerWeek = OnBoardingItemDto( - id = "ONE_TO_TWO_PER_WEEK", + id = "ONE_PER_WEEK", title = "시작이 더 중요해요", description = "일주일에 1회", ) val TargetOutingThreeToFourPerWeek = OnBoardingItemDto( - id = "THREE_TO_FOUR_PER_WEEK", + id = "TWO_TO_THREE_PER_WEEK", title = "너무 무리하지 않아도 괜찮아요", description = "일주일에 2~3회", ) val TargetOutingMoreThenFivePerWeek = OnBoardingItemDto( - id = "MORE_THAN_FIVE_PER_WEEK", + id = "MORE_THAN_FOUR_PER_WEEK", title = "이 정도면 충분히 활력 있는 한 주가 될거에요", description = "일주일에 4회 이상", ) diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt index 2ef84fd3..07f96d4c 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingViewModel.kt @@ -147,7 +147,7 @@ class OnBoardingViewModel @AssistedInject constructor( return currentState.copy( currentOnBoardingPageInfo = recommendRoutinePageInfo, currentStep = currentState.currentStep + 1, - nextButtonEnable = false, + nextButtonEnable = !currentState.onBoardingSetType.canSelectRoutine, ) } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt index 6881669b..d76da889 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/model/OnBoardingSetType.kt @@ -10,12 +10,12 @@ enum class OnBoardingSetType( NEW( subText = "당신의 생활 패턴과 목표에 맞춰 구성된 맞춤 루틴이에요.\n지금부터 가볍게 시작해보세요.", canSkip = true, - canSelectRoutine = false, + canSelectRoutine = true, ), RESET( subText = "생활 패턴과 목표에 맞춰 다시 구성된 맞춤 루틴이에요.\n원하는 루틴을 선택해서 가볍게 시작해보세요.", canSkip = false, - canSelectRoutine = true, + canSelectRoutine = false, ), ; From 80ce18cbf884881d6e48226379268730d0c74c98 Mon Sep 17 00:00:00 2001 From: yunsehwan Date: Wed, 30 Jul 2025 20:20:08 +0900 Subject: [PATCH 3/6] =?UTF-8?q?FEAT:=20=EA=B0=90=EC=A0=95=20=EA=B5=AC?= =?UTF-8?q?=EC=8A=AC=20=EC=84=A0=ED=83=9D=20=ED=9B=84=20=EC=B6=94=EC=B2=9C?= =?UTF-8?q?=20=EB=A3=A8=ED=8B=B4=20=ED=91=9C=EC=8B=9C=20=EB=B0=8F=20?= =?UTF-8?q?=EC=B6=94=EC=B2=9C=20=EB=A3=A8=ED=8B=B4=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dto/EmotionRecommendedRoutineDto.kt | 11 +- .../repositoryImpl/EmotionRepositoryImpl.kt | 9 +- .../emotion/model/EmotionRecommendRoutine.kt | 7 + .../emotion/repository/EmotionRepository.kt | 3 +- .../emotion/usecase/RegisterEmotionUseCase.kt | 3 +- .../presentation/emotion/EmotionScreen.kt | 146 +++++++++++++++++- .../presentation/emotion/EmotionViewModel.kt | 92 ++++++++++- .../model/EmotionRecommendRoutineUiModel.kt | 26 ++++ .../emotion/model/EmotionScreenStep.kt | 6 + .../emotion/model/mvi/EmotionIntent.kt | 9 +- .../emotion/model/mvi/EmotionState.kt | 8 + 11 files changed, 303 insertions(+), 17 deletions(-) create mode 100644 domain/src/main/java/com/threegap/bitnagil/domain/emotion/model/EmotionRecommendRoutine.kt create mode 100644 presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt create mode 100644 presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionScreenStep.kt diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt index 497acdb3..953cf949 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt @@ -1,5 +1,6 @@ package com.threegap.bitnagil.data.emotion.model.dto +import com.threegap.bitnagil.domain.emotion.model.EmotionRecommendRoutine import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -13,4 +14,12 @@ data class EmotionRecommendedRoutineDto( val recommendedRoutineDescription: String, @SerialName("recommendedSubRoutineSearchResult") val recommendedSubRoutineSearchResult: List, -) +) { + fun toEmotionRecommendRoutine() : EmotionRecommendRoutine { + return EmotionRecommendRoutine( + routineId = recommendedRoutineId.toString(), + routineName = recommendedRoutineName, + routineDescription = recommendedRoutineDescription, + ) + } +} diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt index 55ceb838..fdf6dd9c 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt @@ -3,6 +3,7 @@ package com.threegap.bitnagil.data.emotion.repositoryImpl import com.threegap.bitnagil.data.emotion.datasource.EmotionDataSource import com.threegap.bitnagil.data.emotion.model.response.toDomain import com.threegap.bitnagil.domain.emotion.model.Emotion +import com.threegap.bitnagil.domain.emotion.model.EmotionRecommendRoutine import com.threegap.bitnagil.domain.emotion.model.MyEmotion import com.threegap.bitnagil.domain.emotion.repository.EmotionRepository import javax.inject.Inject @@ -26,7 +27,7 @@ class EmotionRepositoryImpl @Inject constructor( } } - override suspend fun registerEmotion(emotion: Emotion): Result { + override suspend fun registerEmotion(emotion: Emotion): Result> { val selectedEmotion = when (emotion) { Emotion.CALM -> "CALM" Emotion.VITALITY -> "VITALITY" @@ -36,7 +37,11 @@ class EmotionRepositoryImpl @Inject constructor( Emotion.FATIGUE -> "FATIGUE" } - return emotionDataSource.registerEmotion(selectedEmotion).map { _ -> } + return emotionDataSource.registerEmotion(selectedEmotion).map { + it.recommendedRoutines.map { + emotionRecommendedRoutineDto -> emotionRecommendedRoutineDto.toEmotionRecommendRoutine() + } + } } override suspend fun getMyEmotionMarble(currentDate: String): Result = diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/model/EmotionRecommendRoutine.kt b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/model/EmotionRecommendRoutine.kt new file mode 100644 index 00000000..a351fad5 --- /dev/null +++ b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/model/EmotionRecommendRoutine.kt @@ -0,0 +1,7 @@ +package com.threegap.bitnagil.domain.emotion.model + +data class EmotionRecommendRoutine( + val routineId: String, + val routineName: String, + val routineDescription: String, +) diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt index a47ca36b..1cb68de7 100644 --- a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt +++ b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/repository/EmotionRepository.kt @@ -1,10 +1,11 @@ package com.threegap.bitnagil.domain.emotion.repository import com.threegap.bitnagil.domain.emotion.model.Emotion +import com.threegap.bitnagil.domain.emotion.model.EmotionRecommendRoutine import com.threegap.bitnagil.domain.emotion.model.MyEmotion interface EmotionRepository { suspend fun getEmotions(): Result> - suspend fun registerEmotion(emotion: Emotion): Result + suspend fun registerEmotion(emotion: Emotion): Result> suspend fun getMyEmotionMarble(currentDate: String): Result } diff --git a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/usecase/RegisterEmotionUseCase.kt b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/usecase/RegisterEmotionUseCase.kt index bad0b24e..6c695312 100644 --- a/domain/src/main/java/com/threegap/bitnagil/domain/emotion/usecase/RegisterEmotionUseCase.kt +++ b/domain/src/main/java/com/threegap/bitnagil/domain/emotion/usecase/RegisterEmotionUseCase.kt @@ -1,13 +1,14 @@ package com.threegap.bitnagil.domain.emotion.usecase import com.threegap.bitnagil.domain.emotion.model.Emotion +import com.threegap.bitnagil.domain.emotion.model.EmotionRecommendRoutine import com.threegap.bitnagil.domain.emotion.repository.EmotionRepository import javax.inject.Inject class RegisterEmotionUseCase @Inject constructor( private val emotionRepository: EmotionRepository, ) { - suspend operator fun invoke(emotion: Emotion): Result { + suspend operator fun invoke(emotion: Emotion): Result> { return emotionRepository.registerEmotion(emotion) } } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt index fe071e53..6e720d53 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt @@ -1,5 +1,6 @@ package com.threegap.bitnagil.presentation.emotion +import androidx.activity.compose.BackHandler import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -11,22 +12,32 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.threegap.bitnagil.designsystem.BitnagilTheme +import com.threegap.bitnagil.designsystem.component.atom.BitnagilSelectButton +import com.threegap.bitnagil.designsystem.component.atom.BitnagilTextButton +import com.threegap.bitnagil.designsystem.component.atom.BitnagilTextButtonColor +import com.threegap.bitnagil.designsystem.component.block.BitnagilProgressTopBar import com.threegap.bitnagil.designsystem.component.block.BitnagilTopBar import com.threegap.bitnagil.designsystem.modifier.clickableWithoutRipple import com.threegap.bitnagil.presentation.common.flow.collectAsEffect import com.threegap.bitnagil.presentation.emotion.model.Emotion +import com.threegap.bitnagil.presentation.emotion.model.EmotionRecommendRoutineUiModel +import com.threegap.bitnagil.presentation.emotion.model.EmotionScreenStep import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionSideEffect import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionState @@ -37,17 +48,30 @@ fun EmotionScreenContainer( ) { val state by viewModel.stateFlow.collectAsState() + BackHandler { + viewModel.moveToPrev() + } + viewModel.sideEffectFlow.collectAsEffect { sideEffect -> when (sideEffect) { EmotionSideEffect.NavigateToBack -> navigateToBack() } } - EmotionScreen( - state = state, - onClickPreviousButton = navigateToBack, - onClickEmotion = viewModel::selectEmotion, - ) + when(state.step) { + EmotionScreenStep.Emotion -> EmotionScreen( + state = state, + onClickPreviousButton = navigateToBack, + onClickEmotion = viewModel::selectEmotion, + ) + EmotionScreenStep.RecommendRoutines -> EmotionRecommendRoutineScreen( + state = state, + onClickPreviousButton = viewModel::moveToPrev, + onClickRoutine = viewModel::selectRecommendRoutine, + onClickRegisterRecommendRoutines = viewModel::registerRecommendRoutines, + onClickSkip = navigateToBack + ) + } } @Composable @@ -111,17 +135,127 @@ private fun EmotionScreen( } } +@Composable +private fun EmotionRecommendRoutineScreen( + state: EmotionState, + onClickPreviousButton: () -> Unit, + onClickRoutine: (String) -> Unit, + onClickRegisterRecommendRoutines: () -> Unit, + onClickSkip: () -> Unit, +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = BitnagilTheme.colors.coolGray99), + ) { + BitnagilProgressTopBar( + onBackClick = onClickPreviousButton, + progress = 1f, + ) + + Column( + modifier = Modifier + .weight(1f) + .padding(start = 16.dp, end = 16.dp, bottom = 20.dp, top = 32.dp), + ) { + Text( + text = "오늘 감정에 따른\n루틴을 추천드릴께요!", + color = BitnagilTheme.colors.navy500, + style = BitnagilTheme.typography.title2Bold, + ) + + + Spacer(modifier = Modifier.height(10.dp)) + + Text( + text = "오늘 당신의 감정 상태에 맞춰 구성된 맞춤 루틴이에요.\n원하는 루틴을 선택해서 가볍게 시작해보세요.", + color = BitnagilTheme.colors.coolGray50, + style = BitnagilTheme.typography.body2Medium, + ) + + + Spacer(modifier = Modifier.height(28.dp)) + + val scrollState = rememberScrollState() + Column( + modifier = Modifier + .weight(1f) + .verticalScroll(state = scrollState), + ) { + for (recommendRoutine in state.recommendRoutines) { + BitnagilSelectButton( + title = recommendRoutine.name, + description = recommendRoutine.description, + onClick = { onClickRoutine(recommendRoutine.id) }, + selected = recommendRoutine.selected, + modifier = Modifier.padding(bottom = 12.dp), + ) + } + } + + Spacer(modifier = Modifier.height(12.dp)) + + BitnagilTextButton( + text = "변경하기", + onClick = onClickRegisterRecommendRoutines, + enabled = state.registerRecommendRoutinesButtonEnabled, + ) + + Spacer(modifier = Modifier.height(10.dp)) + + BitnagilTextButton( + text = "건너뛰기", + onClick = onClickSkip, + colors = BitnagilTextButtonColor.skip().copy( + defaultBackgroundColor = Color.Transparent, + pressedBackgroundColor = Color.Transparent, + disabledBackgroundColor = Color.Transparent, + ), + textStyle = BitnagilTheme.typography.body2Regular, + textDecoration = TextDecoration.Underline, + ) + } + } +} + @Preview @Composable -fun MyPageScreenPreview() { +private fun EmotionScreenPreview() { BitnagilTheme { EmotionScreen( state = EmotionState( emotions = Emotion.entries, isLoading = false, + step = EmotionScreenStep.Emotion, ), onClickEmotion = { _ -> }, onClickPreviousButton = {}, ) } } + +@Preview +@Composable +private fun EmotionRecommendRoutineScreenPreview() { + BitnagilTheme { + EmotionRecommendRoutineScreen( + state = EmotionState( + emotions = Emotion.entries, + isLoading = false, + step = EmotionScreenStep.RecommendRoutines, + recommendRoutines = listOf( + EmotionRecommendRoutineUiModel( + id = "1", + name = "루틴 이름", + description = "루틴 설명", + selected = true, + ) + ) + ), + onClickPreviousButton = {}, + onClickRoutine = {}, + onClickRegisterRecommendRoutines = {}, + onClickSkip = {}, + ) + } +} diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt index db699073..b56df180 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt @@ -4,8 +4,11 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.threegap.bitnagil.domain.emotion.usecase.GetEmotionsUseCase import com.threegap.bitnagil.domain.emotion.usecase.RegisterEmotionUseCase +import com.threegap.bitnagil.domain.onboarding.usecase.RegisterRecommendOnBoardingRoutinesUseCase import com.threegap.bitnagil.presentation.common.mviviewmodel.MviViewModel import com.threegap.bitnagil.presentation.emotion.model.Emotion +import com.threegap.bitnagil.presentation.emotion.model.EmotionRecommendRoutineUiModel +import com.threegap.bitnagil.presentation.emotion.model.EmotionScreenStep import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionIntent import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionSideEffect import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionState @@ -20,6 +23,7 @@ class EmotionViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val getEmotionsUseCase: GetEmotionsUseCase, private val registerEmotionUseCase: RegisterEmotionUseCase, + private val registerRecommendOnBoardingRoutinesUseCase: RegisterRecommendOnBoardingRoutinesUseCase, ) : MviViewModel( savedStateHandle = savedStateHandle, initState = EmotionState.Init, @@ -51,15 +55,55 @@ class EmotionViewModel @Inject constructor( isLoading = false, ) } - EmotionIntent.RegisterEmotionSuccess -> { - postSideEffect(EmotionSideEffect.NavigateToBack) - return null + is EmotionIntent.RegisterEmotionSuccess -> { + return state.copy( + recommendRoutines = intent.recommendRoutines, + step = EmotionScreenStep.RecommendRoutines, + isLoading = false, + ) } EmotionIntent.RegisterEmotionLoading -> { return state.copy( isLoading = true, ) } + EmotionIntent.RegisterRecommendRoutinesLoading -> { + return state.copy( + isLoading = true, + ) + } + EmotionIntent.RegisterRecommendRoutinesFailure -> { + return state.copy( + isLoading = false, + ) + } + EmotionIntent.RegisterRecommendRoutinesSuccess -> { + postSideEffect(EmotionSideEffect.NavigateToBack) + return null + } + EmotionIntent.BackToSelectEmotionStep -> { + return state.copy( + recommendRoutines = listOf(), + step = EmotionScreenStep.Emotion, + isLoading = false, + ) + } + + is EmotionIntent.SelectRecommendRoutine -> { + val selectChangedRecommendRoutines = state.recommendRoutines.map { + if (it.id == intent.recommendRoutineId) { + it.copy(selected = !it.selected) + } else { + it + } + } + return state.copy(recommendRoutines = selectChangedRecommendRoutines) + } + + EmotionIntent.NavigateToBack -> { + postSideEffect(EmotionSideEffect.NavigateToBack) + return null + } } } @@ -70,8 +114,9 @@ class EmotionViewModel @Inject constructor( viewModelScope.launch { sendIntent(EmotionIntent.RegisterEmotionLoading) registerEmotionUseCase(emotion = emotion.toDomain()).fold( - onSuccess = { - sendIntent(EmotionIntent.RegisterEmotionSuccess) + onSuccess = { emotionRecommendRoutines -> + val recommendRoutines = emotionRecommendRoutines.map { EmotionRecommendRoutineUiModel.fromEmotionRecommendRoutine(it) } + sendIntent(EmotionIntent.RegisterEmotionSuccess(recommendRoutines)) }, onFailure = { // todo 실패 케이스 정의되면 처리 @@ -79,4 +124,41 @@ class EmotionViewModel @Inject constructor( ) } } + + fun selectRecommendRoutine(recommendRoutineId: String) { + viewModelScope.launch { + sendIntent(EmotionIntent.SelectRecommendRoutine(recommendRoutineId)) + } + } + + fun moveToPrev() { + viewModelScope.launch { + val currentState = stateFlow.value + + when(currentState.step) { + EmotionScreenStep.Emotion -> sendIntent(EmotionIntent.NavigateToBack) + EmotionScreenStep.RecommendRoutines -> sendIntent(EmotionIntent.BackToSelectEmotionStep) + } + } + } + + fun registerRecommendRoutines() { + val isLoading = stateFlow.value.isLoading + if (isLoading) return + + viewModelScope.launch { + sendIntent(EmotionIntent.RegisterRecommendRoutinesLoading) + + val currentState = stateFlow.value + val selectedRecommendRoutineIds = currentState.recommendRoutines.filter { it.selected }.map { it.id } + registerRecommendOnBoardingRoutinesUseCase(selectedRecommendRoutineIds).fold( + onSuccess = { + sendIntent(EmotionIntent.RegisterRecommendRoutinesSuccess) + }, + onFailure = { + sendIntent(EmotionIntent.RegisterRecommendRoutinesFailure) + }, + ) + } + } } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt new file mode 100644 index 00000000..cc9e8525 --- /dev/null +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt @@ -0,0 +1,26 @@ +package com.threegap.bitnagil.presentation.emotion.model + +import android.os.Parcelable +import com.threegap.bitnagil.domain.emotion.model.EmotionRecommendRoutine +import kotlinx.parcelize.Parcelize + +@Parcelize +data class EmotionRecommendRoutineUiModel( + val id: String, + val name: String, + val description: String, + val selected: Boolean, +) : Parcelable { + companion object { + fun fromEmotionRecommendRoutine( + emotionRecommendRoutine: EmotionRecommendRoutine + ) : EmotionRecommendRoutineUiModel { + return EmotionRecommendRoutineUiModel( + id = emotionRecommendRoutine.routineId, + name = emotionRecommendRoutine.routineName, + description = emotionRecommendRoutine.routineDescription, + selected = false, + ) + } + } +} diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionScreenStep.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionScreenStep.kt new file mode 100644 index 00000000..434c06ce --- /dev/null +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionScreenStep.kt @@ -0,0 +1,6 @@ +package com.threegap.bitnagil.presentation.emotion.model + +enum class EmotionScreenStep { + Emotion, RecommendRoutines, + ; +} diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt index 2778c0c6..9412c605 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt @@ -2,9 +2,16 @@ package com.threegap.bitnagil.presentation.emotion.model.mvi import com.threegap.bitnagil.presentation.common.mviviewmodel.MviIntent import com.threegap.bitnagil.presentation.emotion.model.Emotion +import com.threegap.bitnagil.presentation.emotion.model.EmotionRecommendRoutineUiModel sealed class EmotionIntent : MviIntent { data class EmotionListLoadSuccess(val emotions: List) : EmotionIntent() - data object RegisterEmotionSuccess : EmotionIntent() + data class RegisterEmotionSuccess(val recommendRoutines: List) : EmotionIntent() data object RegisterEmotionLoading : EmotionIntent() + data object RegisterRecommendRoutinesLoading: EmotionIntent() + data object RegisterRecommendRoutinesSuccess: EmotionIntent() + data object RegisterRecommendRoutinesFailure: EmotionIntent() + data object BackToSelectEmotionStep: EmotionIntent() + data class SelectRecommendRoutine(val recommendRoutineId: String) : EmotionIntent() + data object NavigateToBack: EmotionIntent() } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt index c43268a6..6636de95 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt @@ -3,6 +3,8 @@ package com.threegap.bitnagil.presentation.emotion.model.mvi import androidx.compose.runtime.Immutable import com.threegap.bitnagil.presentation.common.mviviewmodel.MviState import com.threegap.bitnagil.presentation.emotion.model.Emotion +import com.threegap.bitnagil.presentation.emotion.model.EmotionRecommendRoutineUiModel +import com.threegap.bitnagil.presentation.emotion.model.EmotionScreenStep import kotlinx.parcelize.Parcelize @Parcelize @@ -10,11 +12,17 @@ import kotlinx.parcelize.Parcelize data class EmotionState( val emotions: List, val isLoading: Boolean, + val recommendRoutines: List = emptyList(), + val step: EmotionScreenStep, ) : MviState { companion object { val Init = EmotionState( emotions = emptyList(), isLoading = true, + step = EmotionScreenStep.Emotion ) } + + val registerRecommendRoutinesButtonEnabled: Boolean + get() = recommendRoutines.any { it.selected } } From 1a2b05cf01897db268f46d11196f5a634425fd3c Mon Sep 17 00:00:00 2001 From: yunsehwan Date: Wed, 30 Jul 2025 20:22:04 +0900 Subject: [PATCH 4/6] =?UTF-8?q?CHORE:=20ktlint=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dto/EmotionRecommendedRoutineDto.kt | 2 +- .../emotion/repositoryImpl/EmotionRepositoryImpl.kt | 3 ++- .../bitnagil/presentation/emotion/EmotionScreen.kt | 12 +++++------- .../presentation/emotion/EmotionViewModel.kt | 2 +- .../emotion/model/EmotionRecommendRoutineUiModel.kt | 4 ++-- .../presentation/emotion/model/mvi/EmotionIntent.kt | 10 +++++----- .../presentation/emotion/model/mvi/EmotionState.kt | 2 +- .../presentation/onboarding/OnBoardingScreen.kt | 8 +++++--- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt index 953cf949..5ac14441 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/model/dto/EmotionRecommendedRoutineDto.kt @@ -15,7 +15,7 @@ data class EmotionRecommendedRoutineDto( @SerialName("recommendedSubRoutineSearchResult") val recommendedSubRoutineSearchResult: List, ) { - fun toEmotionRecommendRoutine() : EmotionRecommendRoutine { + fun toEmotionRecommendRoutine(): EmotionRecommendRoutine { return EmotionRecommendRoutine( routineId = recommendedRoutineId.toString(), routineName = recommendedRoutineName, diff --git a/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt b/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt index fdf6dd9c..6c08bf65 100644 --- a/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt +++ b/data/src/main/java/com/threegap/bitnagil/data/emotion/repositoryImpl/EmotionRepositoryImpl.kt @@ -39,7 +39,8 @@ class EmotionRepositoryImpl @Inject constructor( return emotionDataSource.registerEmotion(selectedEmotion).map { it.recommendedRoutines.map { - emotionRecommendedRoutineDto -> emotionRecommendedRoutineDto.toEmotionRecommendRoutine() + emotionRecommendedRoutineDto -> + emotionRecommendedRoutineDto.toEmotionRecommendRoutine() } } } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt index 6e720d53..af110280 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt @@ -58,8 +58,8 @@ fun EmotionScreenContainer( } } - when(state.step) { - EmotionScreenStep.Emotion -> EmotionScreen( + when (state.step) { + EmotionScreenStep.Emotion -> EmotionScreen( state = state, onClickPreviousButton = navigateToBack, onClickEmotion = viewModel::selectEmotion, @@ -69,7 +69,7 @@ fun EmotionScreenContainer( onClickPreviousButton = viewModel::moveToPrev, onClickRoutine = viewModel::selectRecommendRoutine, onClickRegisterRecommendRoutines = viewModel::registerRecommendRoutines, - onClickSkip = navigateToBack + onClickSkip = navigateToBack, ) } } @@ -164,7 +164,6 @@ private fun EmotionRecommendRoutineScreen( style = BitnagilTheme.typography.title2Bold, ) - Spacer(modifier = Modifier.height(10.dp)) Text( @@ -173,7 +172,6 @@ private fun EmotionRecommendRoutineScreen( style = BitnagilTheme.typography.body2Medium, ) - Spacer(modifier = Modifier.height(28.dp)) val scrollState = rememberScrollState() @@ -249,8 +247,8 @@ private fun EmotionRecommendRoutineScreenPreview() { name = "루틴 이름", description = "루틴 설명", selected = true, - ) - ) + ), + ), ), onClickPreviousButton = {}, onClickRoutine = {}, diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt index b56df180..98a816e1 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt @@ -135,7 +135,7 @@ class EmotionViewModel @Inject constructor( viewModelScope.launch { val currentState = stateFlow.value - when(currentState.step) { + when (currentState.step) { EmotionScreenStep.Emotion -> sendIntent(EmotionIntent.NavigateToBack) EmotionScreenStep.RecommendRoutines -> sendIntent(EmotionIntent.BackToSelectEmotionStep) } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt index cc9e8525..a93a3784 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/EmotionRecommendRoutineUiModel.kt @@ -13,8 +13,8 @@ data class EmotionRecommendRoutineUiModel( ) : Parcelable { companion object { fun fromEmotionRecommendRoutine( - emotionRecommendRoutine: EmotionRecommendRoutine - ) : EmotionRecommendRoutineUiModel { + emotionRecommendRoutine: EmotionRecommendRoutine, + ): EmotionRecommendRoutineUiModel { return EmotionRecommendRoutineUiModel( id = emotionRecommendRoutine.routineId, name = emotionRecommendRoutine.routineName, diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt index 9412c605..33e2b74f 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionIntent.kt @@ -8,10 +8,10 @@ sealed class EmotionIntent : MviIntent { data class EmotionListLoadSuccess(val emotions: List) : EmotionIntent() data class RegisterEmotionSuccess(val recommendRoutines: List) : EmotionIntent() data object RegisterEmotionLoading : EmotionIntent() - data object RegisterRecommendRoutinesLoading: EmotionIntent() - data object RegisterRecommendRoutinesSuccess: EmotionIntent() - data object RegisterRecommendRoutinesFailure: EmotionIntent() - data object BackToSelectEmotionStep: EmotionIntent() + data object RegisterRecommendRoutinesLoading : EmotionIntent() + data object RegisterRecommendRoutinesSuccess : EmotionIntent() + data object RegisterRecommendRoutinesFailure : EmotionIntent() + data object BackToSelectEmotionStep : EmotionIntent() data class SelectRecommendRoutine(val recommendRoutineId: String) : EmotionIntent() - data object NavigateToBack: EmotionIntent() + data object NavigateToBack : EmotionIntent() } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt index 6636de95..e6c00499 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt @@ -19,7 +19,7 @@ data class EmotionState( val Init = EmotionState( emotions = emptyList(), isLoading = true, - step = EmotionScreenStep.Emotion + step = EmotionScreenStep.Emotion, ) } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt index f5c8e753..e0c07696 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/onboarding/OnBoardingScreen.kt @@ -131,9 +131,11 @@ fun OnBoardingScreenPreview() { OnBoardingScreen( state = OnBoardingState.Idle( nextButtonEnable = false, - currentOnBoardingPageInfo = OnBoardingPageInfo.RecommendRoutines(listOf( - OnBoardingItem("1", "루틴명", "세부 루틴 한 줄 설명", null), - )), + currentOnBoardingPageInfo = OnBoardingPageInfo.RecommendRoutines( + listOf( + OnBoardingItem("1", "루틴명", "세부 루틴 한 줄 설명", null), + ), + ), totalStep = 5, currentStep = 1, onBoardingSetType = OnBoardingSetType.RESET, From 852095e44ca4c121b4157d6f058bd0781d80b70d Mon Sep 17 00:00:00 2001 From: yunsehwan Date: Wed, 30 Jul 2025 22:01:25 +0900 Subject: [PATCH 5/6] =?UTF-8?q?FIX:=20=EC=BD=94=EB=93=9C=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC=EC=84=B1=20=EC=9C=A0=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bitnagil/presentation/emotion/EmotionViewModel.kt | 5 ++--- .../bitnagil/presentation/emotion/model/mvi/EmotionState.kt | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt index 98a816e1..9729b1ec 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionViewModel.kt @@ -15,7 +15,6 @@ import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import org.orbitmvi.orbit.syntax.simple.SimpleSyntax -import org.orbitmvi.orbit.syntax.simple.postSideEffect import javax.inject.Inject @HiltViewModel @@ -78,7 +77,7 @@ class EmotionViewModel @Inject constructor( ) } EmotionIntent.RegisterRecommendRoutinesSuccess -> { - postSideEffect(EmotionSideEffect.NavigateToBack) + sendSideEffect(EmotionSideEffect.NavigateToBack) return null } EmotionIntent.BackToSelectEmotionStep -> { @@ -101,7 +100,7 @@ class EmotionViewModel @Inject constructor( } EmotionIntent.NavigateToBack -> { - postSideEffect(EmotionSideEffect.NavigateToBack) + sendSideEffect(EmotionSideEffect.NavigateToBack) return null } } diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt index e6c00499..511c1b76 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/model/mvi/EmotionState.kt @@ -12,13 +12,14 @@ import kotlinx.parcelize.Parcelize data class EmotionState( val emotions: List, val isLoading: Boolean, - val recommendRoutines: List = emptyList(), + val recommendRoutines: List, val step: EmotionScreenStep, ) : MviState { companion object { val Init = EmotionState( emotions = emptyList(), isLoading = true, + recommendRoutines = emptyList(), step = EmotionScreenStep.Emotion, ) } From 240447edec13527573d2b72c05811a41a355da84 Mon Sep 17 00:00:00 2001 From: yunsehwan Date: Wed, 30 Jul 2025 22:05:15 +0900 Subject: [PATCH 6/6] =?UTF-8?q?FIX:=20Preview=20=EC=9D=B8=EC=9E=90=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt index af110280..20fc5846 100644 --- a/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/emotion/EmotionScreen.kt @@ -225,6 +225,7 @@ private fun EmotionScreenPreview() { emotions = Emotion.entries, isLoading = false, step = EmotionScreenStep.Emotion, + recommendRoutines = listOf(), ), onClickEmotion = { _ -> }, onClickPreviousButton = {},