import 'dart:convert'; import 'package:flutter/services.dart' show rootBundle; import 'species_repository.dart'; const _catalogAsset = 'assets/catalog/species.json'; /// Parses the bundled catalog JSON into [SpeciesSeed]s. Kept separate from asset /// loading so it is trivially unit-testable without a Flutter binding. List parseSpeciesCatalog(String jsonString) { final data = jsonDecode(jsonString) as Map; final entries = (data['species'] as List).cast>(); return entries.map((e) { final common = (e['common'] as Map? ?? const {}).map( (lang, names) => MapEntry(lang, (names as List).cast()), ); return SpeciesSeed( scientificName: e['scientific_name'] as String, family: e['family'] as String?, wikidataQid: e['wikidata_qid'] as String?, gbifKey: (e['gbif_key'] as num?)?.toInt(), commonNames: common, viabilityYears: (e['viability_years'] as num?)?.toInt(), ); }).toList(); } /// Loads and parses the bundled species catalog asset. Future> loadBundledSpecies() async { final jsonString = await rootBundle.loadString(_catalogAsset); return parseSpeciesCatalog(jsonString); } /// Version of the bundled catalog, mirrored from the asset's `version` field /// (written by `tool/gen_species_catalog.dart`). A test asserts the two stay in /// sync. The app records the version it last seeded and skips the ~1.5 MB parse /// and the table scan in [SpeciesRepository.seedBundled] on every subsequent /// launch — so bumping this (alongside the asset) is what triggers a one-time /// re-seed after the catalog changes. const int speciesCatalogVersion = 3; /// Reads just the `version` field from a catalog JSON string. Used by the sync /// test to keep [speciesCatalogVersion] aligned with the asset. int parseSpeciesCatalogVersion(String jsonString) => (jsonDecode(jsonString) as Map)['version'] as int;