feat(app): scan a printed seed label back into its record

Closes the physical↔digital loop the labels opened: the QR on a printed
envelope (tane://seed, already encoded by seed_label_codec) can now be
scanned from the inventory bar. A known label opens its variety; an
unknown one asks before adding anything, then creates the variety (species
linked by exact scientific name when bundled) with a lot carrying the
label's year and origin. Scanner is pure ZXing (zxing_barcode_scanner,
MIT) — no ML Kit, no Play Services, F-Droid-safe, the stack Ğ1nkgo ships.
Mobile-only; other platforms don't show the button (OCR precedent).
The post-scan flow is a plain function (handleScannedPayload) so it's
widget-tested without a camera.
This commit is contained in:
vjrj 2026-07-18 12:26:27 +02:00
parent bb5b3d4a43
commit f1aa8f8e66
18 changed files with 1130 additions and 42 deletions

View file

@ -1987,6 +1987,22 @@ class VarietyRepository {
return id;
}
/// The id of the non-deleted variety whose label matches [label]
/// (case-insensitive, trimmed), or null. This is how a scanned envelope
/// label finds its record: the label IS the identity a keeper printed.
Future<String?> findVarietyIdByLabel(String label) async {
final row =
await (_db.select(_db.varieties)
..where(
(v) =>
v.isDeleted.equals(false) &
v.label.lower().equals(label.trim().toLowerCase()),
)
..limit(1))
.getSingleOrNull();
return row?.id;
}
/// Records how a season went for a lot the optional, skippable answer to
/// "how did it do?" asked when a harvest is noted. Returns the new row id.
Future<String> addGardenOutcome({