feat(inventory): local sharing — per-lot share terms, filter and printable catalog

The local half of the original Fase 2 (no network, no Offer entity yet):
- Lot sheet gains a 'do you share it?' choice (gift/swap first, sale last,
  never the default); declaring plenty of abundance reveals it with a nudge.
- Lot lines and list tiles badge shared batches; an 'I share' filter and
  a printable PDF catalog (paper bridge for fairs) round out the view.
- Catalog PDF embeds DejaVu (Latin-ext/Cyrillic/Greek); fonts are a
  per-locale resource like the OCR packs.
This commit is contained in:
vjrj 2026-07-09 22:19:55 +02:00
parent e3ec855630
commit ba87bf2719
20 changed files with 982 additions and 36 deletions

View file

@ -229,6 +229,20 @@
"enoughForMe": "Enough for me",
"runningLow": "Running low"
},
"share": {
"add": "Do you share it?",
"title": "Do you share it?",
"nudge": "You have plenty — you could share some.",
"private": "Just for me",
"gift": "To give away",
"exchange": "To swap",
"sell": "For sale",
"filterChip": "I share",
"printCatalog": "Print what I share",
"catalogTitle": "What I share",
"catalogSaved": "Catalog saved",
"cancelled": "Cancelled"
},
"cropCalendar": {
"add": "Crop calendar",
"title": "Crop calendar",

View file

@ -229,6 +229,20 @@
"enoughForMe": "Suficiente para mí",
"runningLow": "Queda poca"
},
"share": {
"add": "¿La compartes?",
"title": "¿La compartes?",
"nudge": "Tienes de sobra: podrías compartir un poco.",
"private": "Solo para mí",
"gift": "Para regalar",
"exchange": "Para intercambiar",
"sell": "En venta",
"filterChip": "Comparto",
"printCatalog": "Imprimir lo que comparto",
"catalogTitle": "Lo que comparto",
"catalogSaved": "Catálogo guardado",
"cancelled": "Cancelado"
},
"cropCalendar": {
"add": "Calendario de cultivo",
"title": "Calendario de cultivo",

View file

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 2
/// Strings: 530 (265 per locale)
/// Strings: 554 (277 per locale)
///
/// Built on 2026-07-09 at 17:18 UTC
/// Built on 2026-07-09 at 20:14 UTC
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import

View file

@ -62,6 +62,7 @@ class Translations with BaseTranslations<AppLocale, Translations> {
late final Translations$presentation$en presentation = Translations$presentation$en.internal(_root);
late final Translations$provenance$en provenance = Translations$provenance$en.internal(_root);
late final Translations$abundance$en abundance = Translations$abundance$en.internal(_root);
late final Translations$share$en share = Translations$share$en.internal(_root);
late final Translations$cropCalendar$en cropCalendar = Translations$cropCalendar$en.internal(_root);
late final Translations$needsReproduction$en needsReproduction = Translations$needsReproduction$en.internal(_root);
late final Translations$preservation$en preservation = Translations$preservation$en.internal(_root);
@ -765,6 +766,51 @@ class Translations$abundance$en {
String get runningLow => 'Running low';
}
// Path: share
class Translations$share$en {
Translations$share$en.internal(this._root);
final Translations _root; // ignore: unused_field
// Translations
/// en: 'Do you share it?'
String get add => 'Do you share it?';
/// en: 'Do you share it?'
String get title => 'Do you share it?';
/// en: 'You have plenty — you could share some.'
String get nudge => 'You have plenty — you could share some.';
/// en: 'Just for me'
String get private => 'Just for me';
/// en: 'To give away'
String get gift => 'To give away';
/// en: 'To swap'
String get exchange => 'To swap';
/// en: 'For sale'
String get sell => 'For sale';
/// en: 'I share'
String get filterChip => 'I share';
/// en: 'Print what I share'
String get printCatalog => 'Print what I share';
/// en: 'What I share'
String get catalogTitle => 'What I share';
/// en: 'Catalog saved'
String get catalogSaved => 'Catalog saved';
/// en: 'Cancelled'
String get cancelled => 'Cancelled';
}
// Path: cropCalendar
class Translations$cropCalendar$en {
Translations$cropCalendar$en.internal(this._root);
@ -1588,6 +1634,18 @@ extension on Translations {
'abundance.enoughToShare' => 'Enough to share a little',
'abundance.enoughForMe' => 'Enough for me',
'abundance.runningLow' => 'Running low',
'share.add' => 'Do you share it?',
'share.title' => 'Do you share it?',
'share.nudge' => 'You have plenty — you could share some.',
'share.private' => 'Just for me',
'share.gift' => 'To give away',
'share.exchange' => 'To swap',
'share.sell' => 'For sale',
'share.filterChip' => 'I share',
'share.printCatalog' => 'Print what I share',
'share.catalogTitle' => 'What I share',
'share.catalogSaved' => 'Catalog saved',
'share.cancelled' => 'Cancelled',
'cropCalendar.add' => 'Crop calendar',
'cropCalendar.title' => 'Crop calendar',
'cropCalendar.sow' => 'Sow',

View file

@ -61,6 +61,7 @@ class TranslationsEs extends Translations with BaseTranslations<AppLocale, Trans
@override late final _Translations$presentation$es presentation = _Translations$presentation$es._(_root);
@override late final _Translations$provenance$es provenance = _Translations$provenance$es._(_root);
@override late final _Translations$abundance$es abundance = _Translations$abundance$es._(_root);
@override late final _Translations$share$es share = _Translations$share$es._(_root);
@override late final _Translations$cropCalendar$es cropCalendar = _Translations$cropCalendar$es._(_root);
@override late final _Translations$needsReproduction$es needsReproduction = _Translations$needsReproduction$es._(_root);
@override late final _Translations$preservation$es preservation = _Translations$preservation$es._(_root);
@ -442,6 +443,27 @@ class _Translations$abundance$es extends Translations$abundance$en {
@override String get runningLow => 'Queda poca';
}
// Path: share
class _Translations$share$es extends Translations$share$en {
_Translations$share$es._(TranslationsEs root) : this._root = root, super.internal(root);
final TranslationsEs _root; // ignore: unused_field
// Translations
@override String get add => '¿La compartes?';
@override String get title => '¿La compartes?';
@override String get nudge => 'Tienes de sobra: podrías compartir un poco.';
@override String get private => 'Solo para mí';
@override String get gift => 'Para regalar';
@override String get exchange => 'Para intercambiar';
@override String get sell => 'En venta';
@override String get filterChip => 'Comparto';
@override String get printCatalog => 'Imprimir lo que comparto';
@override String get catalogTitle => 'Lo que comparto';
@override String get catalogSaved => 'Catálogo guardado';
@override String get cancelled => 'Cancelado';
}
// Path: cropCalendar
class _Translations$cropCalendar$es extends Translations$cropCalendar$en {
_Translations$cropCalendar$es._(TranslationsEs root) : this._root = root, super.internal(root);
@ -1078,6 +1100,18 @@ extension on TranslationsEs {
'abundance.enoughToShare' => 'Bastante, para compartir con moderación',
'abundance.enoughForMe' => 'Suficiente para mí',
'abundance.runningLow' => 'Queda poca',
'share.add' => '¿La compartes?',
'share.title' => '¿La compartes?',
'share.nudge' => 'Tienes de sobra: podrías compartir un poco.',
'share.private' => 'Solo para mí',
'share.gift' => 'Para regalar',
'share.exchange' => 'Para intercambiar',
'share.sell' => 'En venta',
'share.filterChip' => 'Comparto',
'share.printCatalog' => 'Imprimir lo que comparto',
'share.catalogTitle' => 'Lo que comparto',
'share.catalogSaved' => 'Catálogo guardado',
'share.cancelled' => 'Cancelado',
'cropCalendar.add' => 'Calendario de cultivo',
'cropCalendar.title' => 'Calendario de cultivo',
'cropCalendar.sow' => 'Siembra',