Files
honeyDueKMP/composeApp/src/commonMain/kotlin/com/example/mycrib/cache/DataPrefetchManager.kt
Trey t e40aed31a7 Remove API pagination and fix contractor UI issues
- 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>
2025-11-21 22:56:43 -06:00

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!!
}
}
}