feat(db): lot presentation + attachment sort order (schema v4→v5)
Expand LotType from {seed, plant} to six append-only forms (seed,
seedling, plant, tree, bulb, cutting) and add an optional Presentation
attribute (pot/tray/plug/bareRoot/rootBall) kept separate from quantity
so 'how many' and 'in what packaging' never conflate.
Add attachments.sortOrder so the cover photo is the lowest-ordered one,
enabling reordering from the full-screen viewer. Expand QuantityKind
with the new plant-aware forms.
Migrations are additive (v1→v5 all covered by migration_test); enum
values are stored by name and appended only, keeping CRDT sync safe.
This commit is contained in:
parent
06aed2a586
commit
3954c62aa6
16 changed files with 6174 additions and 32 deletions
|
|
@ -67,6 +67,7 @@ class VarietyLot extends Equatable {
|
|||
this.harvestYear,
|
||||
this.harvestMonth,
|
||||
this.quantity,
|
||||
this.presentation,
|
||||
this.storageLocation,
|
||||
this.germinationTests = const [],
|
||||
});
|
||||
|
|
@ -78,6 +79,9 @@ class VarietyLot extends Equatable {
|
|||
/// Optional harvest month (1..12). Only meaningful when [harvestYear] is set.
|
||||
final int? harvestMonth;
|
||||
final Quantity? quantity;
|
||||
|
||||
/// How living material is packaged (pot, tray, bare-root…); null for seeds.
|
||||
final Presentation? presentation;
|
||||
final String? storageLocation;
|
||||
final List<GerminationEntry> germinationTests;
|
||||
|
||||
|
|
@ -92,6 +96,7 @@ class VarietyLot extends Equatable {
|
|||
harvestYear,
|
||||
harvestMonth,
|
||||
quantity,
|
||||
presentation,
|
||||
storageLocation,
|
||||
germinationTests,
|
||||
];
|
||||
|
|
@ -252,13 +257,18 @@ class VarietyRepository {
|
|||
) async {
|
||||
if (varietyIds.isEmpty) return const {};
|
||||
final rows =
|
||||
await (_db.select(_db.attachments)..where(
|
||||
(a) =>
|
||||
a.parentId.isIn(varietyIds) &
|
||||
a.parentType.equalsValue(ParentType.variety) &
|
||||
a.kind.equalsValue(AttachmentKind.photo) &
|
||||
a.isDeleted.equals(false),
|
||||
))
|
||||
await (_db.select(_db.attachments)
|
||||
..where(
|
||||
(a) =>
|
||||
a.parentId.isIn(varietyIds) &
|
||||
a.parentType.equalsValue(ParentType.variety) &
|
||||
a.kind.equalsValue(AttachmentKind.photo) &
|
||||
a.isDeleted.equals(false),
|
||||
)
|
||||
..orderBy([
|
||||
(a) => OrderingTerm(expression: a.sortOrder),
|
||||
(a) => OrderingTerm(expression: a.createdAt),
|
||||
]))
|
||||
.get();
|
||||
final byVariety = <String, Uint8List>{};
|
||||
for (final row in rows) {
|
||||
|
|
@ -431,7 +441,10 @@ class VarietyRepository {
|
|||
a.kind.equalsValue(AttachmentKind.photo) &
|
||||
a.isDeleted.equals(false),
|
||||
)
|
||||
..orderBy([(a) => OrderingTerm(expression: a.createdAt)]))
|
||||
..orderBy([
|
||||
(a) => OrderingTerm(expression: a.sortOrder),
|
||||
(a) => OrderingTerm(expression: a.createdAt),
|
||||
]))
|
||||
.get();
|
||||
|
||||
final links =
|
||||
|
|
@ -527,6 +540,7 @@ class VarietyRepository {
|
|||
int? harvestYear,
|
||||
int? harvestMonth,
|
||||
Quantity? quantity,
|
||||
Presentation? presentation,
|
||||
String? storageLocation,
|
||||
}) async {
|
||||
final (created, updated) = _stamp();
|
||||
|
|
@ -546,6 +560,7 @@ class VarietyRepository {
|
|||
quantityKind: Value(quantity?.kind.name),
|
||||
quantityPrecise: Value(quantity?.count?.toDouble()),
|
||||
quantityLabel: Value(quantity?.label),
|
||||
presentation: Value(presentation),
|
||||
storageLocation: Value(storageLocation),
|
||||
),
|
||||
);
|
||||
|
|
@ -560,6 +575,7 @@ class VarietyRepository {
|
|||
int? harvestYear,
|
||||
int? harvestMonth,
|
||||
Quantity? quantity,
|
||||
Presentation? presentation,
|
||||
String? storageLocation,
|
||||
}) async {
|
||||
final (_, updated) = _stamp();
|
||||
|
|
@ -571,6 +587,7 @@ class VarietyRepository {
|
|||
quantityKind: Value(quantity?.kind.name),
|
||||
quantityPrecise: Value(quantity?.count?.toDouble()),
|
||||
quantityLabel: Value(quantity?.label),
|
||||
presentation: Value(presentation),
|
||||
storageLocation: Value(storageLocation),
|
||||
updatedAt: Value(updated),
|
||||
lastAuthor: Value(nodeId),
|
||||
|
|
@ -666,6 +683,34 @@ class VarietyRepository {
|
|||
);
|
||||
}
|
||||
|
||||
/// Makes [attachmentId] the cover (preferred) attachment of [varietyId] by
|
||||
/// giving it a [sortOrder] below every current sibling. The cover is what the
|
||||
/// inventory list shows as the avatar and the detail gallery shows first.
|
||||
Future<void> setPreferredPhoto(String varietyId, String attachmentId) async {
|
||||
final siblings =
|
||||
await (_db.select(_db.attachments)..where(
|
||||
(a) =>
|
||||
a.parentId.equals(varietyId) &
|
||||
a.parentType.equalsValue(ParentType.variety) &
|
||||
a.isDeleted.equals(false),
|
||||
))
|
||||
.get();
|
||||
var minOrder = 0;
|
||||
for (final a in siblings) {
|
||||
if (a.sortOrder < minOrder) minOrder = a.sortOrder;
|
||||
}
|
||||
final (_, updated) = _stamp();
|
||||
await (_db.update(
|
||||
_db.attachments,
|
||||
)..where((a) => a.id.equals(attachmentId))).write(
|
||||
AttachmentsCompanion(
|
||||
sortOrder: Value(minOrder - 1),
|
||||
updatedAt: Value(updated),
|
||||
lastAuthor: Value(nodeId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Adds an external link (URL, optional title) to a variety. Returns its id.
|
||||
Future<String> addExternalLink(
|
||||
String varietyId,
|
||||
|
|
@ -756,6 +801,7 @@ class VarietyRepository {
|
|||
type: l.type,
|
||||
harvestYear: l.harvestYear,
|
||||
harvestMonth: l.harvestMonth,
|
||||
presentation: l.presentation,
|
||||
storageLocation: l.storageLocation,
|
||||
germinationTests: germinationTests,
|
||||
quantity: hasQuantity
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue