import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../data/variety_repository.dart'; import '../db/database.dart'; import '../db/enums.dart'; import '../i18n/strings.g.dart'; import 'sale_sheet.dart'; import 'theme.dart'; /// The Sales screen — a local ledger of seed sold or bought, in any currency. /// A model separate from a gift or a Plantare. Reads the encrypted inventory DB. class SalesScreen extends StatelessWidget { const SalesScreen({super.key}); @override Widget build(BuildContext context) { final t = context.t; final repo = context.read(); return Scaffold( appBar: AppBar(title: Text(t.sale.title)), floatingActionButton: FloatingActionButton.extended( key: const Key('sales.add'), onPressed: () => showSaleSheet(context, repository: repo), icon: const Icon(Icons.add), label: Text(t.sale.add), ), body: StreamBuilder>( stream: repo.watchSales(), builder: (context, snapshot) { final sales = snapshot.data; if (sales == null) { return const Center(child: CircularProgressIndicator()); } if (sales.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.all(32), child: Text( t.sale.empty, textAlign: TextAlign.center, style: const TextStyle(color: seedMuted, fontSize: 15), ), ), ); } return ListView.separated( padding: const EdgeInsets.only(bottom: 88), itemCount: sales.length, separatorBuilder: (_, _) => const Divider(height: 1), itemBuilder: (context, i) => _SaleTile(sales[i], repo), ); }, ), ); } } class _SaleTile extends StatelessWidget { const _SaleTile(this.s, this.repo); final Sale s; final VarietyRepository repo; String _money() { final amount = s.amount; if (amount == null) return s.currency?.trim() ?? ''; // Drop a trailing .0 so "5.0 €" reads "5 €". final n = amount == amount.roundToDouble() ? amount.toInt().toString() : amount.toString(); return [n, s.currency?.trim()].where((e) => e != null && e.isNotEmpty).join(' '); } @override Widget build(BuildContext context) { final t = context.t; final iSold = s.direction == SaleDirection.iSold; final money = _money(); final date = MaterialLocalizations.of(context) .formatShortDate(DateTime.fromMillisecondsSinceEpoch(s.soldOn)); final subtitle = [ iSold ? t.sale.iSold : t.sale.iBought, if (s.counterparty?.trim().isNotEmpty ?? false) s.counterparty!.trim(), date, ].join(' · '); return ListTile( leading: Icon( iSold ? Icons.sell_outlined : Icons.shopping_bag_outlined, color: seedGreen, ), title: Text( money.isEmpty ? (s.note?.trim().isNotEmpty ?? false ? s.note!.trim() : (iSold ? t.sale.iSold : t.sale.iBought)) : money, style: const TextStyle(fontWeight: FontWeight.w600), ), subtitle: Text(subtitle, maxLines: 2, overflow: TextOverflow.ellipsis), trailing: PopupMenuButton( key: Key('sale.menu.${s.id}'), onSelected: (v) { if (v == 'delete') repo.deleteSale(s.id); }, itemBuilder: (context) => [PopupMenuItem(value: 'delete', child: Text(t.sale.delete))], ), ); } }