diff --git a/composeApp/src/androidMain/kotlin/com/tt/honeyDue/platform/ImagePicker.android.kt b/composeApp/src/androidMain/kotlin/com/tt/honeyDue/platform/ImagePicker.android.kt index f5143af..5dad462 100644 --- a/composeApp/src/androidMain/kotlin/com/tt/honeyDue/platform/ImagePicker.android.kt +++ b/composeApp/src/androidMain/kotlin/com/tt/honeyDue/platform/ImagePicker.android.kt @@ -8,6 +8,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode import androidx.core.content.FileProvider import java.io.File @@ -58,6 +59,15 @@ actual fun rememberImagePicker( actual fun rememberCameraPicker( onImageCaptured: (ImageData) -> Unit ): () -> Unit { + // Compose previews and Roborazzi snapshot tests run without a + // `FileProvider` resolvable cache path — `getUriForFile` throws + // `Failed to find configured root...` because the test cache dir + // isn't registered in the manifest's `file_paths.xml`. The launch + // callback is never invoked in a preview/snapshot anyway, so + // returning a no-op keeps the composition clean. + if (LocalInspectionMode.current) { + return {} + } val context = LocalContext.current // Create a temp file URI for the camera to save to diff --git a/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/GalleryManifestParityTest.kt b/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/GalleryManifestParityTest.kt new file mode 100644 index 0000000..5031023 --- /dev/null +++ b/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/GalleryManifestParityTest.kt @@ -0,0 +1,68 @@ +package com.tt.honeyDue.screenshot + +import com.tt.honeyDue.testing.GalleryScreens +import com.tt.honeyDue.testing.Platform +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +/** + * Parity gate — asserts [gallerySurfaces] is exactly the set of screens + * declared in [GalleryScreens] with [Platform.ANDROID] in their platforms. + * + * If this fails, either: + * - A new screen was added to [gallerySurfaces] but missing from the + * canonical manifest — update [GalleryScreens.all]. + * - A new screen was added to the manifest but not wired into + * [gallerySurfaces] — add the corresponding `GallerySurface(...)` + * entry. + * - A rename landed on only one side — reconcile. + * + * This keeps Android and iOS from silently drifting apart in coverage. + * The iOS equivalent (`GalleryManifestParityTest.swift`) enforces the + * same invariant on the Swift test file. + */ +class GalleryManifestParityTest { + + @Test + fun android_surfaces_match_manifest_exactly() { + val actual = gallerySurfaces.map { it.name }.toSet() + val expected = GalleryScreens.forAndroid.keys + + val missing = expected - actual + val extra = actual - expected + + if (missing.isNotEmpty() || extra.isNotEmpty()) { + val message = buildString { + appendLine("Android GallerySurfaces drifted from canonical manifest.") + if (missing.isNotEmpty()) { + appendLine() + appendLine("Screens in manifest but missing from GallerySurfaces.kt:") + missing.sorted().forEach { appendLine(" - $it") } + } + if (extra.isNotEmpty()) { + appendLine() + appendLine("Screens in GallerySurfaces.kt but missing from manifest:") + extra.sorted().forEach { appendLine(" - $it") } + } + appendLine() + appendLine("Reconcile by editing com.tt.honeyDue.testing.GalleryScreens and/or") + appendLine("com.tt.honeyDue.screenshot.GallerySurfaces so both agree.") + } + kotlin.test.fail(message) + } + assertEquals(expected, actual) + } + + @Test + fun no_duplicate_surface_names() { + val duplicates = gallerySurfaces.map { it.name } + .groupingBy { it } + .eachCount() + .filterValues { it > 1 } + assertTrue( + duplicates.isEmpty(), + "Duplicate surface names in GallerySurfaces.kt: $duplicates", + ) + } +} diff --git a/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/GallerySurfaces.kt b/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/GallerySurfaces.kt index 6bfdaff..f2bb95a 100644 --- a/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/GallerySurfaces.kt +++ b/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/GallerySurfaces.kt @@ -2,6 +2,7 @@ package com.tt.honeyDue.screenshot import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import com.tt.honeyDue.testing.Fixtures import com.tt.honeyDue.ui.screens.AddDocumentScreen import com.tt.honeyDue.ui.screens.AddResidenceScreen @@ -25,11 +26,10 @@ import com.tt.honeyDue.ui.screens.RegisterScreen import com.tt.honeyDue.ui.screens.ResetPasswordScreen import com.tt.honeyDue.ui.screens.ResidenceDetailScreen import com.tt.honeyDue.ui.screens.ResidencesScreen -import com.tt.honeyDue.ui.screens.TasksScreen import com.tt.honeyDue.ui.screens.VerifyEmailScreen import com.tt.honeyDue.ui.screens.VerifyResetCodeScreen -import com.tt.honeyDue.ui.screens.dev.AnimationTestingScreen import com.tt.honeyDue.ui.screens.onboarding.OnboardingCreateAccountContent +import com.tt.honeyDue.ui.screens.onboarding.OnboardingFirstTaskContent import com.tt.honeyDue.ui.screens.onboarding.OnboardingHomeProfileContent import com.tt.honeyDue.ui.screens.onboarding.OnboardingJoinResidenceContent import com.tt.honeyDue.ui.screens.onboarding.OnboardingLocationContent @@ -40,34 +40,44 @@ import com.tt.honeyDue.ui.screens.onboarding.OnboardingVerifyEmailContent import com.tt.honeyDue.ui.screens.onboarding.OnboardingWelcomeContent import com.tt.honeyDue.ui.screens.residence.JoinResidenceScreen import com.tt.honeyDue.ui.screens.subscription.FeatureComparisonScreen +import com.tt.honeyDue.ui.screens.task.AddTaskWithResidenceScreen import com.tt.honeyDue.ui.screens.task.TaskSuggestionsScreen import com.tt.honeyDue.ui.screens.task.TaskTemplatesBrowserScreen import com.tt.honeyDue.ui.screens.theme.ThemeSelectionScreen +import com.tt.honeyDue.viewmodel.ContractorViewModel +import com.tt.honeyDue.viewmodel.DocumentViewModel import com.tt.honeyDue.viewmodel.OnboardingViewModel import com.tt.honeyDue.viewmodel.PasswordResetViewModel /** - * Declarative manifest of every primary screen in the app that the parity - * gallery captures. Each entry renders the production composable directly — - * the screen reads its data from [com.tt.honeyDue.data.LocalDataManager], - * which the capture driver overrides with a [com.tt.honeyDue.testing.FixtureDataManager] - * (empty or populated) per variant. + * Declarative manifest of every Android gallery surface. Must stay in sync + * with the canonical [com.tt.honeyDue.testing.GalleryScreens] manifest — + * [GalleryManifestParityTest] fails CI if the two drift. * * Scope: the screens users land on. We deliberately skip: * - dialogs that live inside a host screen (already captured on the host), * - animation sub-views / decorative components in AnimationTesting/, * - widget views (Android Glance / iOS WidgetKit — separate surface), - * - shared helper composables listed under `category: shared` in - * docs/ios-parity/screens.json (loaders, error rows, thumbnails — they + * - shared helper composables (loaders, error rows, thumbnails — they * only appear as part of a parent screen). * - * Screens that require a construction-time ViewModel (`OnboardingViewModel`, - * `PasswordResetViewModel`) instantiate it inline here. The production code - * paths start the viewmodel's own `launch { APILayer.xxx() }` on first - * composition — those calls fail fast in the hermetic Robolectric - * environment, but the composition itself renders the surface from the - * injected [com.tt.honeyDue.data.LocalDataManager] before any network - * result arrives, which is exactly what we want to compare against iOS. + * Detail-VM pattern (contractor_detail, document_detail, edit_document): + * the VM is created with the fixture id already pre-selected, so + * `stateIn(SharingStarted.Eagerly, initialValue = dataManager.x[id])` + * emits `Success(entity)` on first composition. Without this pre-select, + * the screens' own `LaunchedEffect(id) { vm.loadX(id) }` dispatches the id + * assignment to a coroutine that runs *after* Roborazzi captures the + * frame — so both empty and populated captures would render the `Idle` + * state and be byte-identical. + * + * Screens that require a construction-time ViewModel + * ([OnboardingViewModel], [PasswordResetViewModel]) instantiate it inline + * here. The production code paths start the viewmodel's own + * `launch { APILayer.xxx() }` on first composition — those calls fail fast + * in the hermetic Robolectric environment, but the composition itself + * renders the surface from the injected + * [com.tt.honeyDue.data.LocalDataManager] before any network result + * arrives, which is exactly what we want to compare against iOS. */ data class GallerySurface( /** Snake-case identifier; used as the golden file-name prefix. */ @@ -177,6 +187,12 @@ val gallerySurfaces: List = listOf( onJoined = {}, ) }, + GallerySurface("onboarding_first_task") { + OnboardingFirstTaskContent( + viewModel = OnboardingViewModel(), + onTasksAdded = {}, + ) + }, GallerySurface("onboarding_subscription") { OnboardingSubscriptionContent( onSubscribe = {}, @@ -184,7 +200,7 @@ val gallerySurfaces: List = listOf( ) }, - // ---------- Home / main navigation ---------- + // ---------- Home (Android-only dashboard) ---------- GallerySurface("home") { HomeScreen( onNavigateToResidences = {}, @@ -240,12 +256,16 @@ val gallerySurfaces: List = listOf( }, // ---------- Tasks ---------- - GallerySurface("tasks") { - TasksScreen(onNavigateBack = {}) - }, GallerySurface("all_tasks") { AllTasksScreen(onNavigateToEditTask = {}) }, + GallerySurface("add_task_with_residence") { + AddTaskWithResidenceScreen( + residenceId = Fixtures.primaryHome.id, + onNavigateBack = {}, + onCreated = {}, + ) + }, GallerySurface("edit_task") { EditTaskScreen( task = Fixtures.tasks.first(), @@ -285,9 +305,20 @@ val gallerySurfaces: List = listOf( ) }, GallerySurface("contractor_detail") { + val id = Fixtures.contractors.first().id + // Pass `initialSelectedContractorId` at VM construction so the + // synchronous `stateIn` initial-value closure observes both the + // id AND the fixture-seeded `dataManager.contractorDetail[id]`, + // emitting `Success(contractor)` on first composition. Without + // this the screen's own `LaunchedEffect(id) { vm.loadContractorDetail(id) }` + // dispatches the id assignment to a coroutine that runs after + // the frame is captured, leaving both empty and populated + // captures byte-identical on the `Idle` branch. + val vm = remember { ContractorViewModel(initialSelectedContractorId = id) } ContractorDetailScreen( - contractorId = Fixtures.contractors.first().id, + contractorId = id, onNavigateBack = {}, + viewModel = vm, ) }, @@ -299,10 +330,13 @@ val gallerySurfaces: List = listOf( ) }, GallerySurface("document_detail") { + val id = Fixtures.documents.first().id ?: 0 + val vm = remember { DocumentViewModel(initialSelectedDocumentId = id) } DocumentDetailScreen( - documentId = Fixtures.documents.first().id ?: 0, + documentId = id, onNavigateBack = {}, - onNavigateToEdit = {}, + onNavigateToEdit = { _ -> }, + documentViewModel = vm, ) }, GallerySurface("add_document") { @@ -313,9 +347,12 @@ val gallerySurfaces: List = listOf( ) }, GallerySurface("edit_document") { + val id = Fixtures.documents.first().id ?: 0 + val vm = remember { DocumentViewModel(initialSelectedDocumentId = id) } EditDocumentScreen( - documentId = Fixtures.documents.first().id ?: 0, + documentId = id, onNavigateBack = {}, + documentViewModel = vm, ) }, @@ -326,14 +363,11 @@ val gallerySurfaces: List = listOf( onLogout = {}, ) }, - GallerySurface("theme_selection") { - ThemeSelectionScreen(onNavigateBack = {}) - }, GallerySurface("notification_preferences") { NotificationPreferencesScreen(onNavigateBack = {}) }, - GallerySurface("animation_testing") { - AnimationTestingScreen(onNavigateBack = {}) + GallerySurface("theme_selection") { + ThemeSelectionScreen(onNavigateBack = {}) }, GallerySurface("biometric_lock") { BiometricLockScreen(onUnlocked = {}) diff --git a/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/ScreenshotTests.kt b/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/ScreenshotTests.kt index e2a6ad6..1711dea 100644 --- a/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/ScreenshotTests.kt +++ b/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/screenshot/ScreenshotTests.kt @@ -6,54 +6,60 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalInspectionMode import androidx.test.core.app.ApplicationProvider import com.github.takahirom.roborazzi.captureRoboImage import com.tt.honeyDue.data.IDataManager import com.tt.honeyDue.data.LocalDataManager import com.tt.honeyDue.testing.FixtureDataManager +import com.tt.honeyDue.testing.GalleryCategory +import com.tt.honeyDue.testing.GalleryScreens import com.tt.honeyDue.ui.theme.AppThemes import com.tt.honeyDue.ui.theme.HoneyDueTheme import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.robolectric.ParameterizedRobolectricTestRunner +import org.robolectric.Shadows.shadowOf import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode /** - * Parity-gallery Roborazzi snapshot tests (P2). + * Parity-gallery Roborazzi snapshot tests. * - * For every entry in [gallerySurfaces] we capture four variants: - * empty × light, empty × dark, populated × light, populated × dark + * Variant matrix (driven by [GalleryCategory] in the canonical + * [GalleryScreens] manifest): * - * Per surface that's 4 PNGs × ~40 surfaces ≈ 160 goldens. Paired with the - * iOS swift-snapshot-testing gallery (P3) that captures the same set of - * (screen, data, theme) tuples, any visual divergence between the two - * platforms surfaces here as a golden diff rather than silently shipping. + * DataCarrying surfaces — capture 4 variants: + * surface_empty_light.png (empty fixture, no lookups, light) + * surface_empty_dark.png (empty fixture, no lookups, dark) + * surface_populated_light.png (populated fixture, light) + * surface_populated_dark.png (populated fixture, dark) * - * How this differs from the showcase tests that lived here before: - * - Showcases rendered hand-crafted theme-agnostic surfaces; now we - * render the actual production composables (`LoginScreen(…)`, etc.) - * through the fixture-backed [LocalDataManager]. - * - Surfaces are declared in [GallerySurfaces.kt] instead of being - * inlined, so adding a new screen is a one-line change. - * - Previously 6 surfaces × 3 themes × 2 modes; now the matrix is - * N surfaces × {empty, populated} × {light, dark} — themes beyond - * the default are intentionally out of scope (theme variation is - * covered by the dedicated theme_selection surface). + * DataFree surfaces — capture 2 variants: + * surface_light.png (empty fixture, lookups seeded, light) + * surface_dark.png (empty fixture, lookups seeded, dark) * - * One parameterized test per surface gives granular CI failures — the + * The `empty` fixture for DataCarrying variants passes + * `seedLookups = false` so form dropdowns render their empty state + * (yielding a visible populated-vs-empty diff for forms that read + * lookups from `DataManager`). The `empty` fixture for DataFree + * variants passes `seedLookups = true` because those screens expect + * realistic production lookups even when the user has no entities yet. + * + * DataFree surfaces omit the populated variant entirely — the screens + * render no entity data, so `populated` would be byte-identical to + * `empty` and add zero signal. + * + * Granular CI failures: one parameterized test per surface means the * report shows `ScreenshotTests[login]`, `ScreenshotTests[tasks]`, etc. * rather than one monolithic failure when any surface drifts. * * Why the goldens land directly under `src/androidUnitTest/roborazzi/`: * Roborazzi resolves `captureRoboImage(filePath = …)` relative to the * Gradle test task's working directory (the module root). Writing to - * the same directory where goldens are committed means record and verify - * round-trip through one canonical location; we never have to copy - * between a transient `build/outputs/roborazzi/` and the committed - * fixture directory (which was the source of the pre-existing - * "original file was not found" failure). + * the same directory where goldens are committed means record and + * verify round-trip through one canonical location. */ @RunWith(ParameterizedRobolectricTestRunner::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) @@ -64,24 +70,15 @@ class ScreenshotTests( /** * Compose Multiplatform's `stringResource()` loads text via a - * JVM-static context held by `AndroidContextProvider`. In a real APK - * that ContentProvider is registered in the manifest and populated at - * app start; under Robolectric unit tests it never runs, so every - * `stringResource(...)` call throws "Android context is not - * initialized." - * - * `PreviewContextConfigurationEffect()` is the documented fix — but - * it only fires inside `LocalInspectionMode = true`, and even then - * the first composition frame renders before the effect lands, so - * `stringResource()` calls race the context set. + * JVM-static context held by `AndroidContextProvider`. Under + * Robolectric unit tests the `ContentProvider` that normally + * populates it never runs, so every `stringResource(...)` call throws + * "Android context is not initialized." * * Install the context eagerly via reflection before each test. - * `AndroidContextProvider` is `internal` in Kotlin, so we can't - * touch its class directly — but its static slot is writable - * through the generated `Companion.setANDROID_CONTEXT` accessor. - * `@Before` runs inside the Robolectric sandbox (where - * `ApplicationProvider` is valid); `@BeforeClass` would run outside - * it and fail with "No instrumentation registered!". + * `AndroidContextProvider` is `internal`, but its static slot is + * writable through the generated `Companion.setANDROID_CONTEXT` + * accessor. */ @Before fun bootstrapComposeResources() { @@ -95,36 +92,44 @@ class ScreenshotTests( @Test fun captureAllVariants() { - Variant.all().forEach { variant -> - val fileName = "${surface.name}_${variant.state}_${variant.mode}.png" + val screen = GalleryScreens.forAndroid[surface.name] + ?: error( + "Surface '${surface.name}' is in GallerySurfaces.kt but not in " + + "GalleryScreens.all (canonical manifest). " + + "GalleryManifestParityTest should have caught this.", + ) + + val variants = when (screen.category) { + GalleryCategory.DataCarrying -> Variant.dataCarrying + GalleryCategory.DataFree -> Variant.dataFree + } + + variants.forEach { variant -> + val fileName = "${surface.name}${variant.fileSuffix}.png" val fixture = variant.dataManager() - // Seed the global DataManager singleton from the fixture. Many - // helpers (SubscriptionHelper, screen ViewModels that read - // DataManager directly, plus the screens' APILayer-triggered - // fallbacks) bypass LocalDataManager and read the singleton. By - // seeding here, all three data paths converge on the fixture - // data so empty/populated tests produce genuinely different - // renders — not just the ones that happen to use LocalDataManager. - val dm = com.tt.honeyDue.data.DataManager - dm.setSubscription(fixture.subscription.value) - dm.setCurrentUser(fixture.currentUser.value) - fixture.myResidences.value?.let { dm.setMyResidences(it) } - dm.setResidences(fixture.residences.value) - fixture.totalSummary.value?.let { dm.setTotalSummary(it) } - fixture.allTasks.value?.let { dm.setAllTasks(it) } - dm.setDocuments(fixture.documents.value) - dm.setContractors(fixture.contractors.value) - dm.setFeatureBenefits(fixture.featureBenefits.value) - dm.setUpgradeTriggers(fixture.upgradeTriggers.value) - dm.setTaskCategories(fixture.taskCategories.value) - dm.setTaskPriorities(fixture.taskPriorities.value) - dm.setTaskFrequencies(fixture.taskFrequencies.value) + seedSingleton(fixture) + // Flush the main-thread Looper so any `stateIn(... Eagerly)` + // collectors on VMs reused across captures have processed the + // DataManager update before we snapshot. Without this, VMs + // might see the previous variant's data because coroutine + // emissions race the capture call. + shadowOf(android.os.Looper.getMainLooper()).idle() captureRoboImage(filePath = "src/androidUnitTest/roborazzi/$fileName") { HoneyDueTheme( themeColors = AppThemes.Default, darkTheme = variant.darkTheme, ) { - CompositionLocalProvider(LocalDataManager provides fixture) { + // `LocalInspectionMode = true` signals to production + // composables that they're rendering in a hermetic + // preview/test environment. Camera pickers, gated push + // registrations, and animation callbacks use this flag + // to short-circuit calls that require real Android + // subsystems (e.g. `FileProvider` paths that aren't + // resolvable under Robolectric's test data dir). + CompositionLocalProvider( + LocalDataManager provides fixture, + LocalInspectionMode provides true, + ) { Box(Modifier.fillMaxSize()) { surface.content() } @@ -136,6 +141,45 @@ class ScreenshotTests( com.tt.honeyDue.data.DataManager.setSubscription(null) } + /** + * Mirror every StateFlow on `fixture` onto the `DataManager` singleton + * so code paths that bypass `LocalDataManager` (screens that call + * `DataManager.x` directly, VMs whose default-arg resolves to the + * singleton, `SubscriptionHelper` free-tier gate) see the same data. + * + * Critical: clear the singleton first so the previous variant's + * writes don't leak into this variant's `empty` render. + */ + private fun seedSingleton(fixture: IDataManager) { + val dm = com.tt.honeyDue.data.DataManager + dm.clear() + dm.setSubscription(fixture.subscription.value) + dm.setCurrentUser(fixture.currentUser.value) + fixture.myResidences.value?.let { dm.setMyResidences(it) } + dm.setResidences(fixture.residences.value) + fixture.totalSummary.value?.let { dm.setTotalSummary(it) } + fixture.allTasks.value?.let { dm.setAllTasks(it) } + dm.setDocuments(fixture.documents.value) + dm.setContractors(fixture.contractors.value) + dm.setFeatureBenefits(fixture.featureBenefits.value) + dm.setUpgradeTriggers(fixture.upgradeTriggers.value) + dm.setTaskCategories(fixture.taskCategories.value) + dm.setTaskPriorities(fixture.taskPriorities.value) + dm.setTaskFrequencies(fixture.taskFrequencies.value) + fixture.contractorsByResidence.value.forEach { (rid, list) -> + dm.setContractorsForResidence(rid, list) + } + fixture.contractorDetail.value.values.forEach { dm.setContractorDetail(it) } + fixture.documentDetail.value.values.forEach { dm.setDocumentDetail(it) } + fixture.taskCompletions.value.forEach { (taskId, completions) -> + dm.setTaskCompletions(taskId, completions) + } + fixture.tasksByResidence.value.forEach { (rid, cols) -> + dm.setTasksForResidence(rid, cols) + } + fixture.notificationPreferences.value?.let { dm.setNotificationPreferences(it) } + } + companion object { @JvmStatic @ParameterizedRobolectricTestRunner.Parameters(name = "{0}") @@ -145,23 +189,48 @@ class ScreenshotTests( } /** - * One of the four render-variants captured per surface. The - * `dataManager` factory is invoked lazily so each capture gets its own - * pristine fixture (avoiding cross-test StateFlow mutation). + * One render-variant captured per surface. The `dataManager` factory is + * invoked lazily so each capture gets a pristine fixture (avoiding + * cross-test StateFlow mutation). + * + * @property fileSuffix Appended to the surface name to form the PNG + * filename. Includes a leading `_`. Examples: `_empty_light`, + * `_populated_dark`, `_light`, `_dark`. */ private data class Variant( - val state: String, - val mode: String, + val fileSuffix: String, val darkTheme: Boolean, val dataManager: () -> IDataManager, ) { companion object { - fun all(): List = listOf( - Variant("empty", "light", darkTheme = false) { FixtureDataManager.empty() }, - Variant("empty", "dark", darkTheme = true) { FixtureDataManager.empty() }, - Variant("populated", "light", darkTheme = false) { FixtureDataManager.populated() }, - Variant("populated", "dark", darkTheme = true) { FixtureDataManager.populated() }, + /** + * DataCarrying surfaces: 4 variants. `empty` captures pass + * `seedLookups = false` so form dropdowns render empty in the + * empty-variant PNGs — letting screens that read lookups produce + * a visible diff against the populated variant. + */ + val dataCarrying: List = listOf( + Variant("_empty_light", darkTheme = false) { + FixtureDataManager.empty(seedLookups = false) + }, + Variant("_empty_dark", darkTheme = true) { + FixtureDataManager.empty(seedLookups = false) + }, + Variant("_populated_light", darkTheme = false) { FixtureDataManager.populated() }, + Variant("_populated_dark", darkTheme = true) { FixtureDataManager.populated() }, + ) + + /** + * DataFree surfaces: 2 variants (light/dark only). Lookups are + * seeded because forms expect them to be present in production + * (a user with zero entities still sees the priority picker). + * The populated variant is deliberately omitted — DataFree + * surfaces render no entity data, so `populated` would be + * byte-identical to `empty`. + */ + val dataFree: List = listOf( + Variant("_light", darkTheme = false) { FixtureDataManager.empty(seedLookups = true) }, + Variant("_dark", darkTheme = true) { FixtureDataManager.empty(seedLookups = true) }, ) } } - diff --git a/composeApp/src/androidUnitTest/roborazzi/add_document_dark.png b/composeApp/src/androidUnitTest/roborazzi/add_document_dark.png new file mode 100644 index 0000000..0d43a55 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/add_document_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_document_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/add_document_empty_dark.png deleted file mode 100644 index 8263d72..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/add_document_empty_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_document_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/add_document_empty_light.png deleted file mode 100644 index 884205a..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/add_document_empty_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_document_light.png b/composeApp/src/androidUnitTest/roborazzi/add_document_light.png new file mode 100644 index 0000000..6a10a42 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/add_document_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_document_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/add_document_populated_dark.png deleted file mode 100644 index 8263d72..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/add_document_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_document_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/add_document_populated_light.png deleted file mode 100644 index 884205a..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/add_document_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_residence_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/add_residence_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/add_residence_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/add_residence_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/add_residence_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/add_residence_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/add_residence_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/add_residence_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/add_residence_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/add_residence_populated_dark.png deleted file mode 100644 index 4054ddc..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/add_residence_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_residence_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/add_residence_populated_light.png deleted file mode 100644 index 94cc19a..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/add_residence_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_dark.png b/composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_dark.png new file mode 100644 index 0000000..06fbaa8 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_light.png b/composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_light.png new file mode 100644 index 0000000..920bfff Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_dark.png index b37138a..f21021b 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_light.png index 39339d6..f7ae738 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_light.png and b/composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_dark.png index b37138a..55d5bb6 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_dark.png and b/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_light.png index e21ddf1..0088857 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_light.png and b/composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_dark.png deleted file mode 100644 index 15c4e71..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_light.png deleted file mode 100644 index 5d048ac..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_dark.png deleted file mode 100644 index 15c4e71..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_light.png deleted file mode 100644 index 5d048ac..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/biometric_lock_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/biometric_lock_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/biometric_lock_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/biometric_lock_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/biometric_lock_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/biometric_lock_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/biometric_lock_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/biometric_lock_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_dark.png deleted file mode 100644 index cc67f43..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_light.png deleted file mode 100644 index b06c5f1..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/complete_task_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/complete_task_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/complete_task_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/complete_task_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/complete_task_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/complete_task_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/complete_task_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/complete_task_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/complete_task_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/complete_task_populated_dark.png deleted file mode 100644 index 2cbaab3..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/complete_task_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/complete_task_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/complete_task_populated_light.png deleted file mode 100644 index 626fe45..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/complete_task_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_dark.png index b66067c..9147eeb 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_light.png index 7565e8d..20f36b7 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_light.png and b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_dark.png index b66067c..a56718a 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_dark.png and b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_light.png index 907ce8b..b663d09 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_light.png and b/composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractors_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/contractors_empty_dark.png index 9d8f964..e825adb 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractors_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/contractors_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractors_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/contractors_empty_light.png index 701d04a..011f6e1 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractors_empty_light.png and b/composeApp/src/androidUnitTest/roborazzi/contractors_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractors_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/contractors_populated_dark.png index 9d8f964..909b914 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractors_populated_dark.png and b/composeApp/src/androidUnitTest/roborazzi/contractors_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/contractors_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/contractors_populated_light.png index 61eb47a..7bc93f4 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/contractors_populated_light.png and b/composeApp/src/androidUnitTest/roborazzi/contractors_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_dark.png index 997472d..b6f98d5 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_light.png index f9ffae1..31a7cb7 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_light.png and b/composeApp/src/androidUnitTest/roborazzi/document_detail_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_dark.png index 997472d..5221dd1 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_dark.png and b/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_light.png index 30e401b..b279053 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_light.png and b/composeApp/src/androidUnitTest/roborazzi/document_detail_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_document_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_document_dark.png new file mode 100644 index 0000000..bc9475c Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/edit_document_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_document_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_document_empty_dark.png deleted file mode 100644 index 36df8ce..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_document_empty_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_document_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_document_empty_light.png deleted file mode 100644 index f3f908c..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_document_empty_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_document_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_document_light.png new file mode 100644 index 0000000..2a50d84 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/edit_document_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_document_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_document_populated_dark.png deleted file mode 100644 index 36df8ce..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_document_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_document_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_document_populated_light.png deleted file mode 100644 index f3f908c..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_document_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_residence_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_residence_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/edit_residence_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/edit_residence_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_residence_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_residence_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/edit_residence_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/edit_residence_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_dark.png deleted file mode 100644 index 39bc114..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_light.png deleted file mode 100644 index 2d37f21..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_task_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_task_dark.png new file mode 100644 index 0000000..161c15a Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/edit_task_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_task_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_task_empty_dark.png deleted file mode 100644 index 9ee7027..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_task_empty_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_task_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_task_empty_light.png deleted file mode 100644 index dfb3224..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_task_empty_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_task_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_task_light.png new file mode 100644 index 0000000..aa9bf90 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/edit_task_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_task_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/edit_task_populated_dark.png deleted file mode 100644 index 9ee7027..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_task_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/edit_task_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/edit_task_populated_light.png deleted file mode 100644 index dfb3224..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/edit_task_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/feature_comparison_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/feature_comparison_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/feature_comparison_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/feature_comparison_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/feature_comparison_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/feature_comparison_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/feature_comparison_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/feature_comparison_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_dark.png deleted file mode 100644 index 35d72c0..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_light.png deleted file mode 100644 index bd7b912..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/forgot_password_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/forgot_password_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/forgot_password_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/forgot_password_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/forgot_password_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/forgot_password_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/forgot_password_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/forgot_password_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_dark.png deleted file mode 100644 index 283b5c6..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_light.png deleted file mode 100644 index 81b7b4a..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/home_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/home_empty_dark.png index cbfbb2c..d2b6637 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/home_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/home_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/home_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/home_empty_light.png index e89ce9b..f9c6432 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/home_empty_light.png and b/composeApp/src/androidUnitTest/roborazzi/home_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/join_residence_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/join_residence_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/join_residence_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/join_residence_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/join_residence_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/join_residence_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/join_residence_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/join_residence_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/join_residence_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/join_residence_populated_dark.png deleted file mode 100644 index 1f09a94..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/join_residence_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/join_residence_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/join_residence_populated_light.png deleted file mode 100644 index c35a830..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/join_residence_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/login_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/login_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/login_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/login_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/login_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/login_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/login_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/login_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/login_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/login_populated_dark.png deleted file mode 100644 index 3d23e54..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/login_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/login_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/login_populated_light.png deleted file mode 100644 index 8d334f8..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/login_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/manage_users_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/manage_users_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/manage_users_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/manage_users_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/manage_users_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/manage_users_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/manage_users_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/manage_users_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/manage_users_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/manage_users_populated_dark.png deleted file mode 100644 index fe8808c..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/manage_users_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/manage_users_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/manage_users_populated_light.png deleted file mode 100644 index dfc5155..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/manage_users_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/notification_preferences_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/notification_preferences_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/notification_preferences_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/notification_preferences_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/notification_preferences_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/notification_preferences_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/notification_preferences_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/notification_preferences_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_dark.png deleted file mode 100644 index a6ae19f..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_light.png deleted file mode 100644 index 73a8dfd..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_dark.png deleted file mode 100644 index deb65a6..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_light.png deleted file mode 100644 index 4e02e77..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_dark.png new file mode 100644 index 0000000..8e7149d Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_light.png new file mode 100644 index 0000000..d8e2c78 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_dark.png new file mode 100644 index 0000000..e400332 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_light.png new file mode 100644 index 0000000..a4fc8d7 Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_dark.png deleted file mode 100644 index dce1927..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_light.png deleted file mode 100644 index 9544812..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_dark.png deleted file mode 100644 index aeb9c55..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_light.png deleted file mode 100644 index 3fcea4a..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_location_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_location_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_location_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_location_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_location_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_location_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_location_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_location_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_dark.png deleted file mode 100644 index c6cf0f6..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_light.png deleted file mode 100644 index 4590f22..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_dark.png deleted file mode 100644 index e054fb7..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_light.png deleted file mode 100644 index 11d47ce..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_dark.png new file mode 100644 index 0000000..9cf1d4f Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_dark.png deleted file mode 100644 index ecb45d3..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_light.png deleted file mode 100644 index 1712439..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_light.png new file mode 100644 index 0000000..a067adc Binary files /dev/null and b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_dark.png deleted file mode 100644 index ecb45d3..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_light.png deleted file mode 100644 index 459c94a..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_dark.png deleted file mode 100644 index 3497957..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_light.png deleted file mode 100644 index f29937e..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_dark.png deleted file mode 100644 index 094bf4d..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_light.png deleted file mode 100644 index 2993f98..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_dark.png deleted file mode 100644 index b30e69b..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_light.png deleted file mode 100644 index dec569e..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/profile_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/profile_populated_dark.png index 3075ec6..d77927f 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/profile_populated_dark.png and b/composeApp/src/androidUnitTest/roborazzi/profile_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/profile_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/profile_populated_light.png index 895d773..33af015 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/profile_populated_light.png and b/composeApp/src/androidUnitTest/roborazzi/profile_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/register_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/register_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/register_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/register_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/register_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/register_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/register_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/register_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/register_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/register_populated_dark.png deleted file mode 100644 index e374285..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/register_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/register_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/register_populated_light.png deleted file mode 100644 index 1db9fd4..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/register_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/reset_password_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/reset_password_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/reset_password_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/reset_password_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/reset_password_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/reset_password_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/reset_password_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/reset_password_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/reset_password_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/reset_password_populated_dark.png deleted file mode 100644 index 21fc612..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/reset_password_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/reset_password_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/reset_password_populated_light.png deleted file mode 100644 index c08918b..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/reset_password_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_dark.png index 9acadc1..79d5bbc 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_light.png index 5b1fce5..6b277af 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_light.png and b/composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/residences_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/residences_empty_dark.png index 240c4d0..c089832 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/residences_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/residences_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/residences_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/residences_empty_light.png index fb23bc1..8c1c424 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/residences_empty_light.png and b/composeApp/src/androidUnitTest/roborazzi/residences_empty_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/residences_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/residences_populated_dark.png index b19ec2b..eb09736 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/residences_populated_dark.png and b/composeApp/src/androidUnitTest/roborazzi/residences_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/residences_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/residences_populated_light.png index c29cd95..bfbae59 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/residences_populated_light.png and b/composeApp/src/androidUnitTest/roborazzi/residences_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/task_suggestions_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/task_suggestions_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/task_suggestions_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/task_suggestions_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/task_suggestions_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/task_suggestions_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/task_suggestions_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/task_suggestions_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_dark.png deleted file mode 100644 index 6f8bb14..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_light.png deleted file mode 100644 index 5b1c7de..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_dark.png index f2db3fb..f3c6f47 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_dark.png and b/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_dark.png index 303cb99..f3c6f47 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_dark.png and b/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_dark.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_light.png index c287ad3..0626302 100644 Binary files a/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_light.png and b/composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_light.png differ diff --git a/composeApp/src/androidUnitTest/roborazzi/tasks_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/tasks_empty_dark.png deleted file mode 100644 index 4cac08b..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/tasks_empty_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/tasks_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/tasks_empty_light.png deleted file mode 100644 index 4909bb7..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/tasks_empty_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/tasks_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/tasks_populated_dark.png deleted file mode 100644 index 9d6e389..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/tasks_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/tasks_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/tasks_populated_light.png deleted file mode 100644 index 4909bb7..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/tasks_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/theme_selection_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/theme_selection_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/theme_selection_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/theme_selection_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/theme_selection_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/theme_selection_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/theme_selection_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/theme_selection_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_dark.png deleted file mode 100644 index 4bb2b38..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_light.png deleted file mode 100644 index 2e75add..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_email_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/verify_email_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/verify_email_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/verify_email_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_email_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/verify_email_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/verify_email_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/verify_email_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_email_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/verify_email_populated_dark.png deleted file mode 100644 index aa36f8f..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/verify_email_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_email_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/verify_email_populated_light.png deleted file mode 100644 index 8b89b3e..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/verify_email_populated_light.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_empty_dark.png b/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_dark.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/verify_reset_code_empty_dark.png rename to composeApp/src/androidUnitTest/roborazzi/verify_reset_code_dark.png diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_empty_light.png b/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_light.png similarity index 100% rename from composeApp/src/androidUnitTest/roborazzi/verify_reset_code_empty_light.png rename to composeApp/src/androidUnitTest/roborazzi/verify_reset_code_light.png diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_dark.png b/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_dark.png deleted file mode 100644 index 096bcfb..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_dark.png and /dev/null differ diff --git a/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_light.png b/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_light.png deleted file mode 100644 index a0a907e..0000000 Binary files a/composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_light.png and /dev/null differ diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/data/DataManager.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/data/DataManager.kt index 98cc3c1..988028b 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/data/DataManager.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/data/DataManager.kt @@ -823,7 +823,12 @@ object DataManager : IDataManager { _tasksByResidence.value = emptyMap() _documents.value = emptyList() _documentsByResidence.value = emptyMap() + _documentDetail.value = emptyMap() _contractors.value = emptyList() + _contractorsByResidence.value = emptyMap() + _contractorDetail.value = emptyMap() + _taskCompletions.value = emptyMap() + _notificationPreferences.value = null // Clear subscription _subscription.value = null diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/testing/FixtureDataManager.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/testing/FixtureDataManager.kt index 714ce53..fce30a7 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/testing/FixtureDataManager.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/testing/FixtureDataManager.kt @@ -28,12 +28,20 @@ object FixtureDataManager { /** * Data-free fixture — represents a freshly-signed-in user with no - * residences, no tasks, no contractors, no documents. Lookups - * (priorities, categories, frequencies) are still populated because - * empty-state form pickers render them even before the user has any - * entities of their own. + * residences, no tasks, no contractors, no documents. + * + * @param seedLookups When `true` (the default), lookups (priorities, + * categories, frequencies, residence types, contractor specialties, + * task templates) are populated. This matches product behaviour — + * a user with zero residences still sees the priority picker in + * every form. + * + * When `false`, lookups are empty too. Use this for snapshot tests + * that want the `empty` variant of a form to render empty dropdowns + * (so populated vs. empty PNGs diff for form screens). The parity + * gallery's empty variant passes `seedLookups = false`. */ - fun empty(): IDataManager = InMemoryDataManager( + fun empty(seedLookups: Boolean = true): IDataManager = InMemoryDataManager( currentUser = null, residences = emptyList(), myResidencesResponse = null, @@ -48,13 +56,13 @@ object FixtureDataManager { upgradeTriggers = emptyMap(), featureBenefits = Fixtures.featureBenefits, promotions = emptyList(), - residenceTypes = Fixtures.residenceTypes, - taskFrequencies = Fixtures.taskFrequencies, - taskPriorities = Fixtures.taskPriorities, - taskCategories = Fixtures.taskCategories, - contractorSpecialties = Fixtures.contractorSpecialties, - taskTemplates = Fixtures.taskTemplates, - taskTemplatesGrouped = Fixtures.taskTemplatesGrouped, + residenceTypes = if (seedLookups) Fixtures.residenceTypes else emptyList(), + taskFrequencies = if (seedLookups) Fixtures.taskFrequencies else emptyList(), + taskPriorities = if (seedLookups) Fixtures.taskPriorities else emptyList(), + taskCategories = if (seedLookups) Fixtures.taskCategories else emptyList(), + contractorSpecialties = if (seedLookups) Fixtures.contractorSpecialties else emptyList(), + taskTemplates = if (seedLookups) Fixtures.taskTemplates else emptyList(), + taskTemplatesGrouped = if (seedLookups) Fixtures.taskTemplatesGrouped else null, ) /** diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/testing/GalleryManifest.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/testing/GalleryManifest.kt new file mode 100644 index 0000000..7b36fcd --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/testing/GalleryManifest.kt @@ -0,0 +1,177 @@ +package com.tt.honeyDue.testing + +/** + * Canonical list of every user-reachable screen in the HoneyDue app, used + * as the single source of truth for the iOS↔Android parity-gallery + * snapshot tests. + * + * Both platforms' snapshot harnesses are CI-gated against this manifest: + * - Android: `GalleryManifestParityTest` fails if the entries in + * `GallerySurfaces.kt` don't match the subset of screens with + * [Platform.ANDROID] in [platforms]. + * - iOS: `GalleryManifestParityTest.swift` performs the equivalent check + * against `SnapshotGalleryTests.swift`. + * + * This prevents the two platforms from silently drifting apart in + * coverage — adding a screen to one side without updating this manifest + * (and therefore the other side) fails CI. + * + * When a screen is reachable on only one platform (e.g. [GalleryScreens.home] + * on Android, [GalleryScreens.documentsWarranties] on iOS), mark it with + * the relevant [Platform] set. The gallery HTML renders a visible + * `[missing — ]` placeholder for the absent side so the gap is + * obvious rather than silently omitted. + */ + +/** Category of a gallery screen — drives the capture-variant matrix. */ +enum class GalleryCategory { + /** + * Screen renders data from [com.tt.honeyDue.data.IDataManager] (lists, + * detail views, dashboards). Captures 4 variants: empty+populated x + * light+dark — so the test proves the fixture actually reaches the UI. + */ + DataCarrying, + + /** + * Screen is a pure form, auth view, static onboarding step, or chrome + * with no backing entity data. Captures 2 variants: light+dark only. + * Skipping the populated variant prevents ~50 byte-identical-to-empty + * goldens that add no signal. + */ + DataFree, +} + +/** Platforms that include a given screen in their parity-gallery harness. */ +enum class Platform { ANDROID, IOS } + +/** + * One canonical screen in the parity manifest. + * + * @property name Snake-case identifier; doubles as the golden-PNG filename + * prefix on both platforms. + * @property category Drives the capture-variant matrix (see [GalleryCategory]). + * @property platforms Platforms that capture this screen. Screens captured + * on both have a paired row in the gallery; screens on only one show a + * `[missing]` placeholder for the absent platform. + */ +data class GalleryScreen( + val name: String, + val category: GalleryCategory, + val platforms: Set, +) + +/** + * Canonical manifest — 43 screens, ordered by product flow. + * + * Breakdown: + * - 12 [GalleryCategory.DataCarrying] screens — 4 captures each. + * - 31 [GalleryCategory.DataFree] screens — 2 captures each. + * - 37 screens captured on both platforms. + * - 3 Android-only: `home`, `documents`, `biometric_lock`. + * - 3 iOS-only: `documents_warranties`, `add_task`, `profile_edit`. + */ +object GalleryScreens { + + private val both = setOf(Platform.ANDROID, Platform.IOS) + private val androidOnly = setOf(Platform.ANDROID) + private val iosOnly = setOf(Platform.IOS) + + val all: List = listOf( + // ---------- Auth ---------- + GalleryScreen("login", GalleryCategory.DataFree, both), + GalleryScreen("register", GalleryCategory.DataFree, both), + GalleryScreen("forgot_password", GalleryCategory.DataFree, both), + GalleryScreen("verify_reset_code", GalleryCategory.DataFree, both), + GalleryScreen("reset_password", GalleryCategory.DataFree, both), + GalleryScreen("verify_email", GalleryCategory.DataFree, both), + + // ---------- Onboarding ---------- + GalleryScreen("onboarding_welcome", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_value_props", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_create_account", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_verify_email", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_location", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_name_residence", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_home_profile", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_join_residence", GalleryCategory.DataFree, both), + GalleryScreen("onboarding_first_task", GalleryCategory.DataCarrying, both), + GalleryScreen("onboarding_subscription", GalleryCategory.DataFree, both), + + // ---------- Home / dashboard (Android-only) ---------- + GalleryScreen("home", GalleryCategory.DataCarrying, androidOnly), + + // ---------- Residences ---------- + GalleryScreen("residences", GalleryCategory.DataCarrying, both), + GalleryScreen("residence_detail", GalleryCategory.DataCarrying, both), + GalleryScreen("add_residence", GalleryCategory.DataFree, both), + GalleryScreen("edit_residence", GalleryCategory.DataFree, both), + GalleryScreen("join_residence", GalleryCategory.DataFree, both), + // `manage_users` is DataFree: both platforms render a loading / + // error state on first paint because residence-users data is + // fetched via APILayer directly (no fixture seam). Populating + // it would require a new `usersByResidence` field on + // `IDataManager` plus fixture+screen wiring — deferred as a + // production improvement rather than a snapshot-test-only + // shim. + GalleryScreen("manage_users", GalleryCategory.DataFree, both), + + // ---------- Tasks ---------- + GalleryScreen("all_tasks", GalleryCategory.DataCarrying, both), + // `add_task` is iOS-only: iOS presents an "Add task" sheet from a + // residence-scoped context. Android adds tasks via an inline dialog + // inside `residence_detail`, with no standalone destination. + GalleryScreen("add_task", GalleryCategory.DataFree, iosOnly), + GalleryScreen("add_task_with_residence", GalleryCategory.DataFree, both), + GalleryScreen("edit_task", GalleryCategory.DataFree, both), + // `complete_task` is DataFree: the task and residence-name are + // passed as static props, completion form fields default-render + // the same regardless of fixture state, and the contractor + // picker is collapsed on first paint. Nothing visible diffs + // between empty and populated. + GalleryScreen("complete_task", GalleryCategory.DataFree, both), + // `task_suggestions` is DataFree in snapshot terms: the visible + // first-paint state is driven by an `APILayer.getTaskSuggestions` + // call (which fails hermetically), not by anything on + // `IDataManager`. The populated templates stored on DM are only + // surfaced after the API resolves, so both variants render the + // same loading/error frame. Treating as DataFree is honest. + GalleryScreen("task_suggestions", GalleryCategory.DataFree, both), + GalleryScreen("task_templates_browser", GalleryCategory.DataCarrying, both), + + // ---------- Contractors ---------- + GalleryScreen("contractors", GalleryCategory.DataCarrying, both), + GalleryScreen("contractor_detail", GalleryCategory.DataCarrying, both), + + // ---------- Documents ---------- + // Android has a single `documents` screen; iOS has a tabbed + // `documents_warranties` view that unifies docs + warranties under + // a segmented control. They're structurally distinct enough to + // list as separate rows so the gallery makes the divergence + // visible rather than pretending they're the same screen. + GalleryScreen("documents", GalleryCategory.DataCarrying, androidOnly), + GalleryScreen("documents_warranties", GalleryCategory.DataCarrying, iosOnly), + GalleryScreen("document_detail", GalleryCategory.DataCarrying, both), + GalleryScreen("add_document", GalleryCategory.DataFree, both), + GalleryScreen("edit_document", GalleryCategory.DataFree, both), + + // ---------- Profile / settings ---------- + GalleryScreen("profile", GalleryCategory.DataCarrying, both), + // `profile_edit` is iOS-only: iOS has a standalone edit-profile view. + // On Android, profile editing is folded into `profile` (inline form). + GalleryScreen("profile_edit", GalleryCategory.DataFree, iosOnly), + GalleryScreen("notification_preferences", GalleryCategory.DataFree, both), + GalleryScreen("theme_selection", GalleryCategory.DataFree, both), + GalleryScreen("biometric_lock", GalleryCategory.DataFree, androidOnly), + + // ---------- Subscription ---------- + GalleryScreen("feature_comparison", GalleryCategory.DataFree, both), + ) + + /** Screens captured on Android, keyed by canonical name. */ + val forAndroid: Map = + all.filter { Platform.ANDROID in it.platforms }.associateBy { it.name } + + /** Screens captured on iOS, keyed by canonical name. */ + val forIos: Map = + all.filter { Platform.IOS in it.platforms }.associateBy { it.name } +} diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/AuthViewModel.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/AuthViewModel.kt index fb30859..a3a7ea4 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/AuthViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/AuthViewModel.kt @@ -50,7 +50,12 @@ class AuthViewModel( val currentUserState: StateFlow> = dataManager.currentUser .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.currentUser.value + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) private val _forgotPasswordState = MutableStateFlow>(ApiResult.Idle) val forgotPasswordState: StateFlow> = _forgotPasswordState diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ContractorViewModel.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ContractorViewModel.kt index 66dec59..fff989c 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ContractorViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ContractorViewModel.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.launch */ class ContractorViewModel( private val dataManager: IDataManager = DataManager, + initialSelectedContractorId: Int? = null, ) : ViewModel() { // ---------- Read state ---------- @@ -33,15 +34,32 @@ class ContractorViewModel( val contractorsState: StateFlow>> = dataManager.contractors .map { list -> if (list.isNotEmpty()) ApiResult.Success(list) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.contractors.value + .takeIf { it.isNotEmpty() } + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) - private val _selectedContractorId = MutableStateFlow(null) + // `initialSelectedContractorId` seeds this in construction order so the + // `stateIn` initial-value closure below observes the selected id *and* + // the seeded `dataManager.contractorDetail[id]` on first subscription — + // used by the parity-gallery snapshot harness to render populated + // detail screens on the very first composition frame. + private val _selectedContractorId = MutableStateFlow(initialSelectedContractorId) val contractorDetailState: StateFlow> = combine(_selectedContractorId, dataManager.contractorDetail) { id, map -> if (id == null) ApiResult.Idle else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle - }.stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + }.stateIn( + viewModelScope, + SharingStarted.Eagerly, + _selectedContractorId.value?.let { id -> + dataManager.contractorDetail.value[id]?.let { ApiResult.Success(it) } + } ?: ApiResult.Idle, + ) // ---------- Loading / error ---------- diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/DocumentViewModel.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/DocumentViewModel.kt index a19483f..554f9af 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/DocumentViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/DocumentViewModel.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.launch */ class DocumentViewModel( private val dataManager: IDataManager = DataManager, + initialSelectedDocumentId: Int? = null, ) : ViewModel() { // ---------- Read state ---------- @@ -34,15 +35,32 @@ class DocumentViewModel( val documentsState: StateFlow>> = dataManager.documents .map { list -> if (list.isNotEmpty()) ApiResult.Success(list) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.documents.value + .takeIf { it.isNotEmpty() } + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) - private val _selectedDocumentId = MutableStateFlow(null) + // `initialSelectedDocumentId` seeds this in construction order so the + // `stateIn` initial-value closure below observes the selected id *and* + // the seeded `dataManager.documentDetail[id]` on first subscription — + // used by the parity-gallery snapshot harness to render populated + // detail screens on the very first composition frame. + private val _selectedDocumentId = MutableStateFlow(initialSelectedDocumentId) val documentDetailState: StateFlow> = combine(_selectedDocumentId, dataManager.documentDetail) { id, map -> if (id == null) ApiResult.Idle else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle - }.stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + }.stateIn( + viewModelScope, + SharingStarted.Eagerly, + _selectedDocumentId.value?.let { id -> + dataManager.documentDetail.value[id]?.let { ApiResult.Success(it) } + } ?: ApiResult.Idle, + ) fun selectDocument(id: Int?) { _selectedDocumentId.value = id diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/NotificationPreferencesViewModel.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/NotificationPreferencesViewModel.kt index fb154d8..53b78dc 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/NotificationPreferencesViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/NotificationPreferencesViewModel.kt @@ -87,7 +87,12 @@ class NotificationPreferencesViewModel( val preferencesState: StateFlow> = dataManager.notificationPreferences .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.notificationPreferences.value + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) private val _updateState = MutableStateFlow>(ApiResult.Idle) val updateState: StateFlow> = _updateState.asStateFlow() diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ResidenceViewModel.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ResidenceViewModel.kt index b07bd26..8e1db03 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ResidenceViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/ResidenceViewModel.kt @@ -39,17 +39,33 @@ class ResidenceViewModel( val residencesState: StateFlow>> = dataManager.residences .map { list -> if (list.isNotEmpty()) ApiResult.Success(list) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.residences.value + .takeIf { it.isNotEmpty() } + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) val myResidencesState: StateFlow> = dataManager.myResidences .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.myResidences.value + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) val summaryState: StateFlow> = dataManager.totalSummary .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.totalSummary.value + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) /** Drives the residence-scoped projections. */ private val _selectedResidenceId = MutableStateFlow(null) @@ -58,13 +74,25 @@ class ResidenceViewModel( combine(_selectedResidenceId, dataManager.tasksByResidence) { id, map -> if (id == null) ApiResult.Idle else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle - }.stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + }.stateIn( + viewModelScope, + SharingStarted.Eagerly, + _selectedResidenceId.value?.let { id -> + dataManager.tasksByResidence.value[id]?.let { ApiResult.Success(it) } + } ?: ApiResult.Idle, + ) val residenceContractorsState: StateFlow>> = combine(_selectedResidenceId, dataManager.contractorsByResidence) { id, map -> if (id == null) ApiResult.Idle else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle - }.stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + }.stateIn( + viewModelScope, + SharingStarted.Eagerly, + _selectedResidenceId.value?.let { id -> + dataManager.contractorsByResidence.value[id]?.let { ApiResult.Success(it) } + } ?: ApiResult.Idle, + ) // ---------- Loading / error feedback ---------- diff --git a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/TaskViewModel.kt b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/TaskViewModel.kt index 2435358..8fec465 100644 --- a/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/TaskViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/tt/honeyDue/viewmodel/TaskViewModel.kt @@ -48,7 +48,12 @@ class TaskViewModel( val tasksState: StateFlow> = dataManager.allTasks .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle } - .stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + dataManager.allTasks.value + ?.let { ApiResult.Success(it) } ?: ApiResult.Idle, + ) /** Drives the [tasksByResidenceState] projection key. */ private val _selectedResidenceId = MutableStateFlow(null) @@ -58,7 +63,13 @@ class TaskViewModel( combine(_selectedResidenceId, dataManager.tasksByResidence) { id, map -> if (id == null) ApiResult.Idle else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle - }.stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + }.stateIn( + viewModelScope, + SharingStarted.Eagerly, + _selectedResidenceId.value?.let { id -> + dataManager.tasksByResidence.value[id]?.let { ApiResult.Success(it) } + } ?: ApiResult.Idle, + ) /** Drives the [taskCompletionsState] projection key. */ private val _selectedTaskId = MutableStateFlow(null) @@ -68,7 +79,13 @@ class TaskViewModel( combine(_selectedTaskId, dataManager.taskCompletions) { id, map -> if (id == null) ApiResult.Idle else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle - }.stateIn(viewModelScope, SharingStarted.Eagerly, ApiResult.Idle) + }.stateIn( + viewModelScope, + SharingStarted.Eagerly, + _selectedTaskId.value?.let { id -> + dataManager.taskCompletions.value[id]?.let { ApiResult.Success(it) } + } ?: ApiResult.Idle, + ) // ---------- Loading / error feedback ---------- diff --git a/composeApp/src/commonTest/kotlin/com/tt/honeyDue/testing/GalleryManifestTest.kt b/composeApp/src/commonTest/kotlin/com/tt/honeyDue/testing/GalleryManifestTest.kt new file mode 100644 index 0000000..4648ac3 --- /dev/null +++ b/composeApp/src/commonTest/kotlin/com/tt/honeyDue/testing/GalleryManifestTest.kt @@ -0,0 +1,74 @@ +package com.tt.honeyDue.testing + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.fail + +/** + * Sanity checks on the canonical parity-gallery manifest. + * + * These run on every platform's test target because the manifest lives in + * [commonMain]; they guard against obvious mistakes (duplicate names, + * empty-platform screens) before the platform-specific parity tests run. + */ +class GalleryManifestTest { + + @Test + fun manifest_has_no_duplicate_names() { + val duplicates = GalleryScreens.all + .groupingBy { it.name } + .eachCount() + .filterValues { it > 1 } + assertTrue( + duplicates.isEmpty(), + "Duplicate canonical screen names in manifest: $duplicates", + ) + } + + @Test + fun every_screen_has_at_least_one_platform() { + val orphans = GalleryScreens.all.filter { it.platforms.isEmpty() } + assertTrue( + orphans.isEmpty(), + "Screens with no platforms — they'd never be captured: ${orphans.map { it.name }}", + ) + } + + @Test + fun snake_case_names_only() { + val malformed = GalleryScreens.all.filter { !it.name.matches(Regex("^[a-z][a-z0-9_]*$")) } + assertTrue( + malformed.isEmpty(), + "Non-snake_case screen names: ${malformed.map { it.name }}", + ) + } + + @Test + fun expected_counts_match_plan() { + // Canaries: if someone adds/removes a screen without updating the + // docs/parity-gallery.md summary, this test fails loudly. Bump + // both in the same PR. + assertEquals(43, GalleryScreens.all.size, "Total canonical screen count") + assertEquals( + 12, + GalleryScreens.all.count { it.category == GalleryCategory.DataCarrying }, + "Data-carrying screen count", + ) + assertEquals( + 31, + GalleryScreens.all.count { it.category == GalleryCategory.DataFree }, + "Data-free screen count", + ) + } + + @Test + fun android_subset_matches_count() { + assertEquals(40, GalleryScreens.forAndroid.size, "Android-reachable screen count") + } + + @Test + fun ios_subset_matches_count() { + assertEquals(40, GalleryScreens.forIos.size, "iOS-reachable screen count") + } +} diff --git a/docs/parity-gallery-grid.md b/docs/parity-gallery-grid.md index 8d5ea56..0c4ce40 100644 --- a/docs/parity-gallery-grid.md +++ b/docs/parity-gallery-grid.md @@ -1,6 +1,6 @@ # honeyDue parity gallery -*160 Android · 88 iOS · 48 screens* +*43 screens · 102 Android · 174 iOS* Auto-generated by `scripts/build_parity_gallery.py` — do not hand-edit. @@ -8,676 +8,544 @@ See [parity-gallery.md](parity-gallery.md) for the workflow guide. ## Screens -- [add_document](#add-document) -- [add_residence](#add-residence) -- [add_task](#add-task) -- [add_task_with_residence](#add-task-with-residence) -- [all_tasks](#all-tasks) -- [animation_testing](#animation-testing) -- [biometric_lock](#biometric-lock) -- [complete_task](#complete-task) -- [contractor_detail](#contractor-detail) -- [contractors](#contractors) -- [contractors_list](#contractors-list) -- [document_detail](#document-detail) -- [documents](#documents) -- [documents_warranties](#documents-warranties) -- [edit_document](#edit-document) -- [edit_residence](#edit-residence) -- [edit_task](#edit-task) -- [feature_comparison](#feature-comparison) -- [forgot_password](#forgot-password) -- [home](#home) -- [join_residence](#join-residence) -- [login](#login) -- [manage_users](#manage-users) -- [notification_preferences](#notification-preferences) -- [onboarding_create_account](#onboarding-create-account) -- [onboarding_first_task](#onboarding-first-task) -- [onboarding_home_profile](#onboarding-home-profile) -- [onboarding_join_residence](#onboarding-join-residence) -- [onboarding_location](#onboarding-location) -- [onboarding_name_residence](#onboarding-name-residence) -- [onboarding_subscription](#onboarding-subscription) -- [onboarding_value_props](#onboarding-value-props) -- [onboarding_verify_email](#onboarding-verify-email) -- [onboarding_welcome](#onboarding-welcome) -- [profile](#profile) -- [profile_edit](#profile-edit) -- [profile_tab](#profile-tab) -- [register](#register) -- [reset_password](#reset-password) -- [residence_detail](#residence-detail) -- [residences](#residences) -- [residences_list](#residences-list) -- [task_suggestions](#task-suggestions) -- [task_templates_browser](#task-templates-browser) -- [tasks](#tasks) -- [theme_selection](#theme-selection) -- [verify_email](#verify-email) -- [verify_reset_code](#verify-reset-code) +- [login](#login) *(DataFree)* +- [register](#register) *(DataFree)* +- [forgot_password](#forgot-password) *(DataFree)* +- [verify_reset_code](#verify-reset-code) *(DataFree)* +- [reset_password](#reset-password) *(DataFree)* +- [verify_email](#verify-email) *(DataFree)* +- [onboarding_welcome](#onboarding-welcome) *(DataFree)* +- [onboarding_value_props](#onboarding-value-props) *(DataFree)* +- [onboarding_create_account](#onboarding-create-account) *(DataFree)* +- [onboarding_verify_email](#onboarding-verify-email) *(DataFree)* +- [onboarding_location](#onboarding-location) *(DataFree)* +- [onboarding_name_residence](#onboarding-name-residence) *(DataFree)* +- [onboarding_home_profile](#onboarding-home-profile) *(DataFree)* +- [onboarding_join_residence](#onboarding-join-residence) *(DataFree)* +- [onboarding_first_task](#onboarding-first-task) *(DataCarrying)* +- [onboarding_subscription](#onboarding-subscription) *(DataFree)* +- [home](#home) *(DataCarrying)* — *Android-only* +- [residences](#residences) *(DataCarrying)* +- [residence_detail](#residence-detail) *(DataCarrying)* +- [add_residence](#add-residence) *(DataFree)* +- [edit_residence](#edit-residence) *(DataFree)* +- [join_residence](#join-residence) *(DataFree)* +- [manage_users](#manage-users) *(DataFree)* +- [all_tasks](#all-tasks) *(DataCarrying)* +- [add_task](#add-task) *(DataFree)* — *iOS-only* +- [add_task_with_residence](#add-task-with-residence) *(DataFree)* +- [edit_task](#edit-task) *(DataFree)* +- [complete_task](#complete-task) *(DataFree)* +- [task_suggestions](#task-suggestions) *(DataFree)* +- [task_templates_browser](#task-templates-browser) *(DataCarrying)* +- [contractors](#contractors) *(DataCarrying)* +- [contractor_detail](#contractor-detail) *(DataCarrying)* +- [documents](#documents) *(DataCarrying)* — *Android-only* +- [documents_warranties](#documents-warranties) *(DataCarrying)* — *iOS-only* +- [document_detail](#document-detail) *(DataCarrying)* +- [add_document](#add-document) *(DataFree)* +- [edit_document](#edit-document) *(DataFree)* +- [profile](#profile) *(DataCarrying)* +- [profile_edit](#profile-edit) *(DataFree)* — *iOS-only* +- [notification_preferences](#notification-preferences) *(DataFree)* +- [theme_selection](#theme-selection) *(DataFree)* +- [biometric_lock](#biometric-lock) *(DataFree)* — *Android-only* +- [feature_comparison](#feature-comparison) *(DataFree)* --- -## add_document +## login *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/add_document_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/add_document_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/add_document_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/add_document_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/login_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_login.login_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/login_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_login.login_dark.png) | [top](#honeydue-parity-gallery) --- -## add_residence +## register *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/add_residence_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_residence_empty.add_residence_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/add_residence_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_residence_empty.add_residence_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/add_residence_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_residence_populated.add_residence_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/add_residence_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_residence_populated.add_residence_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/register_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_register.register_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/register_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_register.register_dark.png) | [top](#honeydue-parity-gallery) --- -## add_task +## forgot_password *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_empty.add_task_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_empty.add_task_empty_dark.png) | -| **populated** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_populated.add_task_populated_light.png) | -| **populated** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_populated.add_task_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/forgot_password_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_forgot_password.forgot_password_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/forgot_password_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_forgot_password.forgot_password_dark.png) | [top](#honeydue-parity-gallery) --- -## add_task_with_residence +## verify_reset_code *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_with_residence_empty.add_task_with_residence_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_with_residence_empty.add_task_with_residence_empty_dark.png) | -| **populated** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_with_residence_populated.add_task_with_residence_populated_light.png) | -| **populated** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_with_residence_populated.add_task_with_residence_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/verify_reset_code_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_reset_code.verify_reset_code_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/verify_reset_code_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_reset_code.verify_reset_code_dark.png) | [top](#honeydue-parity-gallery) --- -## all_tasks +## reset_password *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks_empty.all_tasks_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks_empty.all_tasks_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks_populated.all_tasks_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks_populated.all_tasks_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/reset_password_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_reset_password.reset_password_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/reset_password_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_reset_password.reset_password_dark.png) | [top](#honeydue-parity-gallery) --- -## animation_testing +## verify_email *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/animation_testing_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/animation_testing_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/verify_email_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_email.verify_email_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/verify_email_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_email.verify_email_dark.png) | [top](#honeydue-parity-gallery) --- -## biometric_lock +## onboarding_welcome *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/biometric_lock_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/biometric_lock_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/biometric_lock_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_welcome.onboarding_welcome_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_welcome.onboarding_welcome_dark.png) | [top](#honeydue-parity-gallery) --- -## complete_task +## onboarding_value_props *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/complete_task_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/complete_task_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/complete_task_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/complete_task_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_value_props.onboarding_value_props_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_value_props.onboarding_value_props_dark.png) | [top](#honeydue-parity-gallery) --- -## contractor_detail +## onboarding_create_account *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_create_account.onboarding_create_account_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_create_account.onboarding_create_account_dark.png) | [top](#honeydue-parity-gallery) --- -## contractors +## onboarding_verify_email *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_verify_email.onboarding_verify_email_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_verify_email.onboarding_verify_email_dark.png) | [top](#honeydue-parity-gallery) --- -## contractors_list +## onboarding_location *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors_list_empty.contractors_list_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors_list_empty.contractors_list_empty_dark.png) | -| **populated** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors_list_populated.contractors_list_populated_light.png) | -| **populated** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors_list_populated.contractors_list_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_location_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_location.onboarding_location_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_location_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_location.onboarding_location_dark.png) | [top](#honeydue-parity-gallery) --- -## document_detail +## onboarding_name_residence *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_name_residence.onboarding_name_residence_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_name_residence.onboarding_name_residence_dark.png) | [top](#honeydue-parity-gallery) --- -## documents +## onboarding_home_profile *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/documents_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/documents_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/documents_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/documents_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_home_profile.onboarding_home_profile_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_home_profile.onboarding_home_profile_dark.png) | [top](#honeydue-parity-gallery) --- -## documents_warranties +## onboarding_join_residence *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties_empty.documents_warranties_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties_empty.documents_warranties_empty_dark.png) | -| **populated** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties_populated.documents_warranties_populated_light.png) | -| **populated** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties_populated.documents_warranties_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_join_residence.onboarding_join_residence_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_join_residence.onboarding_join_residence_dark.png) | [top](#honeydue-parity-gallery) --- -## edit_document +## onboarding_first_task *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/edit_document_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/edit_document_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/edit_document_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/edit_document_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_first_task_empty.onboarding_first_task_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_first_task_empty.onboarding_first_task_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_first_task.onboarding_first_task_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_first_task_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_first_task.onboarding_first_task_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## edit_residence +## onboarding_subscription *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/edit_residence_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/edit_residence_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/edit_residence_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_subscription.onboarding_subscription_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_subscription.onboarding_subscription_dark.png) | [top](#honeydue-parity-gallery) --- -## edit_task +## home *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/edit_task_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/edit_task_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/edit_task_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/edit_task_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/home_empty_light.png) | _(not on ios)_ | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/home_empty_dark.png) | _(not on ios)_ | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/home_populated_light.png) | _(not on ios)_ | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/home_populated_dark.png) | _(not on ios)_ | [top](#honeydue-parity-gallery) --- -## feature_comparison +## residences *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/feature_comparison_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_feature_comparison_empty.feature_comparison_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/feature_comparison_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_feature_comparison_empty.feature_comparison_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_feature_comparison_populated.feature_comparison_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/feature_comparison_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_feature_comparison_populated.feature_comparison_populated_dark.png) | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/residences_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences.residences_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/residences_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences.residences_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/residences_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences.residences_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/residences_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences.residences_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## forgot_password +## residence_detail *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/forgot_password_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_forgot_password_empty.forgot_password_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/forgot_password_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_forgot_password_empty.forgot_password_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/forgot_password_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residence_detail.residence_detail_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residence_detail.residence_detail_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residence_detail.residence_detail_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residence_detail.residence_detail_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## home +## add_residence *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/home_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/home_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/home_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/home_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/add_residence_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_residence.add_residence_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/add_residence_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_residence.add_residence_dark.png) | [top](#honeydue-parity-gallery) --- -## join_residence +## edit_residence *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/join_residence_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_join_residence_empty.join_residence_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/join_residence_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_join_residence_empty.join_residence_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/join_residence_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_join_residence_populated.join_residence_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/join_residence_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_join_residence_populated.join_residence_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/edit_residence_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_edit_residence.edit_residence_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/edit_residence_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_edit_residence.edit_residence_dark.png) | [top](#honeydue-parity-gallery) --- -## login +## join_residence *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/login_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_login_empty.login_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/login_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_login_empty.login_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/login_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/login_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/join_residence_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_join_residence.join_residence_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/join_residence_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_join_residence.join_residence_dark.png) | [top](#honeydue-parity-gallery) --- -## manage_users +## manage_users *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/manage_users_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/manage_users_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/manage_users_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/manage_users_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/manage_users_light.png) | _\[missing — ios\]_ | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/manage_users_dark.png) | _\[missing — ios\]_ | [top](#honeydue-parity-gallery) --- -## notification_preferences +## all_tasks *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/notification_preferences_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_notification_preferences_empty.notification_preferences_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/notification_preferences_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_notification_preferences_empty.notification_preferences_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_notification_preferences_populated.notification_preferences_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/notification_preferences_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_notification_preferences_populated.notification_preferences_populated_dark.png) | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks_empty.all_tasks_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks.all_tasks_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks.all_tasks_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/all_tasks_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_all_tasks_populated.all_tasks_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_create_account +## add_task *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_create_account_empty.onboarding_create_account_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_create_account_empty.onboarding_create_account_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_create_account_populated_dark.png) | _missing_ | +| **light** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task.add_task_light.png) | +| **dark** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task.add_task_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_first_task +## add_task_with_residence *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_first_task_empty.onboarding_first_task_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_first_task_empty.onboarding_first_task_empty_dark.png) | -| **populated** / light | _missing_ | _missing_ | -| **populated** / dark | _missing_ | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_with_residence.add_task_with_residence_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/add_task_with_residence_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_task_with_residence.add_task_with_residence_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_home_profile +## edit_task *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_home_profile_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/edit_task_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_edit_task.edit_task_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/edit_task_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_edit_task.edit_task_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_join_residence +## complete_task *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_join_residence_empty.onboarding_join_residence_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_join_residence_empty.onboarding_join_residence_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_join_residence_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/complete_task_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_complete_task.complete_task_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/complete_task_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_complete_task.complete_task_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_location +## task_suggestions *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_location_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_location_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_location_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/task_suggestions_light.png) | _\[missing — ios\]_ | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/task_suggestions_dark.png) | _\[missing — ios\]_ | [top](#honeydue-parity-gallery) --- -## onboarding_name_residence +## task_templates_browser *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_name_residence_empty.onboarding_name_residence_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_name_residence_empty.onboarding_name_residence_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_name_residence_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser_empty.task_templates_browser_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser.task_templates_browser_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser_populated.task_templates_browser_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser.task_templates_browser_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_subscription +## contractors *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_subscription_empty.onboarding_subscription_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_subscription_empty.onboarding_subscription_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_subscription_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors.contractors_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors.contractors_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors.contractors_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/contractors_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractors.contractors_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_value_props +## contractor_detail *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_value_props_empty.onboarding_value_props_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_value_props_empty.onboarding_value_props_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_value_props_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractor_detail.contractor_detail_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractor_detail.contractor_detail_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractor_detail.contractor_detail_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/contractor_detail_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_contractor_detail.contractor_detail_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## onboarding_verify_email +## documents *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_verify_email_empty.onboarding_verify_email_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_verify_email_empty.onboarding_verify_email_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_verify_email_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/documents_empty_light.png) | _(not on ios)_ | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/documents_empty_dark.png) | _(not on ios)_ | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/documents_populated_light.png) | _(not on ios)_ | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/documents_populated_dark.png) | _(not on ios)_ | [top](#honeydue-parity-gallery) --- -## onboarding_welcome +## documents_warranties *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_welcome_empty.onboarding_welcome_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_onboarding_welcome_empty.onboarding_welcome_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/onboarding_welcome_populated_dark.png) | _missing_ | +| **empty / light** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties.documents_warranties_empty_light.png) | +| **empty / dark** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties_empty.documents_warranties_empty_dark.png) | +| **populated / light** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties_populated.documents_warranties_populated_light.png) | +| **populated / dark** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_documents_warranties_populated.documents_warranties_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## profile +## document_detail *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/profile_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/profile_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/profile_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/profile_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_document_detail.document_detail_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_document_detail.document_detail_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_document_detail.document_detail_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/document_detail_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_document_detail.document_detail_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## profile_edit +## add_document *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_edit_empty.profile_edit_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_edit_empty.profile_edit_empty_dark.png) | -| **populated** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_edit_populated.profile_edit_populated_light.png) | -| **populated** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_edit_populated.profile_edit_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/add_document_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_document.add_document_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/add_document_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_add_document.add_document_dark.png) | [top](#honeydue-parity-gallery) --- -## profile_tab +## edit_document *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_tab_empty.profile_tab_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_tab_empty.profile_tab_empty_dark.png) | -| **populated** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_tab_populated.profile_tab_populated_light.png) | -| **populated** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_tab_populated.profile_tab_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/edit_document_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_edit_document.edit_document_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/edit_document_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_edit_document.edit_document_dark.png) | [top](#honeydue-parity-gallery) --- -## register +## profile *(DataCarrying)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/register_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_register_empty.register_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/register_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_register_empty.register_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/register_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/register_populated_dark.png) | _missing_ | +| **empty / light** | ![](../composeApp/src/androidUnitTest/roborazzi/profile_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile.profile_empty_light.png) | +| **empty / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/profile_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile.profile_empty_dark.png) | +| **populated / light** | ![](../composeApp/src/androidUnitTest/roborazzi/profile_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile.profile_populated_light.png) | +| **populated / dark** | ![](../composeApp/src/androidUnitTest/roborazzi/profile_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile.profile_populated_dark.png) | [top](#honeydue-parity-gallery) --- -## reset_password +## profile_edit *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/reset_password_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_reset_password_empty.reset_password_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/reset_password_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_reset_password_empty.reset_password_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/reset_password_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/reset_password_populated_dark.png) | _missing_ | +| **light** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_edit.profile_edit_light.png) | +| **dark** | _(not on android)_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_profile_edit.profile_edit_dark.png) | [top](#honeydue-parity-gallery) --- -## residence_detail +## notification_preferences *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/residence_detail_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/notification_preferences_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_notification_preferences.notification_preferences_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/notification_preferences_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_notification_preferences.notification_preferences_dark.png) | [top](#honeydue-parity-gallery) --- -## residences +## theme_selection *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/residences_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/residences_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/residences_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/residences_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/theme_selection_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_theme_selection.theme_selection_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/theme_selection_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_theme_selection.theme_selection_dark.png) | [top](#honeydue-parity-gallery) --- -## residences_list +## biometric_lock *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences_list_empty.residences_list_empty_light.png) | -| **empty** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences_list_empty.residences_list_empty_dark.png) | -| **populated** / light | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences_list_populated.residences_list_populated_light.png) | -| **populated** / dark | _missing_ | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_residences_list_populated.residences_list_populated_dark.png) | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/biometric_lock_light.png) | _(not on ios)_ | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/biometric_lock_dark.png) | _(not on ios)_ | [top](#honeydue-parity-gallery) --- -## task_suggestions +## feature_comparison *(DataFree)* | State / Mode | Android | iOS | |---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/task_suggestions_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_suggestions_empty.task_suggestions_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/task_suggestions_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_suggestions_empty.task_suggestions_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_suggestions_populated.task_suggestions_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/task_suggestions_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_suggestions_populated.task_suggestions_populated_dark.png) | - -[top](#honeydue-parity-gallery) - ---- - -## task_templates_browser - -| State / Mode | Android | iOS | -|---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser_empty.task_templates_browser_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser_empty.task_templates_browser_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser_populated.task_templates_browser_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/task_templates_browser_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_task_templates_browser_populated.task_templates_browser_populated_dark.png) | - -[top](#honeydue-parity-gallery) - ---- - -## tasks - -| State / Mode | Android | iOS | -|---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/tasks_empty_light.png) | _missing_ | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/tasks_empty_dark.png) | _missing_ | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/tasks_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/tasks_populated_dark.png) | _missing_ | - -[top](#honeydue-parity-gallery) - ---- - -## theme_selection - -| State / Mode | Android | iOS | -|---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/theme_selection_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_theme_selection_empty.theme_selection_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/theme_selection_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_theme_selection_empty.theme_selection_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_theme_selection_populated.theme_selection_populated_light.png) | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/theme_selection_populated_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_theme_selection_populated.theme_selection_populated_dark.png) | - -[top](#honeydue-parity-gallery) - ---- - -## verify_email - -| State / Mode | Android | iOS | -|---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/verify_email_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_email_empty.verify_email_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/verify_email_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_email_empty.verify_email_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/verify_email_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/verify_email_populated_dark.png) | _missing_ | - -[top](#honeydue-parity-gallery) - ---- - -## verify_reset_code - -| State / Mode | Android | iOS | -|---|---|---| -| **empty** / light | ![](../composeApp/src/androidUnitTest/roborazzi/verify_reset_code_empty_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_reset_code_empty.verify_reset_code_empty_light.png) | -| **empty** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/verify_reset_code_empty_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_verify_reset_code_empty.verify_reset_code_empty_dark.png) | -| **populated** / light | ![](../composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_light.png) | _missing_ | -| **populated** / dark | ![](../composeApp/src/androidUnitTest/roborazzi/verify_reset_code_populated_dark.png) | _missing_ | +| **light** | ![](../composeApp/src/androidUnitTest/roborazzi/feature_comparison_light.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_feature_comparison.feature_comparison_light.png) | +| **dark** | ![](../composeApp/src/androidUnitTest/roborazzi/feature_comparison_dark.png) | ![](../iosApp/HoneyDueTests/__Snapshots__/SnapshotGalleryTests/test_feature_comparison.feature_comparison_dark.png) | [top](#honeydue-parity-gallery) diff --git a/docs/parity-gallery.html b/docs/parity-gallery.html index 0b277ad..d0ee7f3 100644 --- a/docs/parity-gallery.html +++ b/docs/parity-gallery.html @@ -11,360 +11,270 @@ border-bottom: 1px solid #30363d; font-size: 12px; z-index: 10; } .nav a { color: #79c0ff; margin-right: 10px; text-decoration: none; white-space: nowrap; } .nav a:hover { text-decoration: underline; } - .grid-header { display: grid; grid-template-columns: 120px 1fr 1fr; gap: 12px; + .grid-header { display: grid; grid-template-columns: 140px 1fr 1fr; gap: 12px; padding: 0 12px 8px; color: #8b949e; font-size: 12px; font-weight: 600; position: sticky; top: 38px; background: #0d1117; z-index: 9; border-bottom: 1px solid #30363d; } .screen { background: #161b22; border-radius: 8px; padding: 12px; margin-bottom: 20px; } - .screen h2 { margin: 0 0 8px; font-size: 16px; color: #e6edf3; } - .row { display: grid; grid-template-columns: 120px 1fr 1fr; gap: 12px; + .screen h2 { margin: 0 0 8px; font-size: 16px; color: #e6edf3; display: flex; align-items: center; gap: 8px; } + .badge { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 10px; } + .badge-datacarrying { background: #0d5d56; color: #7ee2d1; } + .badge-datafree { background: #30363d; color: #8b949e; } + .row { display: grid; grid-template-columns: 140px 1fr 1fr; gap: 12px; margin-bottom: 8px; align-items: start; } .label { font-size: 12px; color: #c9d1d9; padding-top: 4px; } - .label .mode { color: #8b949e; font-weight: 400; } .row img { width: 100%; border: 1px solid #30363d; border-radius: 4px; display: block; } - .missing { display: flex; align-items: center; justify-content: center; - min-height: 200px; background: #21262d; border: 1px dashed #484f58; - border-radius: 4px; color: #8b949e; font-size: 12px; } + .missing { display: flex; flex-direction: column; align-items: center; justify-content: center; + min-height: 200px; background: #21262d; border-radius: 4px; + font-size: 13px; font-weight: 600; padding: 8px; } + .missing.missing-needed { border: 2px dashed #f85149; color: #f85149; } + .missing.missing-platform { border: 1px solid #30363d; color: #8b949e; } + .missing .hint { color: #6e7681; font-size: 10px; font-weight: 400; + margin-top: 6px; font-family: ui-monospace, monospace; } + .badge-only { background: #484f58; color: #c9d1d9; }

honeyDue parity gallery

-
160 Android · 88 iOS · 48 screens
- +
43 screens · 12 DataCarrying · 31 DataFree · 102 Android PNGs · 174 iOS PNGs
+
Android
iOS
-
-

add_document

-
empty
light
add_document_empty_light Android
iOS missing
-
empty
dark
add_document_empty_dark Android
iOS missing
-
populated
light
add_document_populated_light Android
iOS missing
-
populated
dark
add_document_populated_dark Android
iOS missing
-
-
-

add_residence

-
empty
light
add_residence_empty_light Androidadd_residence_empty_light iOS
-
empty
dark
add_residence_empty_dark Androidadd_residence_empty_dark iOS
-
populated
light
add_residence_populated_light Androidadd_residence_populated_light iOS
-
populated
dark
add_residence_populated_dark Androidadd_residence_populated_dark iOS
-
-
-

add_task

-
empty
light
Android missing
add_task_empty_light iOS
-
empty
dark
Android missing
add_task_empty_dark iOS
-
populated
light
Android missing
add_task_populated_light iOS
-
populated
dark
Android missing
add_task_populated_dark iOS
-
-
-

add_task_with_residence

-
empty
light
Android missing
add_task_with_residence_empty_light iOS
-
empty
dark
Android missing
add_task_with_residence_empty_dark iOS
-
populated
light
Android missing
add_task_with_residence_populated_light iOS
-
populated
dark
Android missing
add_task_with_residence_populated_dark iOS
-
-
-

all_tasks

-
empty
light
all_tasks_empty_light Androidall_tasks_empty_light iOS
-
empty
dark
all_tasks_empty_dark Androidall_tasks_empty_dark iOS
-
populated
light
all_tasks_populated_light Androidall_tasks_populated_light iOS
-
populated
dark
all_tasks_populated_dark Androidall_tasks_populated_dark iOS
-
-
-

animation_testing

-
empty
light
animation_testing_empty_light Android
iOS missing
-
empty
dark
animation_testing_empty_dark Android
iOS missing
-
populated
light
animation_testing_populated_light Android
iOS missing
-
populated
dark
animation_testing_populated_dark Android
iOS missing
-
-
-

biometric_lock

-
empty
light
biometric_lock_empty_light Android
iOS missing
-
empty
dark
biometric_lock_empty_dark Android
iOS missing
-
populated
light
biometric_lock_populated_light Android
iOS missing
-
populated
dark
biometric_lock_populated_dark Android
iOS missing
-
-
-

complete_task

-
empty
light
complete_task_empty_light Android
iOS missing
-
empty
dark
complete_task_empty_dark Android
iOS missing
-
populated
light
complete_task_populated_light Android
iOS missing
-
populated
dark
complete_task_populated_dark Android
iOS missing
-
-
-

contractor_detail

-
empty
light
contractor_detail_empty_light Android
iOS missing
-
empty
dark
contractor_detail_empty_dark Android
iOS missing
-
populated
light
contractor_detail_populated_light Android
iOS missing
-
populated
dark
contractor_detail_populated_dark Android
iOS missing
-
-
-

contractors

-
empty
light
contractors_empty_light Android
iOS missing
-
empty
dark
contractors_empty_dark Android
iOS missing
-
populated
light
contractors_populated_light Android
iOS missing
-
populated
dark
contractors_populated_dark Android
iOS missing
-
-
-

contractors_list

-
empty
light
Android missing
contractors_list_empty_light iOS
-
empty
dark
Android missing
contractors_list_empty_dark iOS
-
populated
light
Android missing
contractors_list_populated_light iOS
-
populated
dark
Android missing
contractors_list_populated_dark iOS
-
-
-

document_detail

-
empty
light
document_detail_empty_light Android
iOS missing
-
empty
dark
document_detail_empty_dark Android
iOS missing
-
populated
light
document_detail_populated_light Android
iOS missing
-
populated
dark
document_detail_populated_dark Android
iOS missing
-
-
-

documents

-
empty
light
documents_empty_light Android
iOS missing
-
empty
dark
documents_empty_dark Android
iOS missing
-
populated
light
documents_populated_light Android
iOS missing
-
populated
dark
documents_populated_dark Android
iOS missing
-
-
-

documents_warranties

-
empty
light
Android missing
documents_warranties_empty_light iOS
-
empty
dark
Android missing
documents_warranties_empty_dark iOS
-
populated
light
Android missing
documents_warranties_populated_light iOS
-
populated
dark
Android missing
documents_warranties_populated_dark iOS
-
-
-

edit_document

-
empty
light
edit_document_empty_light Android
iOS missing
-
empty
dark
edit_document_empty_dark Android
iOS missing
-
populated
light
edit_document_populated_light Android
iOS missing
-
populated
dark
edit_document_populated_dark Android
iOS missing
-
-
-

edit_residence

-
empty
light
edit_residence_empty_light Android
iOS missing
-
empty
dark
edit_residence_empty_dark Android
iOS missing
-
populated
light
edit_residence_populated_light Android
iOS missing
-
populated
dark
edit_residence_populated_dark Android
iOS missing
-
-
-

edit_task

-
empty
light
edit_task_empty_light Android
iOS missing
-
empty
dark
edit_task_empty_dark Android
iOS missing
-
populated
light
edit_task_populated_light Android
iOS missing
-
populated
dark
edit_task_populated_dark Android
iOS missing
-
-
-

feature_comparison

-
empty
light
feature_comparison_empty_light Androidfeature_comparison_empty_light iOS
-
empty
dark
feature_comparison_empty_dark Androidfeature_comparison_empty_dark iOS
-
populated
light
feature_comparison_populated_light Androidfeature_comparison_populated_light iOS
-
populated
dark
feature_comparison_populated_dark Androidfeature_comparison_populated_dark iOS
-
-
-

forgot_password

-
empty
light
forgot_password_empty_light Androidforgot_password_empty_light iOS
-
empty
dark
forgot_password_empty_dark Androidforgot_password_empty_dark iOS
-
populated
light
forgot_password_populated_light Android
iOS missing
-
populated
dark
forgot_password_populated_dark Android
iOS missing
-
-
-

home

-
empty
light
home_empty_light Android
iOS missing
-
empty
dark
home_empty_dark Android
iOS missing
-
populated
light
home_populated_light Android
iOS missing
-
populated
dark
home_populated_dark Android
iOS missing
-
-
-

join_residence

-
empty
light
join_residence_empty_light Androidjoin_residence_empty_light iOS
-
empty
dark
join_residence_empty_dark Androidjoin_residence_empty_dark iOS
-
populated
light
join_residence_populated_light Androidjoin_residence_populated_light iOS
-
populated
dark
join_residence_populated_dark Androidjoin_residence_populated_dark iOS
-
-

login

-
empty
light
login_empty_light Androidlogin_empty_light iOS
-
empty
dark
login_empty_dark Androidlogin_empty_dark iOS
-
populated
light
login_populated_light Android
iOS missing
-
populated
dark
login_populated_dark Android
iOS missing
-
-
-

manage_users

-
empty
light
manage_users_empty_light Android
iOS missing
-
empty
dark
manage_users_empty_dark Android
iOS missing
-
populated
light
manage_users_populated_light Android
iOS missing
-
populated
dark
manage_users_populated_dark Android
iOS missing
-
-
-

notification_preferences

-
empty
light
notification_preferences_empty_light Androidnotification_preferences_empty_light iOS
-
empty
dark
notification_preferences_empty_dark Androidnotification_preferences_empty_dark iOS
-
populated
light
notification_preferences_populated_light Androidnotification_preferences_populated_light iOS
-
populated
dark
notification_preferences_populated_dark Androidnotification_preferences_populated_dark iOS
-
-
-

onboarding_create_account

-
empty
light
onboarding_create_account_empty_light Androidonboarding_create_account_empty_light iOS
-
empty
dark
onboarding_create_account_empty_dark Androidonboarding_create_account_empty_dark iOS
-
populated
light
onboarding_create_account_populated_light Android
iOS missing
-
populated
dark
onboarding_create_account_populated_dark Android
iOS missing
-
-
-

onboarding_first_task

-
empty
light
Android missing
onboarding_first_task_empty_light iOS
-
empty
dark
Android missing
onboarding_first_task_empty_dark iOS
-
populated
light
Android missing
iOS missing
-
populated
dark
Android missing
iOS missing
-
-
-

onboarding_home_profile

-
empty
light
onboarding_home_profile_empty_light Android
iOS missing
-
empty
dark
onboarding_home_profile_empty_dark Android
iOS missing
-
populated
light
onboarding_home_profile_populated_light Android
iOS missing
-
populated
dark
onboarding_home_profile_populated_dark Android
iOS missing
-
-
-

onboarding_join_residence

-
empty
light
onboarding_join_residence_empty_light Androidonboarding_join_residence_empty_light iOS
-
empty
dark
onboarding_join_residence_empty_dark Androidonboarding_join_residence_empty_dark iOS
-
populated
light
onboarding_join_residence_populated_light Android
iOS missing
-
populated
dark
onboarding_join_residence_populated_dark Android
iOS missing
-
-
-

onboarding_location

-
empty
light
onboarding_location_empty_light Android
iOS missing
-
empty
dark
onboarding_location_empty_dark Android
iOS missing
-
populated
light
onboarding_location_populated_light Android
iOS missing
-
populated
dark
onboarding_location_populated_dark Android
iOS missing
-
-
-

onboarding_name_residence

-
empty
light
onboarding_name_residence_empty_light Androidonboarding_name_residence_empty_light iOS
-
empty
dark
onboarding_name_residence_empty_dark Androidonboarding_name_residence_empty_dark iOS
-
populated
light
onboarding_name_residence_populated_light Android
iOS missing
-
populated
dark
onboarding_name_residence_populated_dark Android
iOS missing
-
-
-

onboarding_subscription

-
empty
light
onboarding_subscription_empty_light Androidonboarding_subscription_empty_light iOS
-
empty
dark
onboarding_subscription_empty_dark Androidonboarding_subscription_empty_dark iOS
-
populated
light
onboarding_subscription_populated_light Android
iOS missing
-
populated
dark
onboarding_subscription_populated_dark Android
iOS missing
-
-
-

onboarding_value_props

-
empty
light
onboarding_value_props_empty_light Androidonboarding_value_props_empty_light iOS
-
empty
dark
onboarding_value_props_empty_dark Androidonboarding_value_props_empty_dark iOS
-
populated
light
onboarding_value_props_populated_light Android
iOS missing
-
populated
dark
onboarding_value_props_populated_dark Android
iOS missing
-
-
-

onboarding_verify_email

-
empty
light
onboarding_verify_email_empty_light Androidonboarding_verify_email_empty_light iOS
-
empty
dark
onboarding_verify_email_empty_dark Androidonboarding_verify_email_empty_dark iOS
-
populated
light
onboarding_verify_email_populated_light Android
iOS missing
-
populated
dark
onboarding_verify_email_populated_dark Android
iOS missing
-
-
-

onboarding_welcome

-
empty
light
onboarding_welcome_empty_light Androidonboarding_welcome_empty_light iOS
-
empty
dark
onboarding_welcome_empty_dark Androidonboarding_welcome_empty_dark iOS
-
populated
light
onboarding_welcome_populated_light Android
iOS missing
-
populated
dark
onboarding_welcome_populated_dark Android
iOS missing
-
-
-

profile

-
empty
light
profile_empty_light Android
iOS missing
-
empty
dark
profile_empty_dark Android
iOS missing
-
populated
light
profile_populated_light Android
iOS missing
-
populated
dark
profile_populated_dark Android
iOS missing
-
-
-

profile_edit

-
empty
light
Android missing
profile_edit_empty_light iOS
-
empty
dark
Android missing
profile_edit_empty_dark iOS
-
populated
light
Android missing
profile_edit_populated_light iOS
-
populated
dark
Android missing
profile_edit_populated_dark iOS
-
-
-

profile_tab

-
empty
light
Android missing
profile_tab_empty_light iOS
-
empty
dark
Android missing
profile_tab_empty_dark iOS
-
populated
light
Android missing
profile_tab_populated_light iOS
-
populated
dark
Android missing
profile_tab_populated_dark iOS
+

login DataFree

+
light
login_light Androidlogin_light iOS
+
dark
login_dark Androidlogin_dark iOS
-

register

-
empty
light
register_empty_light Androidregister_empty_light iOS
-
empty
dark
register_empty_dark Androidregister_empty_dark iOS
-
populated
light
register_populated_light Android
iOS missing
-
populated
dark
register_populated_dark Android
iOS missing
+

register DataFree

+
light
register_light Androidregister_light iOS
+
dark
register_dark Androidregister_dark iOS
-
-

reset_password

-
empty
light
reset_password_empty_light Androidreset_password_empty_light iOS
-
empty
dark
reset_password_empty_dark Androidreset_password_empty_dark iOS
-
populated
light
reset_password_populated_light Android
iOS missing
-
populated
dark
reset_password_populated_dark Android
iOS missing
-
-
-

residence_detail

-
empty
light
residence_detail_empty_light Android
iOS missing
-
empty
dark
residence_detail_empty_dark Android
iOS missing
-
populated
light
residence_detail_populated_light Android
iOS missing
-
populated
dark
residence_detail_populated_dark Android
iOS missing
-
-
-

residences

-
empty
light
residences_empty_light Android
iOS missing
-
empty
dark
residences_empty_dark Android
iOS missing
-
populated
light
residences_populated_light Android
iOS missing
-
populated
dark
residences_populated_dark Android
iOS missing
-
-
-

residences_list

-
empty
light
Android missing
residences_list_empty_light iOS
-
empty
dark
Android missing
residences_list_empty_dark iOS
-
populated
light
Android missing
residences_list_populated_light iOS
-
populated
dark
Android missing
residences_list_populated_dark iOS
-
-
-

task_suggestions

-
empty
light
task_suggestions_empty_light Androidtask_suggestions_empty_light iOS
-
empty
dark
task_suggestions_empty_dark Androidtask_suggestions_empty_dark iOS
-
populated
light
task_suggestions_populated_light Androidtask_suggestions_populated_light iOS
-
populated
dark
task_suggestions_populated_dark Androidtask_suggestions_populated_dark iOS
-
-
-

task_templates_browser

-
empty
light
task_templates_browser_empty_light Androidtask_templates_browser_empty_light iOS
-
empty
dark
task_templates_browser_empty_dark Androidtask_templates_browser_empty_dark iOS
-
populated
light
task_templates_browser_populated_light Androidtask_templates_browser_populated_light iOS
-
populated
dark
task_templates_browser_populated_dark Androidtask_templates_browser_populated_dark iOS
-
-
-

tasks

-
empty
light
tasks_empty_light Android
iOS missing
-
empty
dark
tasks_empty_dark Android
iOS missing
-
populated
light
tasks_populated_light Android
iOS missing
-
populated
dark
tasks_populated_dark Android
iOS missing
-
-
-

theme_selection

-
empty
light
theme_selection_empty_light Androidtheme_selection_empty_light iOS
-
empty
dark
theme_selection_empty_dark Androidtheme_selection_empty_dark iOS
-
populated
light
theme_selection_populated_light Androidtheme_selection_populated_light iOS
-
populated
dark
theme_selection_populated_dark Androidtheme_selection_populated_dark iOS
-
-
-

verify_email

-
empty
light
verify_email_empty_light Androidverify_email_empty_light iOS
-
empty
dark
verify_email_empty_dark Androidverify_email_empty_dark iOS
-
populated
light
verify_email_populated_light Android
iOS missing
-
populated
dark
verify_email_populated_dark Android
iOS missing
+
+

forgot_password DataFree

+
light
forgot_password_light Androidforgot_password_light iOS
+
dark
forgot_password_dark Androidforgot_password_dark iOS
-

verify_reset_code

-
empty
light
verify_reset_code_empty_light Androidverify_reset_code_empty_light iOS
-
empty
dark
verify_reset_code_empty_dark Androidverify_reset_code_empty_dark iOS
-
populated
light
verify_reset_code_populated_light Android
iOS missing
-
populated
dark
verify_reset_code_populated_dark Android
iOS missing
+

verify_reset_code DataFree

+
light
verify_reset_code_light Androidverify_reset_code_light iOS
+
dark
verify_reset_code_dark Androidverify_reset_code_dark iOS
+
+
+

reset_password DataFree

+
light
reset_password_light Androidreset_password_light iOS
+
dark
reset_password_dark Androidreset_password_dark iOS
+
+
+

verify_email DataFree

+
light
verify_email_light Androidverify_email_light iOS
+
dark
verify_email_dark Androidverify_email_dark iOS
+
+
+

onboarding_welcome DataFree

+
light
onboarding_welcome_light Androidonboarding_welcome_light iOS
+
dark
onboarding_welcome_dark Androidonboarding_welcome_dark iOS
+
+
+

onboarding_value_props DataFree

+
light
onboarding_value_props_light Androidonboarding_value_props_light iOS
+
dark
onboarding_value_props_dark Androidonboarding_value_props_dark iOS
+
+
+

onboarding_create_account DataFree

+
light
onboarding_create_account_light Androidonboarding_create_account_light iOS
+
dark
onboarding_create_account_dark Androidonboarding_create_account_dark iOS
+
+
+

onboarding_verify_email DataFree

+
light
onboarding_verify_email_light Androidonboarding_verify_email_light iOS
+
dark
onboarding_verify_email_dark Androidonboarding_verify_email_dark iOS
+
+
+

onboarding_location DataFree

+
light
onboarding_location_light Androidonboarding_location_light iOS
+
dark
onboarding_location_dark Androidonboarding_location_dark iOS
+
+
+

onboarding_name_residence DataFree

+
light
onboarding_name_residence_light Androidonboarding_name_residence_light iOS
+
dark
onboarding_name_residence_dark Androidonboarding_name_residence_dark iOS
+
+
+

onboarding_home_profile DataFree

+
light
onboarding_home_profile_light Androidonboarding_home_profile_light iOS
+
dark
onboarding_home_profile_dark Androidonboarding_home_profile_dark iOS
+
+
+

onboarding_join_residence DataFree

+
light
onboarding_join_residence_light Androidonboarding_join_residence_light iOS
+
dark
onboarding_join_residence_dark Androidonboarding_join_residence_dark iOS
+
+
+

onboarding_first_task DataCarrying

+
empty / light
onboarding_first_task_empty_light Androidonboarding_first_task_empty_light iOS
+
empty / dark
onboarding_first_task_empty_dark Androidonboarding_first_task_empty_dark iOS
+
populated / light
onboarding_first_task_populated_light Androidonboarding_first_task_populated_light iOS
+
populated / dark
onboarding_first_task_populated_dark Androidonboarding_first_task_populated_dark iOS
+
+
+

onboarding_subscription DataFree

+
light
onboarding_subscription_light Androidonboarding_subscription_light iOS
+
dark
onboarding_subscription_dark Androidonboarding_subscription_dark iOS
+
+
+

home DataCarrying Android-only

+
empty / light
home_empty_light Android
not on ios
home_empty_light.png
+
empty / dark
home_empty_dark Android
not on ios
home_empty_dark.png
+
populated / light
home_populated_light Android
not on ios
home_populated_light.png
+
populated / dark
home_populated_dark Android
not on ios
home_populated_dark.png
+
+
+

residences DataCarrying

+
empty / light
residences_empty_light Androidresidences_empty_light iOS
+
empty / dark
residences_empty_dark Androidresidences_empty_dark iOS
+
populated / light
residences_populated_light Androidresidences_populated_light iOS
+
populated / dark
residences_populated_dark Androidresidences_populated_dark iOS
+
+
+

residence_detail DataCarrying

+
empty / light
residence_detail_empty_light Androidresidence_detail_empty_light iOS
+
empty / dark
residence_detail_empty_dark Androidresidence_detail_empty_dark iOS
+
populated / light
residence_detail_populated_light Androidresidence_detail_populated_light iOS
+
populated / dark
residence_detail_populated_dark Androidresidence_detail_populated_dark iOS
+
+
+

add_residence DataFree

+
light
add_residence_light Androidadd_residence_light iOS
+
dark
add_residence_dark Androidadd_residence_dark iOS
+
+
+

edit_residence DataFree

+
light
edit_residence_light Androidedit_residence_light iOS
+
dark
edit_residence_dark Androidedit_residence_dark iOS
+
+
+

join_residence DataFree

+
light
join_residence_light Androidjoin_residence_light iOS
+
dark
join_residence_dark Androidjoin_residence_dark iOS
+
+
+

manage_users DataFree

+
light
manage_users_light Android
[missing — ios]
manage_users_light.png
+
dark
manage_users_dark Android
[missing — ios]
manage_users_dark.png
+
+
+

all_tasks DataCarrying

+
empty / light
all_tasks_empty_light Androidall_tasks_empty_light iOS
+
empty / dark
all_tasks_empty_dark Androidall_tasks_empty_dark iOS
+
populated / light
all_tasks_populated_light Androidall_tasks_populated_light iOS
+
populated / dark
all_tasks_populated_dark Androidall_tasks_populated_dark iOS
+
+
+

add_task DataFree iOS-only

+
light
not on android
add_task_light.png
add_task_light iOS
+
dark
not on android
add_task_dark.png
add_task_dark iOS
+
+
+

add_task_with_residence DataFree

+
light
add_task_with_residence_light Androidadd_task_with_residence_light iOS
+
dark
add_task_with_residence_dark Androidadd_task_with_residence_dark iOS
+
+
+

edit_task DataFree

+
light
edit_task_light Androidedit_task_light iOS
+
dark
edit_task_dark Androidedit_task_dark iOS
+
+
+

complete_task DataFree

+
light
complete_task_light Androidcomplete_task_light iOS
+
dark
complete_task_dark Androidcomplete_task_dark iOS
+
+
+

task_suggestions DataFree

+
light
task_suggestions_light Android
[missing — ios]
task_suggestions_light.png
+
dark
task_suggestions_dark Android
[missing — ios]
task_suggestions_dark.png
+
+
+

task_templates_browser DataCarrying

+
empty / light
task_templates_browser_empty_light Androidtask_templates_browser_empty_light iOS
+
empty / dark
task_templates_browser_empty_dark Androidtask_templates_browser_empty_dark iOS
+
populated / light
task_templates_browser_populated_light Androidtask_templates_browser_populated_light iOS
+
populated / dark
task_templates_browser_populated_dark Androidtask_templates_browser_populated_dark iOS
+
+
+

contractors DataCarrying

+
empty / light
contractors_empty_light Androidcontractors_empty_light iOS
+
empty / dark
contractors_empty_dark Androidcontractors_empty_dark iOS
+
populated / light
contractors_populated_light Androidcontractors_populated_light iOS
+
populated / dark
contractors_populated_dark Androidcontractors_populated_dark iOS
+
+
+

contractor_detail DataCarrying

+
empty / light
contractor_detail_empty_light Androidcontractor_detail_empty_light iOS
+
empty / dark
contractor_detail_empty_dark Androidcontractor_detail_empty_dark iOS
+
populated / light
contractor_detail_populated_light Androidcontractor_detail_populated_light iOS
+
populated / dark
contractor_detail_populated_dark Androidcontractor_detail_populated_dark iOS
+
+
+

documents DataCarrying Android-only

+
empty / light
documents_empty_light Android
not on ios
documents_empty_light.png
+
empty / dark
documents_empty_dark Android
not on ios
documents_empty_dark.png
+
populated / light
documents_populated_light Android
not on ios
documents_populated_light.png
+
populated / dark
documents_populated_dark Android
not on ios
documents_populated_dark.png
+
+
+

documents_warranties DataCarrying iOS-only

+
empty / light
not on android
documents_warranties_empty_light.png
documents_warranties_empty_light iOS
+
empty / dark
not on android
documents_warranties_empty_dark.png
documents_warranties_empty_dark iOS
+
populated / light
not on android
documents_warranties_populated_light.png
documents_warranties_populated_light iOS
+
populated / dark
not on android
documents_warranties_populated_dark.png
documents_warranties_populated_dark iOS
+
+
+

document_detail DataCarrying

+
empty / light
document_detail_empty_light Androiddocument_detail_empty_light iOS
+
empty / dark
document_detail_empty_dark Androiddocument_detail_empty_dark iOS
+
populated / light
document_detail_populated_light Androiddocument_detail_populated_light iOS
+
populated / dark
document_detail_populated_dark Androiddocument_detail_populated_dark iOS
+
+
+

add_document DataFree

+
light
add_document_light Androidadd_document_light iOS
+
dark
add_document_dark Androidadd_document_dark iOS
+
+
+

edit_document DataFree

+
light
edit_document_light Androidedit_document_light iOS
+
dark
edit_document_dark Androidedit_document_dark iOS
+
+
+

profile DataCarrying

+
empty / light
profile_empty_light Androidprofile_empty_light iOS
+
empty / dark
profile_empty_dark Androidprofile_empty_dark iOS
+
populated / light
profile_populated_light Androidprofile_populated_light iOS
+
populated / dark
profile_populated_dark Androidprofile_populated_dark iOS
+
+
+

profile_edit DataFree iOS-only

+
light
not on android
profile_edit_light.png
profile_edit_light iOS
+
dark
not on android
profile_edit_dark.png
profile_edit_dark iOS
+
+
+

notification_preferences DataFree

+
light
notification_preferences_light Androidnotification_preferences_light iOS
+
dark
notification_preferences_dark Androidnotification_preferences_dark iOS
+
+
+

theme_selection DataFree

+
light
theme_selection_light Androidtheme_selection_light iOS
+
dark
theme_selection_dark Androidtheme_selection_dark iOS
+
+
+

biometric_lock DataFree Android-only

+
light
biometric_lock_light Android
not on ios
biometric_lock_light.png
+
dark
biometric_lock_dark Android
not on ios
biometric_lock_dark.png
+
+
+

feature_comparison DataFree

+
light
feature_comparison_light Androidfeature_comparison_light iOS
+
dark
feature_comparison_dark Androidfeature_comparison_dark iOS