import 'package:flutter/material.dart'; import '../data/export_import/seed_label_codec.dart'; import '../data/variety_repository.dart'; import '../di/injector.dart'; import '../i18n/strings.g.dart'; import '../services/label_sheet_service.dart'; import 'quantity_kind_l10n.dart'; /// Opens the print-labels sheet for [entries] (already gathered from the /// current selection): pick a label size, then save a PDF sheet of labels — /// each with a QR that carries the seed's data. Future showLabelPrintSheet( BuildContext context, List entries, ) { return showModalBottomSheet( context: context, isScrollControlled: true, builder: (_) => _LabelPrintSheet(entries: entries), ); } class _LabelPrintSheet extends StatefulWidget { const _LabelPrintSheet({required this.entries}); final List entries; @override State<_LabelPrintSheet> createState() => _LabelPrintSheetState(); } class _LabelPrintSheetState extends State<_LabelPrintSheet> { LabelSheetFormat _format = LabelSheetFormat.stickers; bool _saving = false; @override Widget build(BuildContext context) { final t = context.t; return SafeArea( child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( t.printLabels.title, style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 4), Text( t.printLabels.count(n: widget.entries.length), style: Theme.of(context).textTheme.bodyMedium, ), const SizedBox(height: 8), RadioGroup( groupValue: _format, onChanged: _pick, child: Column( mainAxisSize: MainAxisSize.min, children: [ RadioListTile( key: const Key('printLabels.format.stickers'), value: LabelSheetFormat.stickers, contentPadding: EdgeInsets.zero, title: Text(t.printLabels.formatStickers), subtitle: Text(t.printLabels.formatStickersHint), ), RadioListTile( key: const Key('printLabels.format.cards'), value: LabelSheetFormat.cards, contentPadding: EdgeInsets.zero, title: Text(t.printLabels.formatCards), subtitle: Text(t.printLabels.formatCardsHint), ), ], ), ), const SizedBox(height: 12), Align( alignment: AlignmentDirectional.centerEnd, child: FilledButton.icon( key: const Key('printLabels.save'), onPressed: _saving ? null : _save, icon: const Icon(Icons.save_alt_outlined), label: Text(t.printLabels.save), ), ), ], ), ), ); } void _pick(LabelSheetFormat? value) { if (value != null) setState(() => _format = value); } Future _save() async { final t = context.t; final messenger = ScaffoldMessenger.of(context); final navigator = Navigator.of(context); final rtl = Directionality.of(context) == TextDirection.rtl; setState(() => _saving = true); final labels = [for (final e in widget.entries) _toLabel(t, e)]; final saved = await getIt().saveLabels( labels: labels, format: _format, suggestedName: 'tanemaki-labels-${_today()}.pdf', rtl: rtl, ); navigator.pop(); messenger.showSnackBar( SnackBar( content: Text(saved ? t.printLabels.saved : t.printLabels.cancelled), ), ); } /// Builds one printable label from a [SeedLabelEntry]: the visible fields plus /// the QR payload (structured, so a future scan can read it). LabelSheetLabel _toLabel(Translations t, SeedLabelEntry e) { final origin = _origin(e); final details = [ if (e.harvestYear != null) '${e.harvestYear}', ?origin, if (e.quantity != null) quantityDisplay(t, e.quantity!), ]; return LabelSheetLabel( varietyLabel: e.varietyLabel, commonName: e.commonName, scientificName: e.scientificName, details: details.isEmpty ? null : details.join(' · '), qrData: SeedLabelCodec.encode( SeedLabelData( varietyLabel: e.varietyLabel, scientificName: e.scientificName, commonName: e.commonName, year: e.harvestYear, origin: origin, ), ), ); } String? _origin(SeedLabelEntry e) { final parts = [ if (e.originName != null && e.originName!.trim().isNotEmpty) e.originName!.trim(), if (e.originPlace != null && e.originPlace!.trim().isNotEmpty) e.originPlace!.trim(), ]; return parts.isEmpty ? null : parts.join(' · '); } String _today() => DateTime.now().toIso8601String().substring(0, 10); }