Commit graph

7 commits

Author SHA1 Message Date
a534c14983 refactor(branding): rename app Tanemaki → Tane
Public name is now Tane (種, "seed"); Tanemaki (種まき, "to scatter seeds")
is kept only as etymology in the About screen and onboarding.

App not yet distributed, so format tokens rename cleanly with no migration:
backup extension .tanemaki→.tane, QR scheme tanemaki://→tane://, file
prefixes tane-*. Website link and species-catalog User-Agent →
tane.comunes.org. Android label capitalised to "Tane".

Identity/crypto constants already use org.comunes.tane (derivation, HKDF
backup, sync namespace, TANE1 recovery tag) — left untouched, so keys,
backups and sync are unaffected. Tests updated; analyze + full suite green.
2026-07-12 13:04:16 +02:00
bf091bf852 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.
2026-07-10 19:14:04 +02:00
2ea8d67cb4 fix(sync): re-seed HLC clock from stored rows so local edits win LWW
The repository clock started fresh at Hlc.zero on every launch and was
never re-seeded from the database. After a restart, if the device wall
clock lagged behind stamps already stored (e.g. rows imported from a
peer whose clock ran ahead), a local edit was stamped *older* than the
row it edited and silently lost last-writer-wins — so lot changes made
on one device did not update when the backup was imported on another.

Re-seed the clock lazily from the newest stored `updatedAt` before the
first local stamp of the session, mirroring what importInventory already
does with the incoming max. _stamp() is now async.

Tests: add a lot-level LWW re-import test (the variety case was covered,
the lot case was not) and a restart-regression test that reproduces the
lagging-wall-clock scenario.
2026-07-10 02:06:01 +02:00
e3ec855630 style: dart format reflow (no behavior change) 2026-07-09 22:19:43 +02:00
6809dc6143 feat(inventory): photo-first drafts + on-device OCR (digitization R2+R4)
Lower the bulk-digitization cliff with two more routes on top of the
already-landed CSV import and "save and add another":

- Photo-first drafts (capture now, catalogue later): burst-capture
  photos (camera or multi-gallery) into unnamed draft varieties, shown
  in a "to catalogue" tray, hidden from the main list until named.
  Adds Variety.isDraft (schema), addDraftVariety/watchDrafts/nameDraft,
  the triage sheet and the inventory banner.
- On-device OCR label suggestion (Tesseract, offline, no Google): a
  "Suggest name from photo" button in the naming dialog behind a
  LabelTextExtractor interface (Tesseract on Android/iOS, no-op
  elsewhere). Reads the largest print via hOCR bounding boxes, drops
  boilerplate/low-confidence noise, preprocesses (grayscale, contrast,
  upscale) and sweeps rotations (0-315 deg) so tilted packets still
  read. Bundles tessdata_fast eng+spa; validated on-device against real
  packets. The photo is written to a temp file deleted immediately in a
  finally block (the plugin needs a path) - a bounded, documented
  exception to no-plaintext-at-rest.

This commit also carries the co-developed schema evolution v5 to v8 that
shares these files (organic flag, species viability years, crop
calendar, lot provenance/abundance/preservation format, condition
checks) plus their exports/migrations and i18n.

Tests: CSV/draft/OCR unit + widget + migration green in isolation.
Note: the full widget suite currently hangs (>10 min) - under investigation.
2026-07-09 21:23:46 +02:00
89b61bc9e4 feat(inventory): additive CSV import for bulk digitization
Import a spreadsheet list (the same 21-column schema the CSV export
already produces) as new varieties/lots. Tolerant reader: columns
matched by header name in any order, only variety_label required,
unknown enums fall back to a safe default, rows sharing variety_id
collapse into one variety with several lots. Species re-linked by
scientific name. Additive by design (fresh ids + HLC), so it never
overwrites existing rows; JSON stays the canonical id-reconciling import.

Adds a hand-rolled RFC 4180 parser (no new dependency), an importCsv
path in VarietyRepository/ExportImportService, an 'Import from CSV'
tile in the backup section, and en/es strings.

Note: i18n .g.dart also carries pre-existing About/intro strings from
the working tree (regenerated by slang).
2026-07-09 14:41:28 +02:00
2812c99280 feat(inventory): CSV/JSON export and JSON import with LWW reconciliation
Interchange export/import for Phase 1 (data-model §7):

- JSON: canonical, versioned envelope (formatVersion 1) with all sync
  metadata verbatim, photos embedded as base64, tombstones excluded.
  Species are re-resolved on import by scientific name (catalog ids are
  per-install). Reader tolerates unknown fields/enum values (§5.2) and
  rejects newer format versions with a clear error.
- CSV: export-only spreadsheet flatten, one row per lot, RFC 4180
  escaping, never any photo bytes.
- Import merges by UUIDv7 id in one transaction: insert-if-unknown
  preserving original stamps, last-writer-wins by packed HLC for known
  mutable rows, append-only movements; afterwards the local clock
  receiveEvent()s the newest imported stamp so it never runs behind.
- Settings gains a Backup section (export CSV/JSON, import JSON with
  confirmation); file dialogs behind a FileService interface backed by
  file_picker (MIT).
- Tests: codec round-trip and tolerance, reconciler LWW, repository
  export→import round-trip (fresh DB, idempotent re-import, newer-local
  wins, clock monotonicity, species re-resolution), backup widget flows.
2026-07-09 12:46:53 +02:00