From 96f0d7cd9f24aa39d261a58bb05984070ae08a9c Mon Sep 17 00:00:00 2001 From: Joao Victor Sena Date: Sat, 8 Aug 2026 09:20:07 -0300 Subject: [PATCH 1/3] fix: drop the item name from the outfit selection grid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The label was drawn on top of the garment photo, so on a 100dp cell it sat over the image with no line limit — long names covered the whole photo and were unreadable either way. The cell is now the photo alone; each cell still exposes the item name as its content description / accessibility label, so screen readers are unaffected. Adds an outfit_item_cell test tag / accessibility identifier so journeys can target the cells, matching clothing_card and outfit_card. Closes #44 Co-Authored-By: Claude Opus 5 (1M context) --- .../com/github/worn/ui/screen/CreateOutfitSheet.kt | 11 +++-------- iosApp/iosApp/Screens/CreateOutfitSheet.swift | 13 +++---------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/composeApp/src/main/kotlin/com/github/worn/ui/screen/CreateOutfitSheet.kt b/composeApp/src/main/kotlin/com/github/worn/ui/screen/CreateOutfitSheet.kt index 0e230ee..1074c4a 100644 --- a/composeApp/src/main/kotlin/com/github/worn/ui/screen/CreateOutfitSheet.kt +++ b/composeApp/src/main/kotlin/com/github/worn/ui/screen/CreateOutfitSheet.kt @@ -229,7 +229,8 @@ private fun ItemSelectionGrid( private val cellShape = RoundedCornerShape(16.dp) - +// The cell is the photo alone: a name label here only ever sat on top of the garment, where it was +// unreadable. The photo carries the item's name as its content description for screen readers. @Composable private fun SelectableItemCell( item: ClothingItem, @@ -241,6 +242,7 @@ private fun SelectableItemCell( modifier = modifier .fillMaxWidth() .height(100.dp) + .testTag("outfit_item_cell") .clip(cellShape) .border( width = if (isSelected) 2.dp else 1.dp, @@ -250,13 +252,6 @@ private fun SelectableItemCell( .clickable(onClick = onClick), ) { ItemThumbnail(item = item) - Text( - text = item.name, - color = WornColors.TextPrimary, - fontSize = 10.sp, - fontWeight = FontWeight.Medium, - modifier = Modifier.align(Alignment.BottomStart).padding(start = 12.dp, bottom = 8.dp), - ) SelectionIndicator(isSelected = isSelected, size = 20.dp, iconSize = 12.dp, modifier = Modifier.padding(8.dp)) } } diff --git a/iosApp/iosApp/Screens/CreateOutfitSheet.swift b/iosApp/iosApp/Screens/CreateOutfitSheet.swift index a639261..2d572ac 100644 --- a/iosApp/iosApp/Screens/CreateOutfitSheet.swift +++ b/iosApp/iosApp/Screens/CreateOutfitSheet.swift @@ -121,6 +121,8 @@ private struct SelectableItemCell: View { let isSelected: Bool let onTap: () -> Void + // The cell is the photo alone: a name label here only ever sat on top of the garment, where it + // was unreadable. The photo carries the item's name as its accessibility label. var body: some View { ZStack(alignment: .topLeading) { StoredPhotoImage(path: item.photoPath) { placeholderIcon } @@ -139,18 +141,9 @@ private struct SelectableItemCell: View { SelectionIndicator(isSelected: isSelected, size: 20, iconSize: 10) .padding(8) - - VStack { - Spacer() - Text(item.name) - .font(.system(size: 10, weight: .medium)) - .foregroundColor(WornColors.textPrimary) - .padding(.horizontal, 12) - .padding(.bottom, 8) - .frame(maxWidth: .infinity, alignment: .leading) - } } .frame(height: 100) + .accessibilityIdentifier("outfit_item_cell") .onTapGesture(perform: onTap) } From 5e4a5009c1f9049e4665af1abc48fa4d53449731 Mon Sep 17 00:00:00 2001 From: Joao Victor Sena Date: Sat, 8 Aug 2026 09:20:08 -0300 Subject: [PATCH 2/3] fix: cap the wardrobe card name at two lines AI-generated names run long; unbounded, a four-line name pushed the category row down and left the card misaligned with its neighbour in the grid row. Co-Authored-By: Claude Opus 5 (1M context) --- .../kotlin/com/github/worn/ui/components/ClothingCard.kt | 5 +++++ iosApp/iosApp/Components/ClothingCard.swift | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/composeApp/src/main/kotlin/com/github/worn/ui/components/ClothingCard.kt b/composeApp/src/main/kotlin/com/github/worn/ui/components/ClothingCard.kt index 52d96f0..f238329 100644 --- a/composeApp/src/main/kotlin/com/github/worn/ui/components/ClothingCard.kt +++ b/composeApp/src/main/kotlin/com/github/worn/ui/components/ClothingCard.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -107,6 +108,10 @@ private fun ItemInfo(item: ClothingItem) { color = WornColors.TextPrimary, fontSize = 14.sp, fontWeight = FontWeight.Medium, + // AI-generated names can run long; left unbounded they push the category row down and + // misalign the cards next to them in the grid row. + maxLines = 2, + overflow = TextOverflow.Ellipsis, ) Row( verticalAlignment = Alignment.CenterVertically, diff --git a/iosApp/iosApp/Components/ClothingCard.swift b/iosApp/iosApp/Components/ClothingCard.swift index c3f5b25..02d2a29 100644 --- a/iosApp/iosApp/Components/ClothingCard.swift +++ b/iosApp/iosApp/Components/ClothingCard.swift @@ -45,9 +45,13 @@ struct ClothingCard: View { private var itemInfo: some View { VStack(alignment: .leading, spacing: 2) { + // AI-generated names can run long; left unbounded they push the category row down and + // misalign the cards next to them in the grid row. Text(item.name) .font(.system(size: 14, weight: .medium)) .foregroundColor(WornColors.textPrimary) + .lineLimit(2) + .truncationMode(.tail) HStack(spacing: 6) { Circle() From db3d28f6c8de34e54e73e5185ea6f6263668f850 Mon Sep 17 00:00:00 2001 From: Joao Victor Sena Date: Sat, 8 Aug 2026 09:20:09 -0300 Subject: [PATCH 3/3] test: add an outfit item grid journey Covers the Create-outfit selection grid: photo-only cells with no name text over the garment, and selection on tap. Unlike the other journeys it needs a populated wardrobe, so the fresh-install precondition note now points at each journey's own description. Co-Authored-By: Claude Opus 5 (1M context) --- journeys/README.md | 6 ++++-- journeys/outfit-item-grid.xml | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 journeys/outfit-item-grid.xml diff --git a/journeys/README.md b/journeys/README.md index 50531f8..592e974 100644 --- a/journeys/README.md +++ b/journeys/README.md @@ -20,8 +20,9 @@ disambiguate. ## Preconditions -These journeys assume a **fresh install**: an empty wardrobe, no saved outfits, and no credentials -configured (neither the Claude API key nor YouCam try-on credentials, and no saved model photo). +Except where a journey's own `` says otherwise — `outfit-item-grid.xml` needs a +populated wardrobe — these journeys assume a **fresh install**: an empty wardrobe, no saved outfits, +and no credentials configured (neither the Claude API key nor YouCam try-on credentials, and no saved model photo). That state exercises the empty-state and locked flows without needing a real photo, network access, or credentials. Journeys that would require capturing a photo or calling an external API stop at the point where that external input is needed and verify the UI is in the expected state. @@ -72,6 +73,7 @@ described above are unavailable on this path, so fall back to the visible text a | `remove-background.xml` | Verify the Add-item "Remove background" toggle is gated on a photo being present (absent until one is chosen). | | `crop-photo.xml` | Verify the Add-item "Crop" button is gated on a photo being present (absent until one is chosen). | | `create-first-outfit.xml` | From the empty Outfits tab, open the Create-outfit sheet. | +| `outfit-item-grid.xml` | Verify the Create-outfit item grid shows photo-only cells and selects on tap. Needs a populated wardrobe. | | `connect-api-key.xml` | Open Settings and reach the Claude API key entry sheet. | | `connect-youcam.xml` | Open Settings and reach the YouCam try-on credentials sheet. | | `edit-profile.xml` | Open Settings and reach the Your-Profile sheet with its chip groups. | diff --git a/journeys/outfit-item-grid.xml b/journeys/outfit-item-grid.xml new file mode 100644 index 0000000..0064f87 --- /dev/null +++ b/journeys/outfit-item-grid.xml @@ -0,0 +1,30 @@ + + + Opens the Create-outfit sheet over a populated wardrobe and verifies the item selection grid + shows photo-only cells with no name text over the garment, and that tapping a cell selects + it. Start state: the wardrobe contains at least two items, one with a long name. + + + + Tap the "OUTFITS" tab in the bottom navigation bar. + + + Tap the "Create" button in the Outfits screen header. + + + Verify the "Create outfit" sheet is shown with an "Outfit name (optional)" field and a + "Select items" section. + + + Verify each item in the selection grid shows only its photo and a selection indicator, + with no item name text drawn over the photo. + + + Tap the first item in the selection grid. + + + Verify the "Select items" header shows "1 selected" and the tapped item shows a filled + selection indicator. + + +