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.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.tt.honeyDue.data.DataManager
|
||||||
import com.tt.honeyDue.models.Residence
|
import com.tt.honeyDue.models.Residence
|
||||||
import com.tt.honeyDue.models.ResidenceCreateRequest
|
import com.tt.honeyDue.models.ResidenceCreateRequest
|
||||||
import com.tt.honeyDue.models.TotalSummary
|
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.ApiResult
|
||||||
import com.tt.honeyDue.network.APILayer
|
import com.tt.honeyDue.network.APILayer
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ResidenceViewModel : ViewModel() {
|
class ResidenceViewModel : ViewModel() {
|
||||||
@@ -28,8 +32,24 @@ class ResidenceViewModel : ViewModel() {
|
|||||||
private val _updateResidenceState = MutableStateFlow<ApiResult<Residence>>(ApiResult.Idle)
|
private val _updateResidenceState = MutableStateFlow<ApiResult<Residence>>(ApiResult.Idle)
|
||||||
val updateResidenceState: StateFlow<ApiResult<Residence>> = _updateResidenceState
|
val updateResidenceState: StateFlow<ApiResult<Residence>> = _updateResidenceState
|
||||||
|
|
||||||
private val _residenceTasksState = MutableStateFlow<ApiResult<TaskColumnsResponse>>(ApiResult.Idle)
|
/// Residence-scoped kanban derived from `DataManager.allTasks` filtered
|
||||||
val residenceTasksState: StateFlow<ApiResult<TaskColumnsResponse>> = _residenceTasksState
|
/// 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)
|
private val _myResidencesState = MutableStateFlow<ApiResult<MyResidencesResponse>>(ApiResult.Idle)
|
||||||
val myResidencesState: StateFlow<ApiResult<MyResidencesResponse>> = _myResidencesState
|
val myResidencesState: StateFlow<ApiResult<MyResidencesResponse>> = _myResidencesState
|
||||||
@@ -85,13 +105,16 @@ class ResidenceViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun resetResidenceTasksState() {
|
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 {
|
viewModelScope.launch {
|
||||||
_residenceTasksState.value = ApiResult.Loading
|
APILayer.getTasks(forceRefresh = forceRefresh)
|
||||||
_residenceTasksState.value = APILayer.getTasksByResidence(residenceId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user