diff --git a/composeApp/src/main/kotlin/com/github/worn/ui/components/AddItemFields.kt b/composeApp/src/main/kotlin/com/github/worn/ui/components/AddItemFields.kt
index 0357ff3..0b26e16 100644
--- a/composeApp/src/main/kotlin/com/github/worn/ui/components/AddItemFields.kt
+++ b/composeApp/src/main/kotlin/com/github/worn/ui/components/AddItemFields.kt
@@ -543,15 +543,16 @@ internal fun Subcategory.displayName(): String = stringResource(
Subcategory.T_SHIRT -> R.string.subcategory_t_shirt
Subcategory.POLO -> R.string.subcategory_polo
Subcategory.DRESS_SHIRT -> R.string.subcategory_dress_shirt
+ Subcategory.LONG_SLEEVE_SHIRT -> R.string.subcategory_long_sleeve_shirt
Subcategory.HENLEY -> R.string.subcategory_henley
- Subcategory.SWEATER -> R.string.subcategory_sweater
- Subcategory.HOODIE -> R.string.subcategory_hoodie
Subcategory.JEANS -> R.string.subcategory_jeans
Subcategory.CHINOS -> R.string.subcategory_chinos
Subcategory.TAILORED_PANTS -> R.string.subcategory_tailored_pants
Subcategory.SHORTS -> R.string.subcategory_shorts
Subcategory.CARGO_PANTS -> R.string.subcategory_cargo_pants
Subcategory.SWEATPANTS -> R.string.subcategory_sweatpants
+ Subcategory.SWEATER -> R.string.subcategory_sweater
+ Subcategory.HOODIE -> R.string.subcategory_hoodie
Subcategory.BOMBER -> R.string.subcategory_bomber
Subcategory.TRUCKER -> R.string.subcategory_trucker
Subcategory.PUFFER -> R.string.subcategory_puffer
diff --git a/composeApp/src/main/res/values-pt-rBR/strings.xml b/composeApp/src/main/res/values-pt-rBR/strings.xml
index 1330868..ed91133 100644
--- a/composeApp/src/main/res/values-pt-rBR/strings.xml
+++ b/composeApp/src/main/res/values-pt-rBR/strings.xml
@@ -233,15 +233,16 @@
Camiseta
Polo
Camisa social
+ Camisa manga longa
Henley
- Suéter
- Moletom
Jeans
Chinos
Calça social
Bermuda
Calça cargo
Calça de moletom
+ Suéter
+ Moletom
Bomber
Trucker
Puffer
diff --git a/composeApp/src/main/res/values/strings.xml b/composeApp/src/main/res/values/strings.xml
index 6e25f47..34d3db2 100644
--- a/composeApp/src/main/res/values/strings.xml
+++ b/composeApp/src/main/res/values/strings.xml
@@ -233,15 +233,16 @@
T shirt
Polo
Dress shirt
+ Long sleeve shirt
Henley
- Sweater
- Hoodie
Jeans
Chinos
Tailored pants
Shorts
Cargo pants
Sweatpants
+ Sweater
+ Hoodie
Bomber
Trucker
Puffer
diff --git a/iosApp/iosApp/en.lproj/Localizable.strings b/iosApp/iosApp/en.lproj/Localizable.strings
index c4725e3..7223d92 100644
--- a/iosApp/iosApp/en.lproj/Localizable.strings
+++ b/iosApp/iosApp/en.lproj/Localizable.strings
@@ -230,15 +230,16 @@
"subcategory_t_shirt" = "T shirt";
"subcategory_polo" = "Polo";
"subcategory_dress_shirt" = "Dress shirt";
+"subcategory_long_sleeve_shirt" = "Long sleeve shirt";
"subcategory_henley" = "Henley";
-"subcategory_sweater" = "Sweater";
-"subcategory_hoodie" = "Hoodie";
"subcategory_jeans" = "Jeans";
"subcategory_chinos" = "Chinos";
"subcategory_tailored_pants" = "Tailored pants";
"subcategory_shorts" = "Shorts";
"subcategory_cargo_pants" = "Cargo pants";
"subcategory_sweatpants" = "Sweatpants";
+"subcategory_sweater" = "Sweater";
+"subcategory_hoodie" = "Hoodie";
"subcategory_bomber" = "Bomber";
"subcategory_trucker" = "Trucker";
"subcategory_puffer" = "Puffer";
diff --git a/iosApp/iosApp/pt-BR.lproj/Localizable.strings b/iosApp/iosApp/pt-BR.lproj/Localizable.strings
index f6495eb..9c687c0 100644
--- a/iosApp/iosApp/pt-BR.lproj/Localizable.strings
+++ b/iosApp/iosApp/pt-BR.lproj/Localizable.strings
@@ -230,15 +230,16 @@
"subcategory_t_shirt" = "Camiseta";
"subcategory_polo" = "Polo";
"subcategory_dress_shirt" = "Camisa social";
+"subcategory_long_sleeve_shirt" = "Camisa manga longa";
"subcategory_henley" = "Henley";
-"subcategory_sweater" = "Suéter";
-"subcategory_hoodie" = "Moletom";
"subcategory_jeans" = "Jeans";
"subcategory_chinos" = "Chinos";
"subcategory_tailored_pants" = "Calça social";
"subcategory_shorts" = "Bermuda";
"subcategory_cargo_pants" = "Calça cargo";
"subcategory_sweatpants" = "Calça de moletom";
+"subcategory_sweater" = "Suéter";
+"subcategory_hoodie" = "Moletom";
"subcategory_bomber" = "Bomber";
"subcategory_trucker" = "Trucker";
"subcategory_puffer" = "Puffer";
diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts
index d8e3cd8..ded108f 100644
--- a/shared/build.gradle.kts
+++ b/shared/build.gradle.kts
@@ -78,7 +78,7 @@ sqldelight {
databases {
create("WardrobeDatabase") {
packageName.set("com.github.worn.data.source.local.db")
- version = 2
+ version = 3
srcDirs("src/commonMain/sqldelight")
}
}
diff --git a/shared/src/commonMain/kotlin/com/github/worn/data/source/ai/AiPrompts.kt b/shared/src/commonMain/kotlin/com/github/worn/data/source/ai/AiPrompts.kt
index f14ac23..d7aa179 100644
--- a/shared/src/commonMain/kotlin/com/github/worn/data/source/ai/AiPrompts.kt
+++ b/shared/src/commonMain/kotlin/com/github/worn/data/source/ai/AiPrompts.kt
@@ -101,7 +101,7 @@ internal object AiPrompts {
}
}
-private const val SUBCATEGORY_VALUES = "T_SHIRT, POLO, DRESS_SHIRT, HENLEY, SWEATER, HOODIE, " +
- "JEANS, CHINOS, TAILORED_PANTS, SHORTS, CARGO_PANTS, SWEATPANTS, BOMBER, TRUCKER, PUFFER, " +
- "BLAZER, COAT, WINDBREAKER, SNEAKERS, BOOTS_MILITARY, BOOTS_CHELSEA, DERBY, OXFORD, LOAFER, " +
- "SANDALS, WATCH, BELT, SUNGLASSES, HAT_CAP, SCARF, BAG_BACKPACK"
+private const val SUBCATEGORY_VALUES = "T_SHIRT, POLO, DRESS_SHIRT, LONG_SLEEVE_SHIRT, HENLEY, " +
+ "JEANS, CHINOS, TAILORED_PANTS, SHORTS, CARGO_PANTS, SWEATPANTS, SWEATER, HOODIE, BOMBER, " +
+ "TRUCKER, PUFFER, BLAZER, COAT, WINDBREAKER, SNEAKERS, BOOTS_MILITARY, BOOTS_CHELSEA, DERBY, " +
+ "OXFORD, LOAFER, SANDALS, WATCH, BELT, SUNGLASSES, HAT_CAP, SCARF, BAG_BACKPACK"
diff --git a/shared/src/commonMain/kotlin/com/github/worn/domain/model/Subcategory.kt b/shared/src/commonMain/kotlin/com/github/worn/domain/model/Subcategory.kt
index ee1240c..8a8241e 100644
--- a/shared/src/commonMain/kotlin/com/github/worn/domain/model/Subcategory.kt
+++ b/shared/src/commonMain/kotlin/com/github/worn/domain/model/Subcategory.kt
@@ -5,9 +5,8 @@ enum class Subcategory {
T_SHIRT,
POLO,
DRESS_SHIRT,
+ LONG_SLEEVE_SHIRT,
HENLEY,
- SWEATER,
- HOODIE,
// BOTTOM
JEANS,
@@ -18,6 +17,8 @@ enum class Subcategory {
SWEATPANTS,
// OUTERWEAR
+ SWEATER,
+ HOODIE,
BOMBER,
TRUCKER,
PUFFER,
@@ -48,9 +49,8 @@ fun subcategoriesFor(category: Category): List = when (category) {
Subcategory.T_SHIRT,
Subcategory.POLO,
Subcategory.DRESS_SHIRT,
+ Subcategory.LONG_SLEEVE_SHIRT,
Subcategory.HENLEY,
- Subcategory.SWEATER,
- Subcategory.HOODIE,
)
Category.BOTTOM -> listOf(
Subcategory.JEANS,
@@ -61,6 +61,8 @@ fun subcategoriesFor(category: Category): List = when (category) {
Subcategory.SWEATPANTS,
)
Category.OUTERWEAR -> listOf(
+ Subcategory.SWEATER,
+ Subcategory.HOODIE,
Subcategory.BOMBER,
Subcategory.TRUCKER,
Subcategory.PUFFER,
diff --git a/shared/src/commonMain/sqldelight/migrations/2.sqm b/shared/src/commonMain/sqldelight/migrations/2.sqm
new file mode 100644
index 0000000..4bd60d1
--- /dev/null
+++ b/shared/src/commonMain/sqldelight/migrations/2.sqm
@@ -0,0 +1 @@
+UPDATE clothingItem SET category = 'OUTERWEAR' WHERE subcategory IN ('HOODIE', 'SWEATER');
diff --git a/shared/src/commonTest/kotlin/com/github/worn/model/SubcategoryTest.kt b/shared/src/commonTest/kotlin/com/github/worn/model/SubcategoryTest.kt
new file mode 100644
index 0000000..02b54b3
--- /dev/null
+++ b/shared/src/commonTest/kotlin/com/github/worn/model/SubcategoryTest.kt
@@ -0,0 +1,39 @@
+package com.github.worn.model
+
+import com.github.worn.domain.model.Category
+import com.github.worn.domain.model.Subcategory
+import com.github.worn.domain.model.capsuleWardrobeSuggestions
+import com.github.worn.domain.model.subcategoriesFor
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class SubcategoryTest {
+
+ @Test
+ fun `every subcategory belongs to exactly one category`() {
+ val mapped = Category.entries.flatMap { subcategoriesFor(it) }
+
+ assertEquals(mapped.size, mapped.toSet().size, "a subcategory is listed under more than one category")
+ assertEquals(Subcategory.entries.toSet(), mapped.toSet(), "a subcategory is missing from subcategoriesFor()")
+ }
+
+ @Test
+ fun `hoodie and sweater are outerwear`() {
+ val outerwear = subcategoriesFor(Category.OUTERWEAR)
+
+ assertTrue(Subcategory.HOODIE in outerwear)
+ assertTrue(Subcategory.SWEATER in outerwear)
+ }
+
+ @Test
+ fun `capsule wardrobe suggestions pair each subcategory with its own category`() {
+ capsuleWardrobeSuggestions.forEach { suggestion ->
+ val subcategory = suggestion.subcategory ?: return@forEach
+ assertTrue(
+ subcategory in subcategoriesFor(suggestion.mappedCategory),
+ "${suggestion.itemName}: $subcategory is not a ${suggestion.mappedCategory} subcategory",
+ )
+ }
+ }
+}