This commit adds a comprehensive theming system to Android matching iOS, and fixes package declarations throughout the codebase to match directory structure. Theme System Additions: - Added 11 themes matching iOS: Default, Teal, Ocean, Forest, Sunset, Monochrome, Lavender, Crimson, Midnight, Desert, Mint - Created ThemeColors.kt with exact iOS color values for light/dark modes - Added ThemeManager.kt for dynamic theme switching - Created Spacing.kt with standardized spacing constants (xs/sm/md/lg/xl) - Added ThemePickerDialog.kt for theme selection UI - Integrated theme switching in ProfileScreen.kt - Updated App.kt to observe ThemeManager for reactive theming Component Library: - Added StandardCard.kt and CompactCard.kt for consistent card styling - Added FormTextField.kt with error/helper text support - Added FormSection.kt for grouping related form fields - Added StandardEmptyState.kt for empty state UI Package Migration: - Fixed all package declarations to match directory structure (com.example.mycrib.*) - Updated package declarations in commonMain, androidMain, and iosMain - Fixed all import statements across entire codebase - Ensures compilation on both Android and iOS platforms iOS Theme Rename: - Renamed "Default" theme to "Teal" in iOS - Renamed "Bright" theme to "Default" in iOS to make vibrant colors the default Build Status: - ✅ Android builds successfully - ✅ iOS builds successfully 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
257 lines
9.2 KiB
Kotlin
257 lines
9.2 KiB
Kotlin
package com.example.mycrib.cache
|
|
|
|
import com.example.mycrib.models.*
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
import kotlin.time.Clock
|
|
import kotlin.time.ExperimentalTime
|
|
|
|
//import kotlinx.datetime.Clock
|
|
//import kotlinx.datetime.Instant
|
|
|
|
/**
|
|
* Centralized data cache for the application.
|
|
* This singleton holds all frequently accessed data in memory to avoid redundant API calls.
|
|
*/
|
|
object DataCache {
|
|
|
|
// User & Authentication
|
|
private val _currentUser = MutableStateFlow<User?>(null)
|
|
val currentUser: StateFlow<User?> = _currentUser.asStateFlow()
|
|
|
|
// Residences
|
|
private val _residences = MutableStateFlow<List<Residence>>(emptyList())
|
|
val residences: StateFlow<List<Residence>> = _residences.asStateFlow()
|
|
|
|
private val _myResidences = MutableStateFlow<MyResidencesResponse?>(null)
|
|
val myResidences: StateFlow<MyResidencesResponse?> = _myResidences.asStateFlow()
|
|
|
|
private val _residenceSummaries = MutableStateFlow<Map<Int, ResidenceSummaryResponse>>(emptyMap())
|
|
val residenceSummaries: StateFlow<Map<Int, ResidenceSummaryResponse>> = _residenceSummaries.asStateFlow()
|
|
|
|
// Tasks
|
|
private val _allTasks = MutableStateFlow<TaskColumnsResponse?>(null)
|
|
val allTasks: StateFlow<TaskColumnsResponse?> = _allTasks.asStateFlow()
|
|
|
|
private val _tasksByResidence = MutableStateFlow<Map<Int, TaskColumnsResponse>>(emptyMap())
|
|
val tasksByResidence: StateFlow<Map<Int, TaskColumnsResponse>> = _tasksByResidence.asStateFlow()
|
|
|
|
// Documents
|
|
private val _documents = MutableStateFlow<List<Document>>(emptyList())
|
|
val documents: StateFlow<List<Document>> = _documents.asStateFlow()
|
|
|
|
private val _documentsByResidence = MutableStateFlow<Map<Int, List<Document>>>(emptyMap())
|
|
val documentsByResidence: StateFlow<Map<Int, List<Document>>> = _documentsByResidence.asStateFlow()
|
|
|
|
// Contractors
|
|
private val _contractors = MutableStateFlow<List<Contractor>>(emptyList())
|
|
val contractors: StateFlow<List<Contractor>> = _contractors.asStateFlow()
|
|
|
|
// Lookups/Reference Data
|
|
private val _residenceTypes = MutableStateFlow<List<ResidenceType>>(emptyList())
|
|
val residenceTypes: StateFlow<List<ResidenceType>> = _residenceTypes.asStateFlow()
|
|
|
|
private val _taskFrequencies = MutableStateFlow<List<TaskFrequency>>(emptyList())
|
|
val taskFrequencies: StateFlow<List<TaskFrequency>> = _taskFrequencies.asStateFlow()
|
|
|
|
private val _taskPriorities = MutableStateFlow<List<TaskPriority>>(emptyList())
|
|
val taskPriorities: StateFlow<List<TaskPriority>> = _taskPriorities.asStateFlow()
|
|
|
|
private val _taskStatuses = MutableStateFlow<List<TaskStatus>>(emptyList())
|
|
val taskStatuses: StateFlow<List<TaskStatus>> = _taskStatuses.asStateFlow()
|
|
|
|
private val _taskCategories = MutableStateFlow<List<TaskCategory>>(emptyList())
|
|
val taskCategories: StateFlow<List<TaskCategory>> = _taskCategories.asStateFlow()
|
|
|
|
private val _contractorSpecialties = MutableStateFlow<List<ContractorSpecialty>>(emptyList())
|
|
val contractorSpecialties: StateFlow<List<ContractorSpecialty>> = _contractorSpecialties.asStateFlow()
|
|
|
|
private val _lookupsInitialized = MutableStateFlow(false)
|
|
val lookupsInitialized: StateFlow<Boolean> = _lookupsInitialized.asStateFlow()
|
|
|
|
// Cache metadata
|
|
private val _lastRefreshTime = MutableStateFlow<Long>(0L)
|
|
val lastRefreshTime: StateFlow<Long> = _lastRefreshTime.asStateFlow()
|
|
|
|
private val _isCacheInitialized = MutableStateFlow(false)
|
|
val isCacheInitialized: StateFlow<Boolean> = _isCacheInitialized.asStateFlow()
|
|
|
|
// Update methods
|
|
fun updateCurrentUser(user: User?) {
|
|
_currentUser.value = user
|
|
}
|
|
|
|
fun updateResidences(residences: List<Residence>) {
|
|
_residences.value = residences
|
|
updateLastRefreshTime()
|
|
}
|
|
|
|
fun updateMyResidences(myResidences: MyResidencesResponse) {
|
|
_myResidences.value = myResidences
|
|
updateLastRefreshTime()
|
|
}
|
|
|
|
fun updateResidenceSummary(residenceId: Int, summary: ResidenceSummaryResponse) {
|
|
_residenceSummaries.value = _residenceSummaries.value + (residenceId to summary)
|
|
}
|
|
|
|
fun updateAllTasks(tasks: TaskColumnsResponse) {
|
|
_allTasks.value = tasks
|
|
updateLastRefreshTime()
|
|
}
|
|
|
|
fun updateTasksByResidence(residenceId: Int, tasks: TaskColumnsResponse) {
|
|
_tasksByResidence.value = _tasksByResidence.value + (residenceId to tasks)
|
|
}
|
|
|
|
fun updateDocuments(documents: List<Document>) {
|
|
_documents.value = documents
|
|
updateLastRefreshTime()
|
|
}
|
|
|
|
fun updateDocumentsByResidence(residenceId: Int, documents: List<Document>) {
|
|
_documentsByResidence.value = _documentsByResidence.value + (residenceId to documents)
|
|
}
|
|
|
|
fun updateContractors(contractors: List<Contractor>) {
|
|
_contractors.value = contractors
|
|
updateLastRefreshTime()
|
|
}
|
|
|
|
// Lookup update methods removed - lookups are handled by LookupsViewModel
|
|
|
|
fun setCacheInitialized(initialized: Boolean) {
|
|
_isCacheInitialized.value = initialized
|
|
}
|
|
|
|
@OptIn(ExperimentalTime::class)
|
|
private fun updateLastRefreshTime() {
|
|
_lastRefreshTime.value = Clock.System.now().toEpochMilliseconds()
|
|
}
|
|
|
|
// Helper methods to add/update/remove individual items
|
|
fun addResidence(residence: Residence) {
|
|
_residences.value = _residences.value + residence
|
|
}
|
|
|
|
fun updateResidence(residence: Residence) {
|
|
_residences.value = _residences.value.map {
|
|
if (it.id == residence.id) residence else it
|
|
}
|
|
}
|
|
|
|
fun removeResidence(residenceId: Int) {
|
|
_residences.value = _residences.value.filter { it.id != residenceId }
|
|
// Also clear related caches
|
|
_tasksByResidence.value = _tasksByResidence.value - residenceId
|
|
_documentsByResidence.value = _documentsByResidence.value - residenceId
|
|
_residenceSummaries.value = _residenceSummaries.value - residenceId
|
|
}
|
|
|
|
fun addDocument(document: Document) {
|
|
_documents.value = _documents.value + document
|
|
}
|
|
|
|
fun updateDocument(document: Document) {
|
|
_documents.value = _documents.value.map {
|
|
if (it.id == document.id) document else it
|
|
}
|
|
}
|
|
|
|
fun removeDocument(documentId: Int) {
|
|
_documents.value = _documents.value.filter { it.id != documentId }
|
|
}
|
|
|
|
fun addContractor(contractor: Contractor) {
|
|
_contractors.value = _contractors.value + contractor
|
|
}
|
|
|
|
fun updateContractor(contractor: Contractor) {
|
|
_contractors.value = _contractors.value.map {
|
|
if (it.id == contractor.id) contractor else it
|
|
}
|
|
}
|
|
|
|
fun removeContractor(contractorId: Int) {
|
|
_contractors.value = _contractors.value.filter { it.id != contractorId }
|
|
}
|
|
|
|
// Lookup update methods
|
|
fun updateResidenceTypes(types: List<ResidenceType>) {
|
|
_residenceTypes.value = types
|
|
}
|
|
|
|
fun updateTaskFrequencies(frequencies: List<TaskFrequency>) {
|
|
_taskFrequencies.value = frequencies
|
|
}
|
|
|
|
fun updateTaskPriorities(priorities: List<TaskPriority>) {
|
|
_taskPriorities.value = priorities
|
|
}
|
|
|
|
fun updateTaskStatuses(statuses: List<TaskStatus>) {
|
|
_taskStatuses.value = statuses
|
|
}
|
|
|
|
fun updateTaskCategories(categories: List<TaskCategory>) {
|
|
_taskCategories.value = categories
|
|
}
|
|
|
|
fun updateContractorSpecialties(specialties: List<ContractorSpecialty>) {
|
|
_contractorSpecialties.value = specialties
|
|
}
|
|
|
|
fun updateAllLookups(staticData: StaticDataResponse) {
|
|
_residenceTypes.value = staticData.residenceTypes
|
|
_taskFrequencies.value = staticData.taskFrequencies
|
|
_taskPriorities.value = staticData.taskPriorities
|
|
_taskStatuses.value = staticData.taskStatuses
|
|
_taskCategories.value = staticData.taskCategories
|
|
_contractorSpecialties.value = staticData.contractorSpecialties
|
|
}
|
|
|
|
fun markLookupsInitialized() {
|
|
_lookupsInitialized.value = true
|
|
}
|
|
|
|
// Clear methods
|
|
fun clearAll() {
|
|
_currentUser.value = null
|
|
_residences.value = emptyList()
|
|
_myResidences.value = null
|
|
_residenceSummaries.value = emptyMap()
|
|
_allTasks.value = null
|
|
_tasksByResidence.value = emptyMap()
|
|
_documents.value = emptyList()
|
|
_documentsByResidence.value = emptyMap()
|
|
_contractors.value = emptyList()
|
|
clearLookups()
|
|
_lastRefreshTime.value = 0L
|
|
_isCacheInitialized.value = false
|
|
}
|
|
|
|
fun clearLookups() {
|
|
_residenceTypes.value = emptyList()
|
|
_taskFrequencies.value = emptyList()
|
|
_taskPriorities.value = emptyList()
|
|
_taskStatuses.value = emptyList()
|
|
_taskCategories.value = emptyList()
|
|
_contractorSpecialties.value = emptyList()
|
|
_lookupsInitialized.value = false
|
|
}
|
|
|
|
fun clearUserData() {
|
|
_currentUser.value = null
|
|
_residences.value = emptyList()
|
|
_myResidences.value = null
|
|
_residenceSummaries.value = emptyMap()
|
|
_allTasks.value = null
|
|
_tasksByResidence.value = emptyMap()
|
|
_documents.value = emptyList()
|
|
_documentsByResidence.value = emptyMap()
|
|
_contractors.value = emptyList()
|
|
_isCacheInitialized.value = false
|
|
}
|
|
}
|