- Remove pagination from all Django REST Framework endpoints - Update Kotlin API clients to return direct lists instead of paginated responses - Update iOS ViewModels to handle direct list responses - Remove ContractorListResponse, DocumentListResponse, and PaginatedResponse models - Fix contractor form specialty selector loading with improved DataCache access - Fix contractor sheet presentation to use full screen (.presentationDetents([.large])) - Improve UI test scrolling to handle lists of any size with smart end detection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
201 lines
7.1 KiB
Kotlin
201 lines
7.1 KiB
Kotlin
package com.mycrib.cache
|
|
|
|
import com.mycrib.shared.network.*
|
|
import com.mycrib.storage.TokenStorage
|
|
import kotlinx.coroutines.*
|
|
|
|
/**
|
|
* Manager responsible for prefetching and caching data when the app launches.
|
|
* This ensures all screens have immediate access to data without making API calls.
|
|
*/
|
|
class DataPrefetchManager {
|
|
|
|
private val residenceApi = ResidenceApi()
|
|
private val taskApi = TaskApi()
|
|
private val documentApi = DocumentApi()
|
|
private val contractorApi = ContractorApi()
|
|
private val lookupsApi = LookupsApi()
|
|
|
|
/**
|
|
* Prefetch all essential data on app launch.
|
|
* This runs asynchronously and populates the DataCache.
|
|
*/
|
|
suspend fun prefetchAllData(): Result<Unit> = withContext(Dispatchers.Default) {
|
|
try {
|
|
val token = TokenStorage.getToken()
|
|
if (token == null) {
|
|
return@withContext Result.failure(Exception("Not authenticated"))
|
|
}
|
|
|
|
println("DataPrefetchManager: Starting data prefetch...")
|
|
|
|
// Launch all prefetch operations in parallel
|
|
val jobs = listOf(
|
|
async { prefetchResidences(token) },
|
|
async { prefetchMyResidences(token) },
|
|
async { prefetchTasks(token) },
|
|
async { prefetchDocuments(token) },
|
|
async { prefetchContractors(token) },
|
|
async { prefetchLookups(token) }
|
|
)
|
|
|
|
// Wait for all jobs to complete
|
|
jobs.awaitAll()
|
|
|
|
// Mark cache as initialized
|
|
DataCache.setCacheInitialized(true)
|
|
|
|
println("DataPrefetchManager: Data prefetch completed successfully")
|
|
Result.success(Unit)
|
|
} catch (e: Exception) {
|
|
println("DataPrefetchManager: Error during prefetch: ${e.message}")
|
|
e.printStackTrace()
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Refresh specific data types.
|
|
* Useful for pull-to-refresh functionality.
|
|
*/
|
|
suspend fun refreshResidences(): Result<Unit> = withContext(Dispatchers.Default) {
|
|
try {
|
|
val token = TokenStorage.getToken() ?: return@withContext Result.failure(Exception("Not authenticated"))
|
|
prefetchResidences(token)
|
|
prefetchMyResidences(token)
|
|
Result.success(Unit)
|
|
} catch (e: Exception) {
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
suspend fun refreshTasks(): Result<Unit> = withContext(Dispatchers.Default) {
|
|
try {
|
|
val token = TokenStorage.getToken() ?: return@withContext Result.failure(Exception("Not authenticated"))
|
|
prefetchTasks(token)
|
|
Result.success(Unit)
|
|
} catch (e: Exception) {
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
suspend fun refreshDocuments(): Result<Unit> = withContext(Dispatchers.Default) {
|
|
try {
|
|
val token = TokenStorage.getToken() ?: return@withContext Result.failure(Exception("Not authenticated"))
|
|
prefetchDocuments(token)
|
|
Result.success(Unit)
|
|
} catch (e: Exception) {
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
suspend fun refreshContractors(): Result<Unit> = withContext(Dispatchers.Default) {
|
|
try {
|
|
val token = TokenStorage.getToken() ?: return@withContext Result.failure(Exception("Not authenticated"))
|
|
prefetchContractors(token)
|
|
Result.success(Unit)
|
|
} catch (e: Exception) {
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
// Private prefetch methods
|
|
private suspend fun prefetchResidences(token: String) {
|
|
try {
|
|
println("DataPrefetchManager: Fetching residences...")
|
|
val result = residenceApi.getResidences(token)
|
|
if (result is ApiResult.Success) {
|
|
DataCache.updateResidences(result.data)
|
|
println("DataPrefetchManager: Cached ${result.data.size} residences")
|
|
}
|
|
} catch (e: Exception) {
|
|
println("DataPrefetchManager: Error fetching residences: ${e.message}")
|
|
}
|
|
}
|
|
|
|
private suspend fun prefetchMyResidences(token: String) {
|
|
try {
|
|
println("DataPrefetchManager: Fetching my residences...")
|
|
val result = residenceApi.getMyResidences(token)
|
|
if (result is ApiResult.Success) {
|
|
DataCache.updateMyResidences(result.data)
|
|
println("DataPrefetchManager: Cached my residences")
|
|
}
|
|
} catch (e: Exception) {
|
|
println("DataPrefetchManager: Error fetching my residences: ${e.message}")
|
|
}
|
|
}
|
|
|
|
private suspend fun prefetchTasks(token: String) {
|
|
try {
|
|
println("DataPrefetchManager: Fetching tasks...")
|
|
val result = taskApi.getTasks(token)
|
|
if (result is ApiResult.Success) {
|
|
DataCache.updateAllTasks(result.data)
|
|
println("DataPrefetchManager: Cached tasks")
|
|
}
|
|
} catch (e: Exception) {
|
|
println("DataPrefetchManager: Error fetching tasks: ${e.message}")
|
|
}
|
|
}
|
|
|
|
private suspend fun prefetchDocuments(token: String) {
|
|
try {
|
|
println("DataPrefetchManager: Fetching documents...")
|
|
val result = documentApi.getDocuments(
|
|
token = token,
|
|
residenceId = null,
|
|
documentType = null,
|
|
category = null,
|
|
contractorId = null,
|
|
isActive = null,
|
|
expiringSoon = null,
|
|
tags = null,
|
|
search = null
|
|
)
|
|
if (result is ApiResult.Success) {
|
|
DataCache.updateDocuments(result.data)
|
|
println("DataPrefetchManager: Cached ${result.data.size} documents")
|
|
}
|
|
} catch (e: Exception) {
|
|
println("DataPrefetchManager: Error fetching documents: ${e.message}")
|
|
}
|
|
}
|
|
|
|
private suspend fun prefetchContractors(token: String) {
|
|
try {
|
|
println("DataPrefetchManager: Fetching contractors...")
|
|
val result = contractorApi.getContractors(
|
|
token = token,
|
|
specialty = null,
|
|
isFavorite = null,
|
|
isActive = null,
|
|
search = null
|
|
)
|
|
if (result is ApiResult.Success) {
|
|
// API returns List<ContractorSummary>, not List<Contractor>
|
|
// Skip caching for now - full Contractor objects will be cached when fetched individually
|
|
println("DataPrefetchManager: Fetched ${result.data.size} contractor summaries")
|
|
}
|
|
} catch (e: Exception) {
|
|
println("DataPrefetchManager: Error fetching contractors: ${e.message}")
|
|
}
|
|
}
|
|
|
|
private suspend fun prefetchLookups(token: String) {
|
|
// Lookups are handled separately by LookupsViewModel with their own caching
|
|
println("DataPrefetchManager: Skipping lookups prefetch (handled by LookupsViewModel)")
|
|
}
|
|
|
|
companion object {
|
|
private var instance: DataPrefetchManager? = null
|
|
|
|
fun getInstance(): DataPrefetchManager {
|
|
if (instance == null) {
|
|
instance = DataPrefetchManager()
|
|
}
|
|
return instance!!
|
|
}
|
|
}
|
|
}
|