Files
TaskTTL/composeApp/src/commonMain/kotlin/com/taskttl/data/viewmodel/CountdownViewModel.kt
2025-10-19 21:51:36 +08:00

167 lines
6.8 KiB
Kotlin

package com.taskttl.data.viewmodel
import androidx.lifecycle.viewModelScope
import com.taskttl.core.notification.NotificationManager
import com.taskttl.core.notification.NotificationPayload
import com.taskttl.core.notification.NotificationRepeatType
import com.taskttl.core.utils.DateUtils.toEpochMillis
import com.taskttl.core.viewmodel.BaseViewModel
import com.taskttl.data.local.model.Category
import com.taskttl.data.local.model.CategoryType
import com.taskttl.data.local.model.Countdown
import com.taskttl.data.repository.CategoryRepository
import com.taskttl.data.repository.CountdownRepository
import com.taskttl.data.state.CountdownEffect
import com.taskttl.data.state.CountdownIntent
import com.taskttl.data.state.CountdownState
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.getString
import taskttl.composeapp.generated.resources.Res
import taskttl.composeapp.generated.resources.countdown_add_failed
import taskttl.composeapp.generated.resources.countdown_add_success
import taskttl.composeapp.generated.resources.countdown_delete_failed
import taskttl.composeapp.generated.resources.countdown_delete_success
import taskttl.composeapp.generated.resources.countdown_load_failed
import taskttl.composeapp.generated.resources.countdown_query_failed
import taskttl.composeapp.generated.resources.countdown_update_failed
import taskttl.composeapp.generated.resources.countdown_update_success
/**
* 倒计时视图模型
* @author admin
* @date 2025/10/04
* @constructor 创建[CountdownViewModel]
* @param [countdownRepository] 倒计时存储库
*/
class CountdownViewModel(
private val countdownRepository: CountdownRepository,
private val categoryRepository: CategoryRepository,
) : BaseViewModel<CountdownState, CountdownIntent, CountdownEffect>(CountdownState()) {
init {
processIntent(CountdownIntent.LoadCountdowns)
}
public override fun handleIntent(intent: CountdownIntent) {
when (intent) {
is CountdownIntent.LoadCountdowns -> loadCountdowns()
is CountdownIntent.GetCountdownById -> getCountdownById(intent.countdownId)
is CountdownIntent.AddCountdown -> addCountdown(intent.countdown)
is CountdownIntent.UpdateCountdown -> updateCountdown(intent.countdown)
is CountdownIntent.DeleteCountdown -> deleteCountdown(intent.countdownId)
is CountdownIntent.FilterByCategory -> filterByCategory(intent.category)
is CountdownIntent.ClearError -> clearError()
}
}
private fun loadCountdowns() {
viewModelScope.launch {
updateState { copy(isLoading = true) }
try {
launch {
categoryRepository.getCategoriesByType(CategoryType.COUNTDOWN)
.collect { categories -> updateState { copy(categories = categories) } }
}
launch {
countdownRepository.getAllCountdowns().collect { countdowns ->
updateState {
copy(
countdowns = countdowns,
filteredCountdowns = filterCountdowns(countdowns)
)
}
}
}
} catch (e: Exception) {
val errStr = getString(Res.string.countdown_load_failed)
updateState { copy(isLoading = false, error = e.message ?: errStr) }
} finally {
updateState { copy(isLoading = false) }
}
}
}
private fun getCountdownById(countdownId: String) {
viewModelScope.launch {
try {
val countdown = countdownRepository.getCountdownById(countdownId)
updateState { copy(editingCountdown = countdown) }
} catch (e: Exception) {
val errStr = getString(Res.string.countdown_query_failed)
updateState { copy(isLoading = false, error = e.message ?: errStr) }
}
}
}
private fun addCountdown(countdown: Countdown) {
viewModelScope.launch {
try {
if (state.value.isProcessing) return@launch
updateState { copy(isLoading = false, isProcessing = true) }
countdownRepository.insertCountdown(countdown)
sendEvent(CountdownEffect.ShowMessage(getString(Res.string.countdown_add_success)))
sendEvent(CountdownEffect.NavigateBack)
} catch (e: Exception) {
val errStr = getString(Res.string.countdown_add_failed)
updateState { copy(error = e.message ?: errStr) }
} finally {
updateState { copy(isLoading = false, isProcessing = false) }
}
}
}
private fun updateCountdown(countdown: Countdown) {
viewModelScope.launch {
try {
if (state.value.isProcessing) return@launch
updateState { copy(isLoading = false, isProcessing = true) }
countdownRepository.updateCountdown(countdown)
sendEvent(CountdownEffect.ShowMessage(getString(Res.string.countdown_update_success)))
sendEvent(CountdownEffect.NavigateBack)
} catch (e: Exception) {
val errStr = getString(Res.string.countdown_update_failed)
updateState { copy(error = e.message ?: errStr) }
} finally {
updateState { copy(isLoading = false, isProcessing = false) }
}
}
}
private fun deleteCountdown(countdownId: String) {
viewModelScope.launch {
try {
if (state.value.isProcessing) return@launch
updateState { copy(isLoading = false, isProcessing = true) }
countdownRepository.deleteCountdown(countdownId)
sendEvent(CountdownEffect.ShowMessage(getString(Res.string.countdown_delete_success)))
} catch (e: Exception) {
val errStr = getString(Res.string.countdown_delete_failed)
updateState { copy(error = e.message ?: errStr) }
} finally {
updateState { copy(isLoading = false, isProcessing = false) }
}
}
}
private fun filterByCategory(category: Category?) {
updateState {
copy(
selectedCategory = category,
filteredCountdowns = filterCountdowns(state.value.countdowns)
)
}
}
private fun clearError() {
updateState { copy(error = null) }
}
private fun filterCountdowns(countdowns: List<Countdown>): List<Countdown> {
val currentState = state.value
return countdowns.filter { countdown ->
currentState.selectedCategory?.let { countdown.category == it } ?: true
}
}
}