feat: Add location display and category chips in pantry and inventory screens
Test Suite / test (24.15.0) (push) Has been cancelled

This commit is contained in:
Nils-Johan Gynther
2026-05-11 20:53:11 +02:00
parent 68476142c1
commit 2281df3716
3 changed files with 90 additions and 22 deletions
@@ -218,6 +218,13 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
}
Future<void> _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 {
@@ -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,
),
),
),
],
),
],
),
@@ -219,6 +219,9 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
@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<PantryScreen> {
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,