diff --git a/flutter/lib/features/inventory/presentation/inventory_edit_screen.dart b/flutter/lib/features/inventory/presentation/inventory_edit_screen.dart index 6cae8638..3fa6e1b4 100644 --- a/flutter/lib/features/inventory/presentation/inventory_edit_screen.dart +++ b/flutter/lib/features/inventory/presentation/inventory_edit_screen.dart @@ -218,6 +218,13 @@ class _InventoryEditScreenState extends ConsumerState { } Future _save() async { + if (_selectedProductId == null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(context.l10n.inventorySelectProduct)), + ); + return; + } + if (!_formKey.currentState!.validate()) return; setState(() => _saving = true); try { diff --git a/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart b/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart index 4c4f91c9..b42dbbf9 100644 --- a/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart +++ b/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart @@ -286,10 +286,12 @@ class _ForegroundTile extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final theme = Theme.of(context); + final location = item.location?.trim(); + final hasLocation = location != null && location.isNotEmpty; final subtitleText = [ '${_fmtQty(item.quantity)} ${item.unit}', - if (item.location != null && item.location!.isNotEmpty) item.location!, + if (hasLocation) location, if (item.bestBeforeDate != null) 'Bäst före: ${_formatDate(item.bestBeforeDate!)}', ].join(' · '); @@ -305,22 +307,50 @@ class _ForegroundTile extends ConsumerWidget { ) : null, title: Text(item.displayName), - // Subtitle: small swipe-hint icon + text on the same row. - subtitle: Row( + // Subtitle: swipe hint + details on first line, category chip below. + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ - if (!selectableMode) ...[ - Icon( - Icons.swap_horiz, - size: 13, - color: theme.colorScheme.outline, - ), - const SizedBox(width: 3), - ], - Expanded( - child: Text( - subtitleText, - overflow: TextOverflow.ellipsis, - ), + Row( + children: [ + if (!selectableMode) ...[ + Icon( + Icons.swap_horiz, + size: 13, + color: theme.colorScheme.outline, + ), + const SizedBox(width: 3), + ], + Expanded( + child: Text( + subtitleText, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + const SizedBox(height: 6), + Row( + children: [ + Flexible( + child: Chip( + label: Text( + 'L1: ${item.l1Category}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + side: BorderSide(color: theme.colorScheme.outlineVariant), + backgroundColor: theme.colorScheme.surface, + labelStyle: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ), + ], ), ], ), diff --git a/flutter/lib/features/pantry/presentation/pantry_screen.dart b/flutter/lib/features/pantry/presentation/pantry_screen.dart index 17eca142..634e6976 100644 --- a/flutter/lib/features/pantry/presentation/pantry_screen.dart +++ b/flutter/lib/features/pantry/presentation/pantry_screen.dart @@ -219,6 +219,9 @@ class _PantryScreenState extends ConsumerState { @override Widget build(BuildContext context) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + final textTheme = theme.textTheme; final pantryAsync = ref.watch(pantryProvider); if (pantryAsync.isLoading) { @@ -370,15 +373,43 @@ class _PantryScreenState extends ConsumerState { if (index == 1) return headerSection; final item = filteredItems[index - 2]; final l1Category = _resolveL1Category(item); + final location = item.location?.trim(); + final hasLocation = location != null && location.isNotEmpty; return ListTile( title: Text(item.displayName), - subtitle: Text( - [ - 'L1: $l1Category', - if (item.location != null && item.location!.trim().isNotEmpty) - 'Plats: ${item.location}', - ].join(' • '), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (hasLocation) + Text( + 'Plats: $location', + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 6), + Row( + children: [ + Flexible( + child: Chip( + label: Text( + 'L1: $l1Category', + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + side: BorderSide(color: colorScheme.outlineVariant), + backgroundColor: colorScheme.surface, + labelStyle: textTheme.bodySmall?.copyWith( + color: colorScheme.onSurfaceVariant, + ), + ), + ), + ], + ), + ], ), trailing: Row( mainAxisSize: MainAxisSize.min,