Files
recipe-app/flutter/lib/features/inventory/presentation/inventory_screen.dart
T
Nils-Johan Gynther 967121113e feat: Add inventory management feature with CRUD operations
- Implemented inventory screen to display items with details.
- Added create, edit, and consume inventory screens for managing items.
- Introduced consumption history screen to track item usage.
- Created inventory repository and providers for API interactions.
- Enhanced routing to include inventory-related paths.
- Added necessary models for inventory items and consumption history.
- Integrated error handling and loading states for better user experience.
2026-04-22 08:12:37 +02:00

96 lines
2.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../core/ui/async_state_views.dart';
import '../data/inventory_providers.dart';
import '../domain/inventory_item.dart';
class InventoryScreen extends ConsumerWidget {
const InventoryScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final inventoryAsync = ref.watch(inventoryProvider);
return inventoryAsync.when(
loading: () => const LoadingStateView(label: 'Laddar inventarie...'),
error: (e, _) => ErrorStateView(
message: e.toString(),
onRetry: () => ref.invalidate(inventoryProvider),
),
data: (items) {
if (items.isEmpty) {
return EmptyStateView(
message: 'Inventariet är tomt.',
action: FloatingActionButton.extended(
onPressed: () => context.push('/inventory/create'),
icon: const Icon(Icons.add),
label: const Text('Lägg till'),
),
);
}
return Stack(
children: [
ListView.separated(
padding: const EdgeInsets.only(bottom: 88),
itemCount: items.length,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (context, index) {
final item = items[index];
return _InventoryTile(item: item);
},
),
Positioned(
right: 16,
bottom: 16,
child: FloatingActionButton.extended(
onPressed: () => context.push('/inventory/create'),
icon: const Icon(Icons.add),
label: const Text('Lägg till'),
),
),
],
);
},
);
}
}
class _InventoryTile extends StatelessWidget {
final InventoryItem item;
const _InventoryTile({required this.item});
@override
Widget build(BuildContext context) {
final subtitle = [
'${item.quantity} ${item.unit}',
if (item.location != null && item.location!.isNotEmpty) item.location!,
if (item.bestBeforeDate != null) 'Bäst före: ${_formatDate(item.bestBeforeDate!)}',
].join(' · ');
return ListTile(
title: Text(item.productName),
subtitle: Text(subtitle),
trailing: item.opened
? const Chip(
label: Text('Öppnad'),
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
)
: null,
onTap: () => context.push('/inventory/${item.id}'),
);
}
String _formatDate(String iso) {
try {
final dt = DateTime.parse(iso);
return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')}';
} catch (_) {
return iso;
}
}
}