Rework quantities the way seeds are actually described — a number of an informal
unit — and let a lot hold seeds or plants (plantel).
Quantity model (commons_core):
- Quantity is now { kind, count?, label } — "3 cobs", "2 packets", "a few".
Count is optional; uncountable vibes (a few, some, pinch) carry no number.
- QuantityKind reorganised into an ascending scale: vibes → containers
(teaspoon/spoon/cup/jar/sack) → seed & fruit forms → plant units, each tagged
countable/not. Stored by name; count reuses the existing numeric column.
Lot type (schema v2):
- Lots gain a `type` (seed | plant); germination stays meaningful for seeds.
schemaVersion 2 with a from1To2 migration (adds the column), drift_schema_v2
exported, migration test covers v1→v2.
UI:
- New QuantityPicker: a horizontal scale of large seed-glyph icons + a number
stepper (shown only for countable units), plus a seed/plant SegmentedButton.
Used in quick-add and add-lot. Lot lines render "3 cobs" / "a few".
- i18n: unit singular/plural (ES/EN, Weblate-friendly), lot-type labels.
Build: slang moved to its CLI (disabled in build_runner to avoid a multi-file
collision); CI runs `dart run slang` before build_runner. 38 tests green,
Linux migrates the existing v1 DB and runs.
94 lines
3 KiB
Dart
94 lines
3 KiB
Dart
import 'package:commons_core/commons_core.dart';
|
||
import 'package:flutter/material.dart';
|
||
|
||
/// Renders a glyph from the bundled `seedks` icon font, whose characters `a`–`k`
|
||
/// map to seed-themed pictograms (jar, packet, spoon…). See
|
||
/// docs/mockups/seedks-glyphs.png.
|
||
class SeedGlyph extends StatelessWidget {
|
||
const SeedGlyph(this.char, {this.size = 24, this.color, super.key});
|
||
|
||
final String char;
|
||
final double size;
|
||
final Color? color;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Text(
|
||
char,
|
||
style: TextStyle(
|
||
fontFamily: 'seedks',
|
||
fontSize: size,
|
||
height: 1,
|
||
color: color ?? Theme.of(context).colorScheme.primary,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// Named seedks glyphs (the character each pictogram is mapped to).
|
||
abstract final class SeedGlyphs {
|
||
static const jar = 'a';
|
||
static const jars = 'b';
|
||
static const search = 'c';
|
||
static const share = 'd';
|
||
static const sack = 'e';
|
||
static const smallSpoon = 'f';
|
||
static const bigSpoon = 'g';
|
||
static const mug = 'h';
|
||
static const envelope = 'i';
|
||
static const pouring = 'j';
|
||
static const scattered = 'k';
|
||
}
|
||
|
||
/// The seedks character for a quantity [kind], or null for plant-form/precise
|
||
/// kinds that have no seed pictogram (they fall back to a Material icon).
|
||
String? seedGlyphForKind(QuantityKind kind) => switch (kind) {
|
||
QuantityKind.aFew => SeedGlyphs.scattered,
|
||
QuantityKind.some => SeedGlyphs.smallSpoon,
|
||
QuantityKind.plenty => SeedGlyphs.jars,
|
||
QuantityKind.pinch => SeedGlyphs.scattered,
|
||
QuantityKind.handful => SeedGlyphs.bigSpoon,
|
||
QuantityKind.teaspoon => SeedGlyphs.smallSpoon,
|
||
QuantityKind.spoon => SeedGlyphs.bigSpoon,
|
||
QuantityKind.cup => SeedGlyphs.mug,
|
||
QuantityKind.jar => SeedGlyphs.jar,
|
||
QuantityKind.sack => SeedGlyphs.sack,
|
||
QuantityKind.packet => SeedGlyphs.envelope,
|
||
_ => null,
|
||
};
|
||
|
||
IconData _materialIconForKind(QuantityKind kind) => switch (kind) {
|
||
QuantityKind.grams => Icons.scale_outlined,
|
||
QuantityKind.count => Icons.tag,
|
||
QuantityKind.cob || QuantityKind.ear => Icons.grass,
|
||
QuantityKind.head || QuantityKind.seedHead => Icons.filter_vintage_outlined,
|
||
QuantityKind.fruit => Icons.local_florist_outlined,
|
||
QuantityKind.plant => Icons.local_florist_outlined,
|
||
QuantityKind.pot => Icons.yard_outlined,
|
||
QuantityKind.tray => Icons.grid_on_outlined,
|
||
QuantityKind.bulb ||
|
||
QuantityKind.tuber ||
|
||
QuantityKind.bunch => Icons.spa_outlined,
|
||
_ => Icons.eco_outlined,
|
||
};
|
||
|
||
/// A consistent icon for a [QuantityKind]: the seed glyph where one exists,
|
||
/// otherwise a Material fallback.
|
||
class QuantityKindIcon extends StatelessWidget {
|
||
const QuantityKindIcon(this.kind, {this.size = 24, this.color, super.key});
|
||
|
||
final QuantityKind kind;
|
||
final double size;
|
||
final Color? color;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final glyph = seedGlyphForKind(kind);
|
||
if (glyph != null) return SeedGlyph(glyph, size: size, color: color);
|
||
return Icon(
|
||
_materialIconForKind(kind),
|
||
size: size,
|
||
color: color ?? Theme.of(context).colorScheme.primary,
|
||
);
|
||
}
|
||
}
|