Files
honeyDueKMP/composeApp/src/commonMain/kotlin/com/tt/honeyDue/models/Lookups.kt
T
Trey T db65db6232
Android UI Tests / ui-tests (push) Has been cancelled
i18n: complete app-wide localization (10 languages) + audit tooling
Localize all user-facing strings across iOS (SwiftUI), shared Kotlin, and
Android Compose into en/es/fr/de/pt/it/ja/ko/nl/zh:
- iOS String Catalogs: main + widget Localizable.xcstrings, InfoPlist.xcstrings
  (permissions), plural variations, ~200 new keys translated
- Shared Kotlin ClientStrings table + Android composeResources/values-* (884 keys
  ×10), routed Api/ViewModel/util error & UI strings through localization
- Backend-localized lookups/suggestions consumed via display names
- Widget extension catalog; theme names, home-profile fallbacks, validation,
  network errors, accessibility labels all localized

Add re-runnable verification gates:
- scripts/i18n_audit.py  — enumerate every literal, partition to GAP=0
- scripts/i18n_coverage.py — all 10 locales translated, format-specifier parity

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:52:28 -05:00

172 lines
5.1 KiB
Kotlin

package com.tt.honeyDue.models
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Residence type lookup - matching Go API
* Note: Go API returns arrays directly, no wrapper
*/
@Serializable
data class ResidenceType(
val id: Int,
val name: String,
@SerialName("display_name") val displayNameLocalized: String = ""
) {
/** Localized label for the current locale; falls back to [name]. */
val displayName: String
get() = displayNameLocalized.ifBlank { name }
}
/**
* Task frequency lookup - matching Go API TaskFrequencyResponse
*/
@Serializable
data class TaskFrequency(
val id: Int,
val name: String,
@SerialName("display_name") val displayNameLocalized: String = "",
val days: Int? = null,
@SerialName("display_order") val displayOrder: Int = 0
) {
/** Localized label for the current locale; falls back to [name]. */
val displayName: String
get() = displayNameLocalized.ifBlank { name }
}
/**
* Task priority lookup - matching Go API TaskPriorityResponse
*/
@Serializable
data class TaskPriority(
val id: Int,
val name: String,
@SerialName("display_name") val displayNameLocalized: String = "",
val level: Int = 0,
val color: String = "",
@SerialName("display_order") val displayOrder: Int = 0
) {
/** Localized label for the current locale; falls back to [name]. */
val displayName: String
get() = displayNameLocalized.ifBlank { name }
}
/**
* Task category lookup - matching Go API TaskCategoryResponse
*/
@Serializable
data class TaskCategory(
val id: Int,
val name: String,
@SerialName("display_name") val displayNameLocalized: String = "",
val description: String = "",
val icon: String = "",
val color: String = "",
@SerialName("display_order") val displayOrder: Int = 0
) {
/** Localized label for the current locale; falls back to [name]. */
val displayName: String
get() = displayNameLocalized.ifBlank { name }
}
/**
* Contractor specialty lookup
*/
@Serializable
data class ContractorSpecialty(
val id: Int,
val name: String,
@SerialName("display_name") val displayNameLocalized: String = "",
val description: String? = null,
val icon: String? = null,
@SerialName("display_order") val displayOrder: Int = 0
) {
/** Localized label for the current locale; falls back to [name]. */
val displayName: String
get() = displayNameLocalized.ifBlank { name }
}
/**
* A selectable home-profile field option (heating type, roof type, etc.),
* served localized by the backend. [value] is the stable code stored on the
* residence; [displayName] is the localized label.
*/
@Serializable
data class HomeProfileOption(
val value: String,
@SerialName("display_name") val displayName: String
)
/**
* Minimal contractor info for task references
*/
@Serializable
data class ContractorMinimal(
val id: Int,
val name: String,
val company: String? = null
)
/**
* Static data response - all lookups in one call
* Note: This may need adjustment based on Go API implementation
*/
@Serializable
data class StaticDataResponse(
@SerialName("residence_types") val residenceTypes: List<ResidenceType>,
@SerialName("task_frequencies") val taskFrequencies: List<TaskFrequency>,
@SerialName("task_priorities") val taskPriorities: List<TaskPriority>,
@SerialName("task_categories") val taskCategories: List<TaskCategory>,
@SerialName("contractor_specialties") val contractorSpecialties: List<ContractorSpecialty>
)
/**
* Unified seeded data response - all lookups + task templates in one call
* Supports ETag-based conditional fetching for efficient caching
*/
@Serializable
data class SeededDataResponse(
@SerialName("residence_types") val residenceTypes: List<ResidenceType>,
@SerialName("task_categories") val taskCategories: List<TaskCategory>,
@SerialName("task_priorities") val taskPriorities: List<TaskPriority>,
@SerialName("task_frequencies") val taskFrequencies: List<TaskFrequency>,
@SerialName("contractor_specialties") val contractorSpecialties: List<ContractorSpecialty>,
@SerialName("task_templates") val taskTemplates: TaskTemplatesGroupedResponse,
@SerialName("home_profile_options") val homeProfileOptions: Map<String, List<HomeProfileOption>> = emptyMap(),
@SerialName("document_types") val documentTypes: List<HomeProfileOption> = emptyList(),
@SerialName("document_categories") val documentCategories: List<HomeProfileOption> = emptyList()
)
// Legacy wrapper responses for backward compatibility
// These can be removed once all code is migrated to use arrays directly
@Serializable
data class ResidenceTypeResponse(
val count: Int,
val results: List<ResidenceType>
)
@Serializable
data class TaskFrequencyResponse(
val count: Int,
val results: List<TaskFrequency>
)
@Serializable
data class TaskPriorityResponse(
val count: Int,
val results: List<TaskPriority>
)
@Serializable
data class TaskCategoryResponse(
val count: Int,
val results: List<TaskCategory>
)
@Serializable
data class ContractorSpecialtyResponse(
val count: Int,
val results: List<ContractorSpecialty>
)