P1: Shared FixtureDataManager (empty + populated) for cross-platform snapshots
InMemoryDataManager + Fixtures with deterministic data (fixed clock 2026-04-15,
2 residences, 8 tasks, 3 contractors, 5 documents). FixtureDataManager.empty()
and .populated() factories. Exposed to Swift via SKIE.
Expanded IDataManager surface (5 -> 22 members) so fixtures cover every
StateFlow and lookup helper screens read: myResidences, allTasks,
tasksByResidence, documents, documentsByResidence, contractors, residenceTypes,
taskFrequencies, taskPriorities, taskCategories, contractorSpecialties,
taskTemplates, taskTemplatesGrouped, residenceSummaries, upgradeTriggers,
promotions, plus get{ResidenceType,TaskFrequency,TaskPriority,TaskCategory,
ContractorSpecialty}(id) lookup helpers. DataManager implementation is a pure
override-keyword addition — no behavior change.
Enables P2 (Android gallery) + P3 (iOS gallery) to render real screens against
identical inputs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -125,35 +125,35 @@ object DataManager : IDataManager {
|
||||
override val residences: StateFlow<List<Residence>> = _residences.asStateFlow()
|
||||
|
||||
private val _myResidences = MutableStateFlow<MyResidencesResponse?>(null)
|
||||
val myResidences: StateFlow<MyResidencesResponse?> = _myResidences.asStateFlow()
|
||||
override val myResidences: StateFlow<MyResidencesResponse?> = _myResidences.asStateFlow()
|
||||
|
||||
private val _totalSummary = MutableStateFlow<TotalSummary?>(null)
|
||||
override val totalSummary: StateFlow<TotalSummary?> = _totalSummary.asStateFlow()
|
||||
|
||||
private val _residenceSummaries = MutableStateFlow<Map<Int, ResidenceSummaryResponse>>(emptyMap())
|
||||
val residenceSummaries: StateFlow<Map<Int, ResidenceSummaryResponse>> = _residenceSummaries.asStateFlow()
|
||||
override val residenceSummaries: StateFlow<Map<Int, ResidenceSummaryResponse>> = _residenceSummaries.asStateFlow()
|
||||
|
||||
// ==================== TASKS ====================
|
||||
|
||||
private val _allTasks = MutableStateFlow<TaskColumnsResponse?>(null)
|
||||
val allTasks: StateFlow<TaskColumnsResponse?> = _allTasks.asStateFlow()
|
||||
override val allTasks: StateFlow<TaskColumnsResponse?> = _allTasks.asStateFlow()
|
||||
|
||||
private val _tasksByResidence = MutableStateFlow<Map<Int, TaskColumnsResponse>>(emptyMap())
|
||||
val tasksByResidence: StateFlow<Map<Int, TaskColumnsResponse>> = _tasksByResidence.asStateFlow()
|
||||
override val tasksByResidence: StateFlow<Map<Int, TaskColumnsResponse>> = _tasksByResidence.asStateFlow()
|
||||
|
||||
// ==================== DOCUMENTS ====================
|
||||
|
||||
private val _documents = MutableStateFlow<List<Document>>(emptyList())
|
||||
val documents: StateFlow<List<Document>> = _documents.asStateFlow()
|
||||
override 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()
|
||||
override val documentsByResidence: StateFlow<Map<Int, List<Document>>> = _documentsByResidence.asStateFlow()
|
||||
|
||||
// ==================== CONTRACTORS ====================
|
||||
// Stores ContractorSummary for list views (lighter weight than full Contractor)
|
||||
|
||||
private val _contractors = MutableStateFlow<List<ContractorSummary>>(emptyList())
|
||||
val contractors: StateFlow<List<ContractorSummary>> = _contractors.asStateFlow()
|
||||
override val contractors: StateFlow<List<ContractorSummary>> = _contractors.asStateFlow()
|
||||
|
||||
// ==================== SUBSCRIPTION ====================
|
||||
|
||||
@@ -161,39 +161,39 @@ object DataManager : IDataManager {
|
||||
override val subscription: StateFlow<SubscriptionStatus?> = _subscription.asStateFlow()
|
||||
|
||||
private val _upgradeTriggers = MutableStateFlow<Map<String, UpgradeTriggerData>>(emptyMap())
|
||||
val upgradeTriggers: StateFlow<Map<String, UpgradeTriggerData>> = _upgradeTriggers.asStateFlow()
|
||||
override val upgradeTriggers: StateFlow<Map<String, UpgradeTriggerData>> = _upgradeTriggers.asStateFlow()
|
||||
|
||||
private val _featureBenefits = MutableStateFlow<List<FeatureBenefit>>(emptyList())
|
||||
override val featureBenefits: StateFlow<List<FeatureBenefit>> = _featureBenefits.asStateFlow()
|
||||
|
||||
private val _promotions = MutableStateFlow<List<Promotion>>(emptyList())
|
||||
val promotions: StateFlow<List<Promotion>> = _promotions.asStateFlow()
|
||||
override val promotions: StateFlow<List<Promotion>> = _promotions.asStateFlow()
|
||||
|
||||
// ==================== LOOKUPS (Reference Data) ====================
|
||||
|
||||
// List-based for dropdowns/pickers
|
||||
private val _residenceTypes = MutableStateFlow<List<ResidenceType>>(emptyList())
|
||||
val residenceTypes: StateFlow<List<ResidenceType>> = _residenceTypes.asStateFlow()
|
||||
override val residenceTypes: StateFlow<List<ResidenceType>> = _residenceTypes.asStateFlow()
|
||||
|
||||
private val _taskFrequencies = MutableStateFlow<List<TaskFrequency>>(emptyList())
|
||||
val taskFrequencies: StateFlow<List<TaskFrequency>> = _taskFrequencies.asStateFlow()
|
||||
override val taskFrequencies: StateFlow<List<TaskFrequency>> = _taskFrequencies.asStateFlow()
|
||||
|
||||
private val _taskPriorities = MutableStateFlow<List<TaskPriority>>(emptyList())
|
||||
val taskPriorities: StateFlow<List<TaskPriority>> = _taskPriorities.asStateFlow()
|
||||
override val taskPriorities: StateFlow<List<TaskPriority>> = _taskPriorities.asStateFlow()
|
||||
|
||||
private val _taskCategories = MutableStateFlow<List<TaskCategory>>(emptyList())
|
||||
val taskCategories: StateFlow<List<TaskCategory>> = _taskCategories.asStateFlow()
|
||||
override val taskCategories: StateFlow<List<TaskCategory>> = _taskCategories.asStateFlow()
|
||||
|
||||
private val _contractorSpecialties = MutableStateFlow<List<ContractorSpecialty>>(emptyList())
|
||||
val contractorSpecialties: StateFlow<List<ContractorSpecialty>> = _contractorSpecialties.asStateFlow()
|
||||
override val contractorSpecialties: StateFlow<List<ContractorSpecialty>> = _contractorSpecialties.asStateFlow()
|
||||
|
||||
// ==================== TASK TEMPLATES ====================
|
||||
|
||||
private val _taskTemplates = MutableStateFlow<List<TaskTemplate>>(emptyList())
|
||||
val taskTemplates: StateFlow<List<TaskTemplate>> = _taskTemplates.asStateFlow()
|
||||
override val taskTemplates: StateFlow<List<TaskTemplate>> = _taskTemplates.asStateFlow()
|
||||
|
||||
private val _taskTemplatesGrouped = MutableStateFlow<TaskTemplatesGroupedResponse?>(null)
|
||||
val taskTemplatesGrouped: StateFlow<TaskTemplatesGroupedResponse?> = _taskTemplatesGrouped.asStateFlow()
|
||||
override val taskTemplatesGrouped: StateFlow<TaskTemplatesGroupedResponse?> = _taskTemplatesGrouped.asStateFlow()
|
||||
|
||||
// Map-based for O(1) ID resolution
|
||||
private val _residenceTypesMap = MutableStateFlow<Map<Int, ResidenceType>>(emptyMap())
|
||||
@@ -261,11 +261,11 @@ object DataManager : IDataManager {
|
||||
|
||||
// ==================== O(1) LOOKUP HELPERS ====================
|
||||
|
||||
fun getResidenceType(id: Int?): ResidenceType? = id?.let { _residenceTypesMap.value[it] }
|
||||
fun getTaskFrequency(id: Int?): TaskFrequency? = id?.let { _taskFrequenciesMap.value[it] }
|
||||
fun getTaskPriority(id: Int?): TaskPriority? = id?.let { _taskPrioritiesMap.value[it] }
|
||||
fun getTaskCategory(id: Int?): TaskCategory? = id?.let { _taskCategoriesMap.value[it] }
|
||||
fun getContractorSpecialty(id: Int?): ContractorSpecialty? = id?.let { _contractorSpecialtiesMap.value[it] }
|
||||
override fun getResidenceType(id: Int?): ResidenceType? = id?.let { _residenceTypesMap.value[it] }
|
||||
override fun getTaskFrequency(id: Int?): TaskFrequency? = id?.let { _taskFrequenciesMap.value[it] }
|
||||
override fun getTaskPriority(id: Int?): TaskPriority? = id?.let { _taskPrioritiesMap.value[it] }
|
||||
override fun getTaskCategory(id: Int?): TaskCategory? = id?.let { _taskCategoriesMap.value[it] }
|
||||
override fun getContractorSpecialty(id: Int?): ContractorSpecialty? = id?.let { _contractorSpecialtiesMap.value[it] }
|
||||
|
||||
// ==================== AUTH UPDATE METHODS ====================
|
||||
|
||||
|
||||
@@ -1,37 +1,110 @@
|
||||
package com.tt.honeyDue.data
|
||||
|
||||
import com.tt.honeyDue.models.ContractorSpecialty
|
||||
import com.tt.honeyDue.models.ContractorSummary
|
||||
import com.tt.honeyDue.models.Document
|
||||
import com.tt.honeyDue.models.FeatureBenefit
|
||||
import com.tt.honeyDue.models.MyResidencesResponse
|
||||
import com.tt.honeyDue.models.Promotion
|
||||
import com.tt.honeyDue.models.Residence
|
||||
import com.tt.honeyDue.models.ResidenceSummaryResponse
|
||||
import com.tt.honeyDue.models.ResidenceType
|
||||
import com.tt.honeyDue.models.SubscriptionStatus
|
||||
import com.tt.honeyDue.models.TaskCategory
|
||||
import com.tt.honeyDue.models.TaskColumnsResponse
|
||||
import com.tt.honeyDue.models.TaskFrequency
|
||||
import com.tt.honeyDue.models.TaskPriority
|
||||
import com.tt.honeyDue.models.TaskTemplate
|
||||
import com.tt.honeyDue.models.TaskTemplatesGroupedResponse
|
||||
import com.tt.honeyDue.models.TotalSummary
|
||||
import com.tt.honeyDue.models.UpgradeTriggerData
|
||||
import com.tt.honeyDue.models.User
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Minimal contract covering the [DataManager] surface consumed by Compose screens.
|
||||
* Contract covering the [DataManager] surface consumed by Compose screens
|
||||
* and the parity-gallery fixture factories.
|
||||
*
|
||||
* This interface exists solely so screens can depend on an abstraction that tests,
|
||||
* previews, and the parity-gallery can substitute via [LocalDataManager]. It is
|
||||
* deliberately narrow — only members referenced from the ui/screens package tree
|
||||
* are included.
|
||||
* This interface exists so screens can depend on an abstraction that tests,
|
||||
* previews, and the parity-gallery can substitute via [LocalDataManager].
|
||||
* The member set intentionally mirrors every StateFlow and lookup helper a
|
||||
* screen may read — [com.tt.honeyDue.testing.FixtureDataManager] produces
|
||||
* fully-populated fakes so snapshot renders have the data every surface
|
||||
* expects without reaching into the production singleton.
|
||||
*
|
||||
* ViewModels, [com.tt.honeyDue.network.APILayer], and [PersistenceManager] continue
|
||||
* to use the concrete [DataManager] singleton directly; widening this interface to
|
||||
* cover their surface is explicitly out of scope for the ambient refactor.
|
||||
* ViewModels, [com.tt.honeyDue.network.APILayer], and [PersistenceManager]
|
||||
* continue to use the concrete [DataManager] singleton directly; they are
|
||||
* not covered by this interface.
|
||||
*/
|
||||
interface IDataManager {
|
||||
|
||||
// ==================== AUTH ====================
|
||||
|
||||
/** Observed by [com.tt.honeyDue.ui.screens.ProfileScreen], [com.tt.honeyDue.ui.screens.ResidenceDetailScreen], [com.tt.honeyDue.ui.screens.ResidenceFormScreen]. */
|
||||
val currentUser: StateFlow<User?>
|
||||
|
||||
// ==================== RESIDENCES ====================
|
||||
|
||||
/** Observed by [com.tt.honeyDue.ui.screens.ContractorDetailScreen] and the onboarding first-task screen. */
|
||||
val residences: StateFlow<List<Residence>>
|
||||
|
||||
/** Full my-residences API response (may include metadata beyond the list itself). */
|
||||
val myResidences: StateFlow<MyResidencesResponse?>
|
||||
|
||||
/** Observed by [com.tt.honeyDue.ui.screens.HomeScreen] and [com.tt.honeyDue.ui.screens.ResidencesScreen]. */
|
||||
val totalSummary: StateFlow<TotalSummary?>
|
||||
|
||||
/** Per-residence summary cache (keyed by residence id). */
|
||||
val residenceSummaries: StateFlow<Map<Int, ResidenceSummaryResponse>>
|
||||
|
||||
// ==================== TASKS ====================
|
||||
|
||||
/** Kanban board covering all tasks across all residences. */
|
||||
val allTasks: StateFlow<TaskColumnsResponse?>
|
||||
|
||||
/** Kanban board cache keyed by residence id. */
|
||||
val tasksByResidence: StateFlow<Map<Int, TaskColumnsResponse>>
|
||||
|
||||
// ==================== DOCUMENTS ====================
|
||||
|
||||
val documents: StateFlow<List<Document>>
|
||||
|
||||
val documentsByResidence: StateFlow<Map<Int, List<Document>>>
|
||||
|
||||
// ==================== CONTRACTORS ====================
|
||||
|
||||
val contractors: StateFlow<List<ContractorSummary>>
|
||||
|
||||
// ==================== SUBSCRIPTION ====================
|
||||
|
||||
/** Observed by [com.tt.honeyDue.ui.screens.ProfileScreen]. */
|
||||
val subscription: StateFlow<SubscriptionStatus?>
|
||||
|
||||
val upgradeTriggers: StateFlow<Map<String, UpgradeTriggerData>>
|
||||
|
||||
/** Observed by [com.tt.honeyDue.ui.screens.subscription.FeatureComparisonScreen]. */
|
||||
val featureBenefits: StateFlow<List<FeatureBenefit>>
|
||||
|
||||
/** Observed by [com.tt.honeyDue.ui.screens.ProfileScreen]. */
|
||||
val subscription: StateFlow<SubscriptionStatus?>
|
||||
val promotions: StateFlow<List<Promotion>>
|
||||
|
||||
// ==================== LOOKUPS ====================
|
||||
|
||||
val residenceTypes: StateFlow<List<ResidenceType>>
|
||||
val taskFrequencies: StateFlow<List<TaskFrequency>>
|
||||
val taskPriorities: StateFlow<List<TaskPriority>>
|
||||
val taskCategories: StateFlow<List<TaskCategory>>
|
||||
val contractorSpecialties: StateFlow<List<ContractorSpecialty>>
|
||||
|
||||
// ==================== TASK TEMPLATES ====================
|
||||
|
||||
val taskTemplates: StateFlow<List<TaskTemplate>>
|
||||
val taskTemplatesGrouped: StateFlow<TaskTemplatesGroupedResponse?>
|
||||
|
||||
// ==================== O(1) LOOKUP HELPERS ====================
|
||||
|
||||
fun getResidenceType(id: Int?): ResidenceType?
|
||||
fun getTaskFrequency(id: Int?): TaskFrequency?
|
||||
fun getTaskPriority(id: Int?): TaskPriority?
|
||||
fun getTaskCategory(id: Int?): TaskCategory?
|
||||
fun getContractorSpecialty(id: Int?): ContractorSpecialty?
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user