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.
50 lines
2.5 KiB
Dart
50 lines
2.5 KiB
Dart
import 'package:commons_core/commons_core.dart';
|
|
|
|
import '../i18n/strings.g.dart';
|
|
|
|
/// Singular + plural label for a [QuantityKind]. For uncountable *vibe* kinds
|
|
/// (a few, some…) both are the same word.
|
|
(String, String) _unit(Translations t, QuantityKind kind) => switch (kind) {
|
|
QuantityKind.aFew => (t.unit.aFew, t.unit.aFew),
|
|
QuantityKind.some => (t.unit.some, t.unit.some),
|
|
QuantityKind.plenty => (t.unit.plenty, t.unit.plenty),
|
|
QuantityKind.pinch => (t.unit.pinch, t.unit.pinch),
|
|
QuantityKind.handful => (t.unit.handful.singular, t.unit.handful.plural),
|
|
QuantityKind.teaspoon => (t.unit.teaspoon.singular, t.unit.teaspoon.plural),
|
|
QuantityKind.spoon => (t.unit.spoon.singular, t.unit.spoon.plural),
|
|
QuantityKind.cup => (t.unit.cup.singular, t.unit.cup.plural),
|
|
QuantityKind.jar => (t.unit.jar.singular, t.unit.jar.plural),
|
|
QuantityKind.sack => (t.unit.sack.singular, t.unit.sack.plural),
|
|
QuantityKind.packet => (t.unit.packet.singular, t.unit.packet.plural),
|
|
QuantityKind.cob => (t.unit.cob.singular, t.unit.cob.plural),
|
|
QuantityKind.pod => (t.unit.pod.singular, t.unit.pod.plural),
|
|
QuantityKind.ear => (t.unit.ear.singular, t.unit.ear.plural),
|
|
QuantityKind.head => (t.unit.head.singular, t.unit.head.plural),
|
|
QuantityKind.fruit => (t.unit.fruit.singular, t.unit.fruit.plural),
|
|
QuantityKind.bulb => (t.unit.bulb.singular, t.unit.bulb.plural),
|
|
QuantityKind.tuber => (t.unit.tuber.singular, t.unit.tuber.plural),
|
|
QuantityKind.seedHead => (t.unit.seedHead.singular, t.unit.seedHead.plural),
|
|
QuantityKind.bunch => (t.unit.bunch.singular, t.unit.bunch.plural),
|
|
QuantityKind.plant => (t.unit.plant.singular, t.unit.plant.plural),
|
|
QuantityKind.pot => (t.unit.pot.singular, t.unit.pot.plural),
|
|
QuantityKind.tray => (t.unit.tray.singular, t.unit.tray.plural),
|
|
QuantityKind.grams => (t.unit.grams.singular, t.unit.grams.plural),
|
|
QuantityKind.count => (t.unit.count.singular, t.unit.count.plural),
|
|
};
|
|
|
|
/// The unit's singular name — for chips/scale items ("cob", "packet").
|
|
String unitLabel(Translations t, QuantityKind kind) => _unit(t, kind).$1;
|
|
|
|
/// A full, human quantity: "3 cobs", "2 packets", "a few".
|
|
String quantityDisplay(Translations t, Quantity q) {
|
|
final n = q.count;
|
|
final (one, other) = _unit(t, q.kind);
|
|
if (!q.kind.countable || n == null) {
|
|
// Vibe amount, or a countable unit with no number → bare unit name.
|
|
return (n != null && n != 1) ? other : one;
|
|
}
|
|
return '${_formatCount(n)} ${n == 1 ? one : other}';
|
|
}
|
|
|
|
String _formatCount(num n) =>
|
|
n == n.roundToDouble() ? n.toInt().toString() : n.toString();
|