refactor: getTasksByResidence is now a thin filter over _allTasks
Was 3 fallback paths (per-residence cache → filter from allTasks → network). Now: ensure _allTasks fresh, return filter. The per-residence cache becomes write-only by this path, scheduled for deletion in the next commit. Eliminates a class of bugs where the per-residence cache slot could be missing while _allTasks was stale — the old Path 1+2 would either return stale data or skip and hit the API redundantly.
This commit is contained in:
@@ -615,36 +615,22 @@ object APILayer {
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns kanban data for a single residence. Single source of truth
|
||||
* is `_allTasks`; this function ensures it's fresh, then filters.
|
||||
*
|
||||
* Replaces the previous 3-path implementation (per-residence cache →
|
||||
* filter from allTasks → API) that produced inconsistent results
|
||||
* when the per-residence cache slot was empty but `_allTasks` was
|
||||
* stale. Phase 3 deletes the per-residence cache entirely.
|
||||
*/
|
||||
suspend fun getTasksByResidence(residenceId: Int, forceRefresh: Boolean = false): ApiResult<TaskColumnsResponse> {
|
||||
// 1. Check residence-specific cache first
|
||||
if (!forceRefresh && DataManager.isCacheValid(DataManager.tasksByResidenceCacheTime[residenceId] ?: 0L)) {
|
||||
val cached = DataManager.tasksByResidence.value[residenceId]
|
||||
if (cached != null) {
|
||||
return ApiResult.Success(cached)
|
||||
}
|
||||
}
|
||||
val allTasksResult = getTasks(forceRefresh = forceRefresh)
|
||||
if (allTasksResult is ApiResult.Error) return allTasksResult
|
||||
|
||||
// 2. Try filtering from allTasks cache before hitting API (optimization)
|
||||
// This avoids a redundant API call when we already have all tasks loaded
|
||||
if (!forceRefresh && DataManager.isCacheValid(DataManager.tasksCacheTime)) {
|
||||
val filtered = DataManager.getTasksForResidence(residenceId)
|
||||
if (filtered != null) {
|
||||
// Cache the filtered result for future use
|
||||
DataManager.setTasksForResidence(residenceId, filtered)
|
||||
return ApiResult.Success(filtered)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback: Fetch from API
|
||||
val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
|
||||
val result = taskApi.getTasksByResidence(token, residenceId)
|
||||
|
||||
// Update DataManager on success
|
||||
if (result is ApiResult.Success) {
|
||||
DataManager.setTasksForResidence(residenceId, result.data)
|
||||
}
|
||||
|
||||
return result
|
||||
val filtered = DataManager.getTasksForResidence(residenceId)
|
||||
?: return ApiResult.Error("Tasks unavailable", 0)
|
||||
return ApiResult.Success(filtered)
|
||||
}
|
||||
|
||||
suspend fun createTask(request: TaskCreateRequest): ApiResult<TaskResponse> {
|
||||
|
||||
Reference in New Issue
Block a user