feat(labels): print seed labels with QR from an inventory selection
Add multi-select to the inventory and a "Print labels" flow that renders a PDF sheet of labels (small stickers or large cards), each carrying the seed's common name, variety, scientific name, year/origin and a tanemaki://seed QR that holds the seed's data offline (future scan-to-import). - SeedLabelCodec: compact, versioned tanemaki://seed URI (encode/decode) - LabelSheetService: pure-Dart PDF grid (pdf + barcode + DejaVu), RTL-aware - VarietyRepository.labelRows: one row per lot, locale-picked common name - InventoryCubit selection mode; contextual app bar + label print sheet - i18n en/es/pt (printLabels.*) Tests: codec, PDF service (both formats + RTL), labelRows, selection cubit, inventory widget selection.
This commit is contained in:
parent
432acded29
commit
efb369eb81
19 changed files with 1465 additions and 116 deletions
|
|
@ -219,4 +219,66 @@ void main() {
|
|||
await disposeTree(tester);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('the label toolbar enters selection and Select all enables print', (
|
||||
tester,
|
||||
) async {
|
||||
final repo = newTestRepository(db);
|
||||
await repo.addQuickVariety(label: 'Tomato', category: 'Solanaceae');
|
||||
await repo.addQuickVariety(label: 'Bean', category: 'Fabaceae');
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapScreen(repository: repo, child: const InventoryListScreen()),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key('inventory.selectLabels')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Nothing picked yet: the count reads zero and print is disabled.
|
||||
expect(find.text('0 selected'), findsOneWidget);
|
||||
expect(
|
||||
tester
|
||||
.widget<IconButton>(find.byKey(const Key('inventory.selection.print')))
|
||||
.onPressed,
|
||||
isNull,
|
||||
);
|
||||
|
||||
await tester.tap(find.byKey(const Key('inventory.selection.selectAll')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('2 selected'), findsOneWidget);
|
||||
expect(
|
||||
tester
|
||||
.widget<IconButton>(find.byKey(const Key('inventory.selection.print')))
|
||||
.onPressed,
|
||||
isNotNull,
|
||||
);
|
||||
|
||||
// Closing the contextual bar leaves selection mode.
|
||||
await tester.tap(find.byKey(const Key('inventory.selection.close')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('inventory.selection.print')), findsNothing);
|
||||
await disposeTree(tester);
|
||||
});
|
||||
|
||||
testWidgets('long-pressing a tile enters selection with it picked', (
|
||||
tester,
|
||||
) async {
|
||||
final repo = newTestRepository(db);
|
||||
await repo.addQuickVariety(label: 'Tomato', category: 'Solanaceae');
|
||||
await repo.addQuickVariety(label: 'Bean', category: 'Fabaceae');
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapScreen(repository: repo, child: const InventoryListScreen()),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.longPress(find.text('Tomato'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('1 selected'), findsOneWidget);
|
||||
expect(find.byType(Checkbox), findsNWidgets(2)); // one per tile
|
||||
await disposeTree(tester);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue