Files
TaskTTL/composeApp/src/commonMain/kotlin/com/taskttl/data/viewmodel/CountdownViewModel.kt
2025-10-16 21:45:02 +08:00

163 lines
6.6 KiB
Kotlin

package com.taskttl.data.viewmodel
import androidx.lifecycle.viewModelScope
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
}
}
}