feat: bundle ID migration + gitea#2 task-cache fix (recovered from fix/task-cache-unification) #4

Merged
admin merged 13 commits from feat/bundle-id-and-task-cache into master 2026-05-01 20:48:29 -05:00
Showing only changes of commit dea8eed184 - Show all commits
@@ -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> {