android: ResidenceViewModel.residenceTasksState derives from _allTasks
Same screen contract, but the data flows from DataManager.allTasks through a combine(_allTasks, _currentResidenceId) into the existing StateFlow. No per-residence network call needed; the upstream getTasks() refresh propagates and the screen re-renders. Eliminates the gitea#2 race window on Android — same fix as the iOS TaskViewModel commit. Both platforms now react to _allTasks changes without manual refresh.
This commit is contained in:
@@ -2,6 +2,7 @@ package com.tt.honeyDue.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tt.honeyDue.data.DataManager
|
||||
import com.tt.honeyDue.models.Residence
|
||||
import com.tt.honeyDue.models.ResidenceCreateRequest
|
||||
import com.tt.honeyDue.models.TotalSummary
|
||||
@@ -11,7 +12,10 @@ import com.tt.honeyDue.models.ContractorSummary
|
||||
import com.tt.honeyDue.network.ApiResult
|
||||
import com.tt.honeyDue.network.APILayer
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ResidenceViewModel : ViewModel() {
|
||||
@@ -28,8 +32,24 @@ class ResidenceViewModel : ViewModel() {
|
||||
private val _updateResidenceState = MutableStateFlow<ApiResult<Residence>>(ApiResult.Idle)
|
||||
val updateResidenceState: StateFlow<ApiResult<Residence>> = _updateResidenceState
|
||||
|
||||
private val _residenceTasksState = MutableStateFlow<ApiResult<TaskColumnsResponse>>(ApiResult.Idle)
|
||||
val residenceTasksState: StateFlow<ApiResult<TaskColumnsResponse>> = _residenceTasksState
|
||||
/// Residence-scoped kanban derived from `DataManager.allTasks` filtered
|
||||
/// by `_currentResidenceId`. Re-emits whenever either upstream changes,
|
||||
/// so the residence detail screen reacts to new tasks (created or
|
||||
/// completed elsewhere) without manual refresh. Replaces the previous
|
||||
/// imperative `_residenceTasksState` that was only written by
|
||||
/// loadResidenceTasks's API result and stayed stale otherwise.
|
||||
private val _currentResidenceId = MutableStateFlow<Int?>(null)
|
||||
val residenceTasksState: StateFlow<ApiResult<TaskColumnsResponse>> =
|
||||
combine(DataManager.allTasks, _currentResidenceId) { all, id ->
|
||||
when {
|
||||
id == null -> ApiResult.Idle
|
||||
all == null -> ApiResult.Loading
|
||||
else -> {
|
||||
val filtered = DataManager.getTasksForResidence(id)
|
||||
if (filtered != null) ApiResult.Success(filtered) else ApiResult.Loading
|
||||
}
|
||||
}
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), ApiResult.Idle)
|
||||
|
||||
private val _myResidencesState = MutableStateFlow<ApiResult<MyResidencesResponse>>(ApiResult.Idle)
|
||||
val myResidencesState: StateFlow<ApiResult<MyResidencesResponse>> = _myResidencesState
|
||||
@@ -85,13 +105,16 @@ class ResidenceViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
fun resetResidenceTasksState() {
|
||||
_residenceTasksState.value = ApiResult.Idle
|
||||
_currentResidenceId.value = null
|
||||
}
|
||||
|
||||
fun loadResidenceTasks(residenceId: Int) {
|
||||
fun loadResidenceTasks(residenceId: Int, forceRefresh: Boolean = false) {
|
||||
_currentResidenceId.value = residenceId
|
||||
// Trigger an _allTasks refresh in the background. The combine flow
|
||||
// above re-emits Success when allTasks lands, so the screen
|
||||
// re-renders without needing the result here.
|
||||
viewModelScope.launch {
|
||||
_residenceTasksState.value = ApiResult.Loading
|
||||
_residenceTasksState.value = APILayer.getTasksByResidence(residenceId)
|
||||
APILayer.getTasks(forceRefresh = forceRefresh)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user