import 'dart:io'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../l10n/app_localizations.dart'; import '../l10n/app_localizations_helpers.dart'; import '../utils/money.dart'; import '../utils/navigation.dart'; import '../viewmodels/product_list_view_model.dart'; import '../viewmodels/remote_sync_view_model.dart'; import 'widgets/managed_on_website_notice.dart'; class ProductListView extends StatefulWidget { const ProductListView({super.key}); @override State createState() => _ProductListViewState(); } class _ProductListViewState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().ensureLoaded(); }); } @override Widget build(BuildContext context) { final viewModel = context.watch(); final l10n = AppLocalizations.of(context); // A paired tablet gets its products from the website final managedOnWebsite = context.watch().isConfigured; return Scaffold( appBar: AppBar( leading: IconButton( onPressed: () => context.popOrGo('/admin'), icon: const Icon(Icons.arrow_back), ), title: Text(l10n.products), ), resizeToAvoidBottomInset: false, floatingActionButton: managedOnWebsite ? null : FloatingActionButton.extended( onPressed: () => context.push('/products/new'), icon: const Icon(Icons.add), label: Text(l10n.addProduct), ), body: Builder( builder: (context) { if (viewModel.isLoading) { return const Center(child: CircularProgressIndicator()); } if (viewModel.loadError != null) { return Center(child: Text(l10n.errorText(viewModel.loadError))); } if (viewModel.products.isEmpty && !managedOnWebsite) { return Center(child: Text(l10n.noProductsYet)); } // The notice takes the first row final offset = managedOnWebsite ? 1 : 0; return ListView.separated( padding: const EdgeInsets.all(16), itemCount: viewModel.products.length + offset, separatorBuilder: (_, _) => const SizedBox(height: 8), itemBuilder: (context, index) { if (index < offset) return const ManagedOnWebsiteNotice(); final product = viewModel.products[index - offset]; return Card( child: ListTile( leading: SizedBox( width: 56, height: 56, child: Center( child: product.imagePath != null && product.imagePath!.isNotEmpty ? Image.file( File(product.imagePath!), fit: BoxFit.contain, cacheWidth: 112, errorBuilder: (context, error, stackTrace) => const Icon( Icons.image_not_supported_outlined, ), ) : const Icon(Icons.image_not_supported_outlined), ), ), title: Text(product.name), subtitle: Text( product.infiniteStock ? l10n.productInfiniteStockSummary( l10n.categoryLabel(product.category), product.priceInCents.asEuro, ) : l10n.productStockSummary( l10n.categoryLabel(product.category), product.priceInCents.asEuro, product.stockQuantity, ), ), trailing: const Icon(Icons.chevron_right), onTap: () => context.push('/products/${product.id}/edit'), ), ); }, ); }, ), ); } }