diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml
index 235114872..75332c1b4 100644
--- a/core/design-system/src/main/res/values/strings.xml
+++ b/core/design-system/src/main/res/values/strings.xml
@@ -192,6 +192,7 @@
닉네임 2~8자
완료
2자에서 8자 이내로 닉네임을 입력해주세요.
+ 짝꿍이 기념일을 먼저 등록했어요
프로필 설정 요청에 실패했습니다.
짝꿍과 연결하고\n함께 키피럽 시작하세요
diff --git a/feature/onboarding/src/main/java/com/twix/onboarding/OnBoardingViewModel.kt b/feature/onboarding/src/main/java/com/twix/onboarding/OnBoardingViewModel.kt
index c27b82fc7..497735b6c 100644
--- a/feature/onboarding/src/main/java/com/twix/onboarding/OnBoardingViewModel.kt
+++ b/feature/onboarding/src/main/java/com/twix/onboarding/OnBoardingViewModel.kt
@@ -23,7 +23,7 @@ class OnBoardingViewModel(
private val onBoardingRepository: OnBoardingRepository,
private val notificationRepository: NotificationRepository,
) : BaseViewModel(OnBoardingUiState()) {
- private var pollingJob: Job? = null
+ private var onboardingStatusJob: Job? = null
private var connectCoupleJob: Job? = null
init {
@@ -70,6 +70,8 @@ class OnBoardingViewModel(
// 디데이 설정 화면
is OnBoardingIntent.SelectDate -> reduceDday(intent.value)
OnBoardingIntent.SubmitDday -> anniversarySetup()
+ OnBoardingIntent.StartDdayPollingStatus -> startDdayPolling()
+ OnBoardingIntent.StopDdayPollingStatus -> stopPolling()
is OnBoardingIntent.SubmitMarketingConsent ->
initNotificationSettings(
@@ -81,14 +83,28 @@ class OnBoardingViewModel(
}
private fun startPolling() {
- if (pollingJob?.isActive == true) return
- pollingJob =
+ startStatusPolling { status ->
+ if (status == OnboardingStatus.COUPLE_CONNECTION) return@startStatusPolling false
+
+ emitSideEffect(OnBoardingSideEffect.CoupleConnection.NavigateToNext)
+ true
+ }
+ }
+
+ private fun startDdayPolling() {
+ startStatusPolling { status ->
+ if (status != OnboardingStatus.COMPLETED) return@startStatusPolling false
+
+ showAnniversaryAlreadyRegisteredToast()
+ emitSideEffect(OnBoardingSideEffect.DdaySetting.NavigateToHome)
+ true
+ }
+ }
+
+ private fun startStatusPolling(onStatusFetched: suspend (OnboardingStatus) -> Boolean) {
+ if (onboardingStatusJob?.isActive == true) return
+ onboardingStatusJob =
viewModelScope.launch {
- /**
- * 네트워크 오류 등으로 API 호출이 연속으로 실패한 횟수
- * 성공 응답을 받으면 0으로 리셋되며, MAX_POLLING_FAILURE_COUNT에 도달하면 폴링을 중단한다.
- * 일시적인 오류에는 폴링을 유지하되, 지속적인 오류 상황에서 무한 루프를 방지하기 위해 사용한다.
- * **/
var consecutiveFailureCount = 0
while (isActive) {
@@ -96,16 +112,15 @@ class OnBoardingViewModel(
when (val result = onBoardingRepository.fetchOnboardingStatus()) {
is AppResult.Success -> {
consecutiveFailureCount = 0
- if (result.data != OnboardingStatus.COUPLE_CONNECTION) {
- stopPolling()
- emitSideEffect(OnBoardingSideEffect.CoupleConnection.NavigateToNext)
+ if (onStatusFetched(result.data)) {
+ onboardingStatusJob = null
break
}
}
is AppResult.Error -> {
if (++consecutiveFailureCount >= MAX_POLLING_FAILURE_COUNT) {
- stopPolling()
+ onboardingStatusJob = null
break
}
}
@@ -115,8 +130,8 @@ class OnBoardingViewModel(
}
private fun stopPolling() {
- pollingJob?.cancel()
- pollingJob = null
+ onboardingStatusJob?.cancel()
+ onboardingStatusJob = null
}
private fun reduceInviteCode(value: String) {
@@ -198,21 +213,29 @@ class OnBoardingViewModel(
launchResult(
block = { onBoardingRepository.fetchOnboardingStatus() },
onSuccess = { onboardingStatus ->
- val sideEffect =
- when (onboardingStatus) {
- OnboardingStatus.ANNIVERSARY_SETUP ->
- OnBoardingSideEffect.ProfileSetting.NavigateToNext
+ when (onboardingStatus) {
+ OnboardingStatus.ANNIVERSARY_SETUP ->
+ tryEmitSideEffect(OnBoardingSideEffect.ProfileSetting.NavigateToNext)
- OnboardingStatus.COMPLETED ->
- OnBoardingSideEffect.ProfileSetting.NavigateToHome
+ OnboardingStatus.COMPLETED ->
+ onProfileAnniversaryAlreadyRegistered()
- else -> return@launchResult
- }
- tryEmitSideEffect(sideEffect)
+ else -> return@launchResult
+ }
},
)
}
+ private fun onProfileAnniversaryAlreadyRegistered() {
+ tryEmitSideEffect(
+ OnBoardingSideEffect.ShowToast(
+ message = R.string.onboarding_anniversary_already_registered_toast,
+ type = ToastType.DEFAULT,
+ ),
+ )
+ tryEmitSideEffect(OnBoardingSideEffect.ProfileSetting.NavigateToHome)
+ }
+
private fun reduceDday(value: LocalDate) {
reduce {
copy(
@@ -255,6 +278,10 @@ class OnBoardingViewModel(
emitSideEffect(OnBoardingSideEffect.ShowToast(message, type))
}
+ private suspend fun showAnniversaryAlreadyRegisteredToast() {
+ showToast(R.string.onboarding_anniversary_already_registered_toast, ToastType.DEFAULT)
+ }
+
companion object {
private const val ALREADY_USED_INVITE_CODE_MESSAGE = "이미 사용된 초대 코드입니다."
private const val INVALID_INVITE_CODE_MESSAGE = "유효하지 않은 초대 코드입니다."
diff --git a/feature/onboarding/src/main/java/com/twix/onboarding/contract/OnBoardingIntent.kt b/feature/onboarding/src/main/java/com/twix/onboarding/contract/OnBoardingIntent.kt
index 72fcb4aa8..debbc4251 100644
--- a/feature/onboarding/src/main/java/com/twix/onboarding/contract/OnBoardingIntent.kt
+++ b/feature/onboarding/src/main/java/com/twix/onboarding/contract/OnBoardingIntent.kt
@@ -35,4 +35,8 @@ sealed interface OnBoardingIntent : Intent {
data object StartPollingStatus : OnBoardingIntent
data object StopPollingStatus : OnBoardingIntent
+
+ data object StartDdayPollingStatus : OnBoardingIntent
+
+ data object StopDdayPollingStatus : OnBoardingIntent
}
diff --git a/feature/onboarding/src/main/java/com/twix/onboarding/dday/DdayRoute.kt b/feature/onboarding/src/main/java/com/twix/onboarding/dday/DdayRoute.kt
index 50c9c139a..af0e01c3c 100644
--- a/feature/onboarding/src/main/java/com/twix/onboarding/dday/DdayRoute.kt
+++ b/feature/onboarding/src/main/java/com/twix/onboarding/dday/DdayRoute.kt
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -54,6 +55,13 @@ fun DdayRoute(
val currentContext by rememberUpdatedState(context)
var showCalendarBottomSheet by remember { mutableStateOf(false) }
+ DisposableEffect(Unit) {
+ viewModel.dispatch(OnBoardingIntent.StartDdayPollingStatus)
+ onDispose {
+ viewModel.dispatch(OnBoardingIntent.StopDdayPollingStatus)
+ }
+ }
+
ObserveAsEvents(viewModel.sideEffect) { sideEffect ->
when (sideEffect) {
OnBoardingSideEffect.DdaySetting.NavigateToHome -> navigateToHome()