feat(ui): align inventory + detail with mockups (seed icons, green theme)
Visual pass toward docs/mockups (06 inventory, 07 item): - Bundle the seedks icon font (chars a–k → seed pictograms: jar, packet, spoon…) and a SeedGlyph/QuantityKindIcon helper. - Green app bar + pale-green canvas theme (buildTaneTheme). - Inventory list: rounded-square photo thumbnail or green initial avatar, bold title, scientific-name subtitle, trailing edit pencil, styled category headers, rounded search field, seed-glyph empty state. - Quantity selectors (quick-add + add-lot) show the seed pictogram + word; detail lot lines use the kind's glyph. - Detail header restyled to mockup 07: category link + scientific name on the left, photo on the right. watchInventory now also returns the linked species' scientific name (subtitle). 37 app tests green; seedks font verified in the Linux asset bundle.
This commit is contained in:
parent
e41ec9872b
commit
48e9d15772
12 changed files with 329 additions and 49 deletions
|
|
@ -12,6 +12,7 @@ class VarietyListItem extends Equatable {
|
|||
required this.id,
|
||||
required this.label,
|
||||
this.category,
|
||||
this.scientificName,
|
||||
this.photo,
|
||||
});
|
||||
|
||||
|
|
@ -19,11 +20,14 @@ class VarietyListItem extends Equatable {
|
|||
final String label;
|
||||
final String? category;
|
||||
|
||||
/// Scientific name of the linked species, shown as the tile subtitle.
|
||||
final String? scientificName;
|
||||
|
||||
/// First photo (encrypted BLOB) for the avatar, or null → show an initial.
|
||||
final Uint8List? photo;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, label, category, photo];
|
||||
List<Object?> get props => [id, label, category, scientificName, photo];
|
||||
}
|
||||
|
||||
/// One germination test on a lot; [rate] is derived (0..1), null when it can't
|
||||
|
|
@ -154,12 +158,18 @@ class VarietyRepository {
|
|||
]);
|
||||
return query.watch().asyncMap((rows) async {
|
||||
final photos = await _firstPhotosFor(rows.map((v) => v.id).toList());
|
||||
final sciNames = await _scientificNamesFor(
|
||||
rows.map((v) => v.speciesId).whereType<String>().toSet(),
|
||||
);
|
||||
return rows
|
||||
.map(
|
||||
(v) => VarietyListItem(
|
||||
id: v.id,
|
||||
label: v.label,
|
||||
category: v.category,
|
||||
scientificName: v.speciesId == null
|
||||
? null
|
||||
: sciNames[v.speciesId],
|
||||
photo: photos[v.id],
|
||||
),
|
||||
)
|
||||
|
|
@ -189,6 +199,17 @@ class VarietyRepository {
|
|||
return byVariety;
|
||||
}
|
||||
|
||||
/// Maps each of [speciesIds] to its scientific name (one query).
|
||||
Future<Map<String, String>> _scientificNamesFor(
|
||||
Set<String> speciesIds,
|
||||
) async {
|
||||
if (speciesIds.isEmpty) return const {};
|
||||
final rows = await (_db.select(
|
||||
_db.species,
|
||||
)..where((s) => s.id.isIn(speciesIds))).get();
|
||||
return {for (final s in rows) s.id: s.scientificName};
|
||||
}
|
||||
|
||||
/// The 20-second quick-add: a [label] (required) plus an optional [category],
|
||||
/// an optional [quantity] (creates a Lot) and an optional [photoBytes]
|
||||
/// (stored as an encrypted BLOB Attachment). Returns the new Variety id.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue