feat(ui): Material 3 redesign, cover-photo viewer, About screen

Apply a Material 3 seed-green palette and rounded components across the
home, inventory, quick-add, quantity picker and variety-detail screens.
The full-screen photo viewer can now set any photo as the cover (via
attachment sort order) and delete after confirmation. Lot forms and
packaging surface as choice chips.

Extract About out of Settings into its own screen (app version via
package_info_plus, website link). Add es/en strings for the new lot
types, presentation, home tagline and About. Update Seedees v2 mockups.
This commit is contained in:
vjrj 2026-07-09 11:51:59 +02:00
parent f5c36f2369
commit 42c16c0e3f
24 changed files with 1960 additions and 416 deletions

View file

@ -46,6 +46,7 @@ class Translations with BaseTranslations<AppLocale, Translations> {
late final Translations$photo$en photo = Translations$photo$en.internal(_root);
late final Translations$menu$en menu = Translations$menu$en.internal(_root);
late final Translations$settings$en settings = Translations$settings$en.internal(_root);
late final Translations$about$en about = Translations$about$en.internal(_root);
late final Translations$inventory$en inventory = Translations$inventory$en.internal(_root);
late final Translations$quickAdd$en quickAdd = Translations$quickAdd$en.internal(_root);
late final Translations$detail$en detail = Translations$detail$en.internal(_root);
@ -54,6 +55,7 @@ class Translations with BaseTranslations<AppLocale, Translations> {
late final Translations$addLot$en addLot = Translations$addLot$en.internal(_root);
late final Translations$harvest$en harvest = Translations$harvest$en.internal(_root);
late final Translations$lotType$en lotType = Translations$lotType$en.internal(_root);
late final Translations$presentation$en presentation = Translations$presentation$en.internal(_root);
late final Translations$unit$en unit = Translations$unit$en.internal(_root);
}
@ -104,11 +106,20 @@ class Translations$home$en {
// Translations
/// en: 'Share and grow local seeds'
String get tagline => 'Share and grow local seeds';
/// en: 'Open market'
String get openMarket => 'Open market';
/// en: 'Browse and exchange'
String get openMarketSubtitle => 'Browse and exchange';
/// en: 'Your inventory'
String get yourInventory => 'Your inventory';
/// en: 'Manage your seeds'
String get yourInventorySubtitle => 'Manage your seeds';
}
// Path: photo
@ -124,6 +135,15 @@ class Translations$photo$en {
/// en: 'Choose from gallery'
String get gallery => 'Choose from gallery';
/// en: 'Set as cover'
String get setAsCover => 'Set as cover';
/// en: 'Cover photo'
String get isCover => 'Cover photo';
/// en: 'Delete this photo?'
String get deleteConfirm => 'Delete this photo?';
}
// Path: menu
@ -134,6 +154,9 @@ class Translations$menu$en {
// Translations
/// en: 'your seed bank'
String get tagline => 'your seed bank';
/// en: 'Inventory'
String get inventory => 'Inventory';
@ -181,6 +204,51 @@ class Translations$settings$en {
/// en: 'Local-first, encrypted inventory for traditional seeds. AGPL-3.0.'
String get aboutText => 'Local-first, encrypted inventory for traditional seeds. AGPL-3.0.';
/// en: 'About Tanemaki'
String get aboutOpen => 'About Tanemaki';
}
// Path: about
class Translations$about$en {
Translations$about$en.internal(this._root);
final Translations _root; // ignore: unused_field
// Translations
/// en: 'About'
String get title => 'About';
/// en: '種まき'
String get kanji => '種まき';
/// en: 'A local-first, decentralized app for managing and sharing traditional seeds and seedlings.'
String get tagline => 'A local-first, decentralized app for managing and sharing traditional seeds and seedlings.';
/// en: 'Tanemaki (種まき, "to sow / scatter seeds" in Japanese; short name Tane, 種 "seed") helps people and collectives keep a friendly inventory of their seed bank, decide what they offer, and share it locally — without a central intermediary that could control, censor, or be fined for it. The goal is both practical and political: to support traditional seed varieties and push back against the seed monopoly.'
String get intro => 'Tanemaki (種まき, "to sow / scatter seeds" in Japanese; short name Tane, 種 "seed") helps people and collectives keep a friendly inventory of their seed bank, decide what they offer, and share it locally — without a central intermediary that could control, censor, or be fined for it. The goal is both practical and political: to support traditional seed varieties and push back against the seed monopoly.';
/// en: 'The name honors the old Japanese mutual-aid traditions around rice — yui (shared community labour) and tanomoshi (reciprocity funds) — that inspired the paper Plantare, the "community currency for seed exchange" (BAH-Semillero, 2009, CC-BY-SA). Tanemaki is the digital Plantare.'
String get heritage => 'The name honors the old Japanese mutual-aid traditions around rice — yui (shared community labour) and tanomoshi (reciprocity funds) — that inspired the paper Plantare, the "community currency for seed exchange" (BAH-Semillero, 2009, CC-BY-SA). Tanemaki is the digital Plantare.';
/// en: 'Version'
String get version => 'Version';
/// en: 'License'
String get license => 'License';
/// en: 'AGPL-3.0'
String get licenseValue => 'AGPL-3.0';
/// en: 'Website'
String get website => 'Website';
/// en: 'Open-source licenses'
String get openSourceLicenses => 'Open-source licenses';
/// en: 'Third-party libraries and their licenses'
String get openSourceLicensesSubtitle => 'Third-party libraries and their licenses';
}
// Path: inventory
@ -410,8 +478,50 @@ class Translations$lotType$en {
/// en: 'Seeds'
String get seed => 'Seeds';
/// en: 'Plants'
String get plant => 'Plants';
/// en: 'Plant'
String get plant => 'Plant';
/// en: 'Seedling'
String get seedling => 'Seedling';
/// en: 'Tree / shrub'
String get tree => 'Tree / shrub';
/// en: 'Bulb / tuber'
String get bulb => 'Bulb / tuber';
/// en: 'Cutting'
String get cutting => 'Cutting';
}
// Path: presentation
class Translations$presentation$en {
Translations$presentation$en.internal(this._root);
final Translations _root; // ignore: unused_field
// Translations
/// en: 'Packaging'
String get title => 'Packaging';
/// en: 'Unspecified'
String get none => 'Unspecified';
/// en: 'Pot'
String get pot => 'Pot';
/// en: 'Tray'
String get tray => 'Tray';
/// en: 'Plug'
String get plug => 'Plug';
/// en: 'Bare-root'
String get bareRoot => 'Bare-root';
/// en: 'Root-ball'
String get rootBall => 'Root-ball';
}
// Path: unit
@ -453,6 +563,9 @@ class Translations$unit$en {
late final Translations$unit$plant$en plant = Translations$unit$plant$en.internal(_root);
late final Translations$unit$pot$en pot = Translations$unit$pot$en.internal(_root);
late final Translations$unit$tray$en tray = Translations$unit$tray$en.internal(_root);
late final Translations$unit$seedling$en seedling = Translations$unit$seedling$en.internal(_root);
late final Translations$unit$tree$en tree = Translations$unit$tree$en.internal(_root);
late final Translations$unit$cutting$en cutting = Translations$unit$cutting$en.internal(_root);
late final Translations$unit$grams$en grams = Translations$unit$grams$en.internal(_root);
late final Translations$unit$count$en count = Translations$unit$count$en.internal(_root);
}
@ -742,6 +855,51 @@ class Translations$unit$tray$en {
String get plural => 'trays';
}
// Path: unit.seedling
class Translations$unit$seedling$en {
Translations$unit$seedling$en.internal(this._root);
final Translations _root; // ignore: unused_field
// Translations
/// en: 'seedling'
String get singular => 'seedling';
/// en: 'seedlings'
String get plural => 'seedlings';
}
// Path: unit.tree
class Translations$unit$tree$en {
Translations$unit$tree$en.internal(this._root);
final Translations _root; // ignore: unused_field
// Translations
/// en: 'tree'
String get singular => 'tree';
/// en: 'trees'
String get plural => 'trees';
}
// Path: unit.cutting
class Translations$unit$cutting$en {
Translations$unit$cutting$en.internal(this._root);
final Translations _root; // ignore: unused_field
// Translations
/// en: 'cutting'
String get singular => 'cutting';
/// en: 'cuttings'
String get plural => 'cuttings';
}
// Path: unit.grams
class Translations$unit$grams$en {
Translations$unit$grams$en.internal(this._root);
@ -787,10 +945,17 @@ extension on Translations {
'common.edit' => 'Edit',
'common.type' => 'Type',
'common.comingSoon' => 'Coming soon',
'home.tagline' => 'Share and grow local seeds',
'home.openMarket' => 'Open market',
'home.openMarketSubtitle' => 'Browse and exchange',
'home.yourInventory' => 'Your inventory',
'home.yourInventorySubtitle' => 'Manage your seeds',
'photo.camera' => 'Take a photo',
'photo.gallery' => 'Choose from gallery',
'photo.setAsCover' => 'Set as cover',
'photo.isCover' => 'Cover photo',
'photo.deleteConfirm' => 'Delete this photo?',
'menu.tagline' => 'your seed bank',
'menu.inventory' => 'Inventory',
'menu.market' => 'Market',
'menu.profile' => 'Your profile',
@ -804,6 +969,18 @@ extension on Translations {
'settings.langEn' => 'English',
'settings.about' => 'About',
'settings.aboutText' => 'Local-first, encrypted inventory for traditional seeds. AGPL-3.0.',
'settings.aboutOpen' => 'About Tanemaki',
'about.title' => 'About',
'about.kanji' => '種まき',
'about.tagline' => 'A local-first, decentralized app for managing and sharing traditional seeds and seedlings.',
'about.intro' => 'Tanemaki (種まき, "to sow / scatter seeds" in Japanese; short name Tane, 種 "seed") helps people and collectives keep a friendly inventory of their seed bank, decide what they offer, and share it locally — without a central intermediary that could control, censor, or be fined for it. The goal is both practical and political: to support traditional seed varieties and push back against the seed monopoly.',
'about.heritage' => 'The name honors the old Japanese mutual-aid traditions around rice — yui (shared community labour) and tanomoshi (reciprocity funds) — that inspired the paper Plantare, the "community currency for seed exchange" (BAH-Semillero, 2009, CC-BY-SA). Tanemaki is the digital Plantare.',
'about.version' => 'Version',
'about.license' => 'License',
'about.licenseValue' => 'AGPL-3.0',
'about.website' => 'Website',
'about.openSourceLicenses' => 'Open-source licenses',
'about.openSourceLicensesSubtitle' => 'Third-party libraries and their licenses',
'inventory.title' => 'Inventory',
'inventory.searchHint' => 'Search seeds',
'inventory.empty' => 'No seeds yet. Tap + to add your first.',
@ -863,7 +1040,18 @@ extension on Translations {
'harvest.monthNames.10' => 'November',
'harvest.monthNames.11' => 'December',
'lotType.seed' => 'Seeds',
'lotType.plant' => 'Plants',
'lotType.plant' => 'Plant',
'lotType.seedling' => 'Seedling',
'lotType.tree' => 'Tree / shrub',
'lotType.bulb' => 'Bulb / tuber',
'lotType.cutting' => 'Cutting',
'presentation.title' => 'Packaging',
'presentation.none' => 'Unspecified',
'presentation.pot' => 'Pot',
'presentation.tray' => 'Tray',
'presentation.plug' => 'Plug',
'presentation.bareRoot' => 'Bare-root',
'presentation.rootBall' => 'Root-ball',
'unit.aFew' => 'a few',
'unit.some' => 'some',
'unit.plenty' => 'plenty',
@ -906,6 +1094,12 @@ extension on Translations {
'unit.pot.plural' => 'pots',
'unit.tray.singular' => 'tray',
'unit.tray.plural' => 'trays',
'unit.seedling.singular' => 'seedling',
'unit.seedling.plural' => 'seedlings',
'unit.tree.singular' => 'tree',
'unit.tree.plural' => 'trees',
'unit.cutting.singular' => 'cutting',
'unit.cutting.plural' => 'cuttings',
'unit.grams.singular' => 'gram',
'unit.grams.plural' => 'grams',
'unit.count.singular' => 'seed',