Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
a077610
[REFACTOR/#231] SplashViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
0f29771
[REFACTOR/#231] OnboardingViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
1c3239f
[REFACTOR/#231] AlarmAddEditViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
ca8f143
[REFACTOR/#231] handleSideEffect 위치를 Route 바로 아래로 이동하여 구조 가독성 개선
DongChyeon Jul 9, 2025
ad83ccd
[REFACTOR/#231] HomeViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
61c6bf7
[REFACTOR/#231] SettingViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
53034c6
[REFACTOR/#231] EditProfileViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
8686872
[REFACTOR/#231] AlarmActionViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
742d645
[REFACTOR/#231] AlarmSnoozeTimerViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
99194cc
[REFACTOR/#231] FortuneViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
9659795
[REFACTOR/#231] MissionViewModel을 ContainerHost 기반으로 리팩토링
DongChyeon Jul 9, 2025
92e1dec
[REMOVE/#231] BaseViewModel 제거
DongChyeon Jul 9, 2025
4fbdeb2
[RENAME/#231] onAction -> processAction
DongChyeon Jul 12, 2025
deb5b4d
[FIX/#231] 운세 재요청 실패 시 홈화면 이동
DongChyeon Jul 12, 2025
c5ff196
[REFACTOR/#231] 중첩 runCatching 제거 및 중복 코드 제거
DongChyeon Jul 12, 2025
04fb29d
[REFACTOR/#231] intent 내에서 processAction 호출 제거
DongChyeon Jul 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 0 additions & 72 deletions core/ui/src/main/java/com/yapp/ui/base/BaseViewModel.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class FortuneRepositoryImpl @Inject constructor(
fortuneResponse.toDomain()
}
}

override suspend fun getFortune(fortuneId: Long): Result<Fortune> {
return fortuneRemoteDataSource.getFortune(fortuneId)
.mapCatching { fortuneResponse ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ fun NavGraphBuilder.alarmInteractionNavGraph(
composable<AlarmInteractionDestination.AlarmSnoozeTimer>(
typeMap = mapOf(typeOf<Alarm>() to AlarmArgType),
) {
AlarmSnoozeTimerRoute(
navigator = navigator,
)
AlarmSnoozeTimerRoute()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -36,6 +35,7 @@ import com.yapp.ui.component.button.OrbitButton
import com.yapp.ui.component.lottie.LottieAnimation
import com.yapp.ui.utils.heightForScreenPercentage
import feature.alarm.interaction.R
import org.orbitmvi.orbit.compose.collectSideEffect
import java.util.Locale

@Composable
Expand All @@ -44,16 +44,9 @@ internal fun AlarmActionRoute(
navigator: OrbitNavigator,
) {
val state by viewModel.container.stateFlow.collectAsStateWithLifecycle()
val sideEffect = viewModel.container.sideEffectFlow

LaunchedEffect(sideEffect) {
sideEffect.collect { action ->
when (action) {
is AlarmActionContract.SideEffect.NavigateToAlarmSnooze -> {
navigator.navigateToAlarmSnoozeTimer(action.alarm)
}
}
}
viewModel.collectSideEffect {
handleSideEffect(it, navigator)
}

AlarmActionScreen(
Expand All @@ -62,6 +55,17 @@ internal fun AlarmActionRoute(
)
}

private fun handleSideEffect(
sideEffect: AlarmActionContract.SideEffect,
navigator: OrbitNavigator,
) {
when (sideEffect) {
is AlarmActionContract.SideEffect.NavigateToAlarmSnooze -> {
navigator.navigateToAlarmSnoozeTimer(sideEffect.alarm)
}
}
}

@Composable
internal fun AlarmActionScreen(
stateProvider: () -> AlarmActionContract.State,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package com.yapp.alarm.interaction.action

import android.app.Application
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.ViewModel
import com.yapp.alarm.pendingIntent.interaction.createAlarmDismissIntent
import com.yapp.alarm.pendingIntent.interaction.createAlarmSnoozeIntent
import com.yapp.domain.model.Alarm
import com.yapp.domain.repository.FortuneRepository
import com.yapp.ui.base.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.orbitmvi.orbit.Container
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 java.time.LocalDate
import java.time.LocalTime
import java.time.format.DateTimeFormatter
Expand All @@ -25,79 +28,79 @@ class AlarmActionViewModel @Inject constructor(
private val app: Application,
private val fortuneRepository: FortuneRepository,
savedStateHandle: SavedStateHandle,
) : BaseViewModel<AlarmActionContract.State, AlarmActionContract.SideEffect>(
AlarmActionContract.State(),
) {
) : ViewModel(), ContainerHost<AlarmActionContract.State, AlarmActionContract.SideEffect> {

override val container: Container<AlarmActionContract.State, AlarmActionContract.SideEffect> = container(
initialState = AlarmActionContract.State(),
) {
fetchIsFirstMission()
initializeAlarmState()
startClock()
}

private val alarmJson: String? = savedStateHandle.get<String>("alarm")
private val alarm: Alarm? = alarmJson?.let { Alarm.fromJson(it) }

init {
fetchIsFirstMission()
updateState {
copy(
fun processAction(action: AlarmActionContract.Action) {
when (action) {
is AlarmActionContract.Action.Snooze -> snooze()
is AlarmActionContract.Action.Dismiss -> dismiss()
}
}

private fun initializeAlarmState() = intent {
reduce {
state.copy(
snoozeEnabled = alarm?.isSnoozeEnabled ?: false,
snoozeCount = alarm?.snoozeCount ?: 5,
snoozeInterval = alarm?.snoozeInterval ?: 5,
)
}

startClock()
}

private fun fetchIsFirstMission() {
viewModelScope.launch {
val fortuneDate = fortuneRepository.fortuneDateFlow.firstOrNull()
val todayDate = LocalDate.now().format(DateTimeFormatter.ISO_DATE)
val isFirstMission = fortuneDate != todayDate
private fun fetchIsFirstMission() = intent {
val fortuneDate = fortuneRepository.fortuneDateFlow.firstOrNull()
val todayDate = LocalDate.now().format(DateTimeFormatter.ISO_DATE)
val isFirstMission = fortuneDate != todayDate

updateState {
copy(isFirstMission = isFirstMission)
}
reduce {
state.copy(isFirstMission = isFirstMission)
}
}

private fun startClock() {
viewModelScope.launch {
while (isActive) {
val now = LocalTime.now()
val today = LocalDate.now()
val dayOfWeek = today.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.KOREAN)

updateState {
copy(
isAm = now.hour < 12,
hour = if (now.hour % 12 == 0) 12 else now.hour % 12,
minute = now.minute,
todayDate = "${today.monthValue}월 ${today.dayOfMonth}일 $dayOfWeek",
initialLoading = false,
)
}
private fun startClock() = intent {
while (true) {
val now = LocalTime.now()
val today = LocalDate.now()
val dayOfWeek = today.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.KOREAN)

delay(1000L)
reduce {
state.copy(
isAm = now.hour < 12,
hour = if (now.hour % 12 == 0) 12 else now.hour % 12,
minute = now.minute,
todayDate = "${today.monthValue}월 ${today.dayOfMonth}일 $dayOfWeek",
initialLoading = false,
)
}
}
}

fun processAction(action: AlarmActionContract.Action) {
when (action) {
is AlarmActionContract.Action.Snooze -> snooze()
is AlarmActionContract.Action.Dismiss -> dismiss()
delay(1000L)
}
}

private fun snooze() {
private fun snooze() = intent {
sendAlarmSnoozeEventToAlarmReceiver()
updateState {
copy(
snoozeCount = if (currentState.snoozeCount == -1) {
currentState.snoozeCount
reduce {
state.copy(
snoozeCount = if (state.snoozeCount == -1) {
state.snoozeCount
} else {
currentState.snoozeCount - 1
state.snoozeCount - 1
},
)
}
alarm?.let {
emitSideEffect(AlarmActionContract.SideEffect.NavigateToAlarmSnooze(it))
postSideEffect(AlarmActionContract.SideEffect.NavigateToAlarmSnooze(it))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -42,7 +41,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.yapp.common.navigation.OrbitNavigator
import com.yapp.designsystem.theme.OrbitTheme
import com.yapp.ui.component.lottie.LottieAnimation
import com.yapp.ui.utils.heightForScreenPercentage
Expand All @@ -51,14 +49,8 @@ import feature.alarm.interaction.R
@Composable
internal fun AlarmSnoozeTimerRoute(
viewModel: AlarmSnoozeTimerViewModel = hiltViewModel(),
navigator: OrbitNavigator,
) {
val state by viewModel.container.stateFlow.collectAsStateWithLifecycle()
val sideEffect = viewModel.container.sideEffectFlow

LaunchedEffect(sideEffect) {
sideEffect.collect { }
}

AlarmSnoozeTimerScreen(
stateProvider = { state },
Expand Down
Loading