Skip to content

Commit

Permalink
[REFACTOR] #89 알람 목록 화면 ViewModel 리펙토링
Browse files Browse the repository at this point in the history
  • Loading branch information
l5x5l committed Dec 28, 2024
1 parent 67b6909 commit 8749fd0
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 45 deletions.
4 changes: 2 additions & 2 deletions app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import com.strayalpaca.pokitdetail.PokitDetailScreenContainer
import com.strayalpaca.pokitdetail.PokitDetailViewModel
import pokitmons.pokit.LoginViewModel
import pokitmons.pokit.alarm.AlarmScreenContainer
import pokitmons.pokit.alarm.AlarmViewModel
import pokitmons.pokit.alarm.AlarmViewModelImpl
import pokitmons.pokit.home.HomeScreen
import pokitmons.pokit.home.pokit.PokitViewModel
import pokitmons.pokit.keyword.KeywordScreen
Expand Down Expand Up @@ -213,7 +213,7 @@ fun RootNavHost(
}

composable(route = Alarm.route) {
val viewModel: AlarmViewModel = hiltViewModel()
val viewModel: AlarmViewModelImpl = hiltViewModel()
AlarmScreenContainer(
viewModel = viewModel,
onBackPressed = navHostController::popBackStack,
Expand Down
44 changes: 19 additions & 25 deletions feature/alarm/src/main/java/pokitmons/pokit/alarm/AlarmScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import pokitmons.pokit.alarm.components.alarmitem.AlarmItem
import pokitmons.pokit.alarm.components.toolbar.Toolbar
import pokitmons.pokit.alarm.model.Alarm
import pokitmons.pokit.alarm.model.AlarmScreenSideEffect
import pokitmons.pokit.core.feature.flow.collectAsEffect
import pokitmons.pokit.core.feature.model.paging.PagingState
import pokitmons.pokit.core.ui.components.atom.loading.LoadingProgress
import pokitmons.pokit.core.ui.components.template.pooki.Pooki
Expand All @@ -26,40 +27,33 @@ import pokitmons.pokit.core.ui.R.string as coreString

@Composable
fun AlarmScreenContainer(
viewModel: AlarmViewModel,
viewModel: AlarmViewModelInterface,
onNavigateToLinkModify: (String) -> Unit = {},
onBackPressed: () -> Unit,
) {
val alarms by viewModel.alarms.collectAsState()
val alarmsState by viewModel.alarmsState.collectAsState()
viewModel.sideEffect.collectAsEffect { sideEffect ->
when (sideEffect) {
is AlarmScreenSideEffect.NavigateToLinkModify -> {
onNavigateToLinkModify(sideEffect.linkId)
}
}
}

AlarmScreen(
onClickBack = onBackPressed,
onClickAlarm = remember {
{ alarmId ->
viewModel.readAlarm(alarmId)
onNavigateToLinkModify(alarmId)
}
},
onClickAlarmRemove = viewModel::removeAlarm,
alarms = alarms,
alarmsState = alarmsState,
loadNextAlarms = viewModel::loadNextAlarms,
refreshAlarms = viewModel::refreshAlarms
viewModel = viewModel
)
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AlarmScreen(
onClickBack: () -> Unit = {},
onClickAlarm: (String) -> Unit = {},
onClickAlarmRemove: (String) -> Unit = {},
alarms: List<Alarm> = emptyList(),
alarmsState: PagingState = PagingState.IDLE,
loadNextAlarms: () -> Unit = {},
refreshAlarms: () -> Unit = {},
viewModel: AlarmViewModelInterface
) {
val alarms by viewModel.alarms.collectAsState()
val alarmsState by viewModel.alarmsState.collectAsState()

Column(
modifier = Modifier.fillMaxSize()
) {
Expand All @@ -79,7 +73,7 @@ fun AlarmScreen(

LaunchedEffect(startAlarmPaging.value) {
if (startAlarmPaging.value && alarmsState == PagingState.IDLE) {
loadNextAlarms()
viewModel.loadNextAlarms()
}
}

Expand All @@ -98,7 +92,7 @@ fun AlarmScreen(
.weight(1f),
title = stringResource(id = coreString.title_error),
sub = stringResource(id = coreString.sub_error),
onClickRetry = refreshAlarms
onClickRetry = viewModel::refreshAlarms
)
}
alarms.isEmpty() -> {
Expand All @@ -124,8 +118,8 @@ fun AlarmScreen(
AlarmItem(
modifier = Modifier.animateItemPlacement(),
alarm = alarm,
onClickAlarm = onClickAlarm,
onClickRemove = onClickAlarmRemove
onClickAlarm = viewModel::readAlarmThenMoveToModifyLink,
onClickRemove = viewModel::removeAlarm
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import pokitmons.pokit.alarm.model.Alarm
import pokitmons.pokit.alarm.model.AlarmScreenSideEffect
import pokitmons.pokit.core.feature.flow.EventFlow
import pokitmons.pokit.core.feature.flow.MutableEventFlow
import pokitmons.pokit.core.feature.flow.asEventFlow
import pokitmons.pokit.core.feature.model.paging.PagingLoadResult
import pokitmons.pokit.core.feature.model.paging.PagingSource
import pokitmons.pokit.core.feature.model.paging.PagingState
Expand All @@ -16,10 +20,10 @@ import pokitmons.pokit.domain.usecase.alert.GetAlertsUseCase
import javax.inject.Inject

@HiltViewModel
class AlarmViewModel @Inject constructor(
class AlarmViewModelImpl @Inject constructor(
private val getAlertsUseCase: GetAlertsUseCase,
private val deleteAlertUseCase: DeleteAlertUseCase,
) : ViewModel() {
) : ViewModel(), AlarmViewModelInterface {

private val alarmPagingSource = object : PagingSource<Alarm> {
override suspend fun load(pageIndex: Int, pageSize: Int): PagingLoadResult<Alarm> {
Expand All @@ -37,44 +41,51 @@ class AlarmViewModel @Inject constructor(
coroutineScope = viewModelScope
)

val alarms: StateFlow<List<Alarm>> = alarmPaging.pagingData
val alarmsState: StateFlow<PagingState> = alarmPaging.pagingState
private val _sideEffect = MutableEventFlow<AlarmScreenSideEffect>()
override val sideEffect: EventFlow<AlarmScreenSideEffect>
get() = _sideEffect.asEventFlow()

override val alarms: StateFlow<List<Alarm>>
get() = alarmPaging.pagingData
override val alarmsState: StateFlow<PagingState>
get() = alarmPaging.pagingState

init {
viewModelScope.launch {
alarmPaging.refresh()
}
}

fun removeAlarm(alarmId: String) {
val id = alarmId.toIntOrNull() ?: return
override fun loadNextAlarms() {
viewModelScope.launch {
val response = deleteAlertUseCase.deleteAlert(id)
if (response is PokitResult.Success) {
viewModelScope.launch {
alarmPaging.deleteItem(alarmId)
}
}
alarmPaging.load()
}
}

fun loadNextAlarms() {
override fun refreshAlarms() {
viewModelScope.launch {
alarmPaging.load()
alarmPaging.refresh()
}
}

fun refreshAlarms() {
override fun removeAlarm(alarmId: String) {
val id = alarmId.toIntOrNull() ?: return
viewModelScope.launch {
alarmPaging.refresh()
val response = deleteAlertUseCase.deleteAlert(id)
if (response is PokitResult.Success) {
viewModelScope.launch {
alarmPaging.deleteItem(alarmId)
}
}
}
}

fun readAlarm(alarmId: String) {
override fun readAlarmThenMoveToModifyLink(alarmId: String) {
val targetAlarm = alarms.value.find { it.id == alarmId } ?: return

viewModelScope.launch {
alarmPaging.modifyItem(targetItem = targetAlarm.copy(read = true))
_sideEffect.emit(AlarmScreenSideEffect.NavigateToLinkModify(linkId = targetAlarm.contentId))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package pokitmons.pokit.alarm

import kotlinx.coroutines.flow.StateFlow
import pokitmons.pokit.alarm.model.Alarm
import pokitmons.pokit.alarm.model.AlarmScreenSideEffect
import pokitmons.pokit.core.feature.flow.EventFlow
import pokitmons.pokit.core.feature.model.paging.PagingState

interface AlarmViewModelInterface {
val sideEffect: EventFlow<AlarmScreenSideEffect>
val alarms: StateFlow<List<Alarm>>
val alarmsState: StateFlow<PagingState>

fun loadNextAlarms()
fun refreshAlarms()
fun removeAlarm(alarmId: String)
fun readAlarmThenMoveToModifyLink(alarmId: String)
}
27 changes: 26 additions & 1 deletion feature/alarm/src/main/java/pokitmons/pokit/alarm/Preview.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ package pokitmons.pokit.alarm
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import pokitmons.pokit.alarm.model.Alarm
import pokitmons.pokit.alarm.model.AlarmScreenSideEffect
import pokitmons.pokit.core.feature.flow.EventFlow
import pokitmons.pokit.core.feature.flow.MutableEventFlow
import pokitmons.pokit.core.feature.model.paging.PagingState
import pokitmons.pokit.core.ui.theme.PokitTheme

@Preview(showBackground = true)
Expand All @@ -12,8 +18,27 @@ internal fun Preview() {
PokitTheme {
Column {
AlarmScreen(
alarms = listOf(Alarm(id = "1", title = "title1", thumbnail = ""), Alarm(id = "2", title = "title2", thumbnail = ""))
onClickBack = {},
viewModel = dummyAlarmViewModel,
)
}
}
}

private val dummyAlarmViewModel = object : AlarmViewModelInterface {
override val sideEffect: EventFlow<AlarmScreenSideEffect>
get() = MutableEventFlow()
override val alarms: StateFlow<List<Alarm>>
get() = MutableStateFlow(listOf(Alarm(id = "1", title = "title1", thumbnail = ""), Alarm(id = "2", title = "title2", thumbnail = "")))
override val alarmsState: StateFlow<PagingState>
get() = MutableStateFlow(PagingState.IDLE)

override fun loadNextAlarms() {}

override fun refreshAlarms() {}

override fun removeAlarm(alarmId: String) {}

override fun readAlarmThenMoveToModifyLink(alarmId: String) {}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package pokitmons.pokit.alarm.model

sealed class AlarmScreenSideEffect {
data class NavigateToLinkModify(val linkId: String) : AlarmScreenSideEffect()
}

0 comments on commit 8749fd0

Please sign in to comment.