feat(seed-saving): source attribution + advisory note

Record where the guidance comes from (copyright/attribution) and make
clear it is general, not local gospel — kept light:
- seed_saving.json gains a top-level sources list (Seed to Seed / Seed
  Savers Exchange / Organic Seed Alliance); parsed into
  SeedSavingData.sources, exposed via SeedSavingCatalog.sources.
- The detail section shows a small muted footer: an italic 'advisory —
  adapt to your climate' line plus a 'Source: …' credit.
- i18n seedSaving.advisory + sourcePrefix (en/es/pt/ast).
- Tests: asset carries sources; the section renders advisory + credit.
This commit is contained in:
vjrj 2026-07-11 07:52:28 +02:00
parent 4a1e72bc7e
commit 5ecdd1222a
15 changed files with 93 additions and 8 deletions

View file

@ -48,4 +48,9 @@ void main() {
expect(g?.vector, PollinationVector.wind);
expect(g?.recommendedPlants, greaterThanOrEqualTo(50));
});
test('carries source attributions', () {
expect(data.sources, isNotEmpty);
expect(data.sources.map((s) => s.title), contains('Seed to Seed'));
});
}

View file

@ -13,6 +13,7 @@ void main() {
db = newTestDatabase();
SeedSavingCatalog.data = parseSeedSaving('''
{
"sources": [ { "title": "Seed to Seed" } ],
"families": {
"Solanaceae": { "pollination": "self", "isolationMinM": 3, "isolationMaxM": 6, "processing": "wet", "difficulty": "easy" }
},
@ -39,6 +40,9 @@ void main() {
// The pollination line is a Text.rich (label + value), so match the run.
expect(find.textContaining('Self-pollinating'), findsOneWidget);
expect(find.text('Easy'), findsOneWidget); // the difficulty pill
// Advisory note + a light source credit.
expect(find.textContaining('adapt it to your climate'), findsOneWidget);
expect(find.textContaining('Seed to Seed'), findsOneWidget);
await disposeTree(tester);
});