Rebrand from MyCrib to Casera

- Rename Kotlin package from com.example.mycrib to com.example.casera
- Update Android app name, namespace, and application ID
- Update iOS bundle identifiers and project settings
- Rename iOS directories (MyCribTests -> CaseraTests, etc.)
- Update deep link schemes from mycrib:// to casera://
- Update app group identifiers
- Update subscription product IDs
- Update all UI strings and branding

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-11-28 21:10:38 -06:00
parent 8dbc816a33
commit c6eef720ed
215 changed files with 767 additions and 767 deletions

View File

@@ -0,0 +1,175 @@
package com.example.casera.repository
import com.example.casera.cache.SubscriptionCache
import com.example.casera.models.*
import com.example.casera.network.ApiResult
import com.example.casera.network.LookupsApi
import com.example.casera.network.SubscriptionApi
import com.example.casera.storage.TokenStorage
import com.example.casera.storage.TaskCacheStorage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
/**
* Singleton repository for managing lookup data across the entire app.
* Fetches data once on initialization and caches it for the app session.
*/
object LookupsRepository {
private val lookupsApi = LookupsApi()
private val subscriptionApi = SubscriptionApi()
private val scope = CoroutineScope(Dispatchers.Default)
private val _residenceTypes = MutableStateFlow<List<ResidenceType>>(emptyList())
val residenceTypes: StateFlow<List<ResidenceType>> = _residenceTypes
private val _taskFrequencies = MutableStateFlow<List<TaskFrequency>>(emptyList())
val taskFrequencies: StateFlow<List<TaskFrequency>> = _taskFrequencies
private val _taskPriorities = MutableStateFlow<List<TaskPriority>>(emptyList())
val taskPriorities: StateFlow<List<TaskPriority>> = _taskPriorities
private val _taskStatuses = MutableStateFlow<List<TaskStatus>>(emptyList())
val taskStatuses: StateFlow<List<TaskStatus>> = _taskStatuses
private val _taskCategories = MutableStateFlow<List<TaskCategory>>(emptyList())
val taskCategories: StateFlow<List<TaskCategory>> = _taskCategories
private val _contractorSpecialties = MutableStateFlow<List<ContractorSpecialty>>(emptyList())
val contractorSpecialties: StateFlow<List<ContractorSpecialty>> = _contractorSpecialties
private val _allTasks = MutableStateFlow<List<CustomTask>>(emptyList())
val allTasks: StateFlow<List<CustomTask>> = _allTasks
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading
private val _isInitialized = MutableStateFlow(false)
val isInitialized: StateFlow<Boolean> = _isInitialized
/**
* Load all lookups from the API.
* This should be called once when the user logs in.
*/
fun initialize() {
// Only initialize once per app session
if (_isInitialized.value) {
return
}
scope.launch {
_isLoading.value = true
// Load cached tasks from disk immediately for offline access
val cachedTasks = TaskCacheStorage.getTasks()
if (cachedTasks != null) {
_allTasks.value = cachedTasks
println("Loaded ${cachedTasks.size} tasks from cache")
}
val token = TokenStorage.getToken()
if (token != null) {
// Load all static data in a single API call
launch {
when (val result = lookupsApi.getStaticData(token)) {
is ApiResult.Success -> {
_residenceTypes.value = result.data.residenceTypes
_taskFrequencies.value = result.data.taskFrequencies
_taskPriorities.value = result.data.taskPriorities
_taskStatuses.value = result.data.taskStatuses
_taskCategories.value = result.data.taskCategories
_contractorSpecialties.value = result.data.contractorSpecialties
println("Loaded all static data successfully")
}
else -> {
println("Failed to fetch static data")
}
}
}
launch {
when (val result = lookupsApi.getAllTasks(token)) {
is ApiResult.Success -> {
_allTasks.value = result.data
// Save to disk cache for offline access
TaskCacheStorage.saveTasks(result.data)
println("Fetched and cached ${result.data.size} tasks from API")
}
else -> {
println("Failed to fetch tasks from API, using cached data if available")
}
}
}
// Load subscription status for limitation checks
launch {
println("🔄 [LookupsRepository] Fetching subscription status...")
when (val result = subscriptionApi.getSubscriptionStatus(token)) {
is ApiResult.Success -> {
println("✅ [LookupsRepository] Subscription status loaded: limitationsEnabled=${result.data.limitationsEnabled}")
println(" Limits: ${result.data.limits}")
SubscriptionCache.updateSubscriptionStatus(result.data)
}
is ApiResult.Error -> {
println("❌ [LookupsRepository] Failed to fetch subscription status: ${result.message}")
}
else -> {
println("❌ [LookupsRepository] Unexpected subscription result")
}
}
}
// Load upgrade triggers for subscription prompts
launch {
println("🔄 [LookupsRepository] Fetching upgrade triggers...")
when (val result = subscriptionApi.getUpgradeTriggers(token)) {
is ApiResult.Success -> {
println("✅ [LookupsRepository] Upgrade triggers loaded: ${result.data.size} triggers")
SubscriptionCache.updateUpgradeTriggers(result.data)
}
is ApiResult.Error -> {
println("❌ [LookupsRepository] Failed to fetch upgrade triggers: ${result.message}")
}
else -> {
println("❌ [LookupsRepository] Unexpected upgrade triggers result")
}
}
}
}
_isInitialized.value = true
_isLoading.value = false
}
}
/**
* Clear all cached data.
* This should be called when the user logs out.
*/
fun clear() {
_residenceTypes.value = emptyList()
_taskFrequencies.value = emptyList()
_taskPriorities.value = emptyList()
_taskStatuses.value = emptyList()
_taskCategories.value = emptyList()
_contractorSpecialties.value = emptyList()
_allTasks.value = emptyList()
// Clear disk cache on logout
TaskCacheStorage.clearTasks()
// Clear subscription cache on logout
SubscriptionCache.clear()
_isInitialized.value = false
_isLoading.value = false
}
/**
* Force refresh all lookups from the API.
*/
fun refresh() {
_isInitialized.value = false
initialize()
}
}