feat(app): show each batch's story as a composite timeline
The Movement log (history + provenance DAG) was recorded but invisible. A new history sheet on every lot tile narrates the batch: movements, germination tests, storage checks and how it entered the collection (origin attached), most-recent first. Two one-tap chips record 'sown today' / 'harvested today' — the first UI door to the sown/harvested movement types. No schema change; one-shot reads only (no live subscriptions in a transient sheet).
This commit is contained in:
parent
11cbdf3022
commit
92fd84590b
10 changed files with 835 additions and 2 deletions
103
apps/app_seeds/test/ui/lot_history_sheet_test.dart
Normal file
103
apps/app_seeds/test/ui/lot_history_sheet_test.dart
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tane/db/database.dart';
|
||||
import 'package:tane/db/enums.dart';
|
||||
|
||||
import '../support/test_support.dart';
|
||||
|
||||
void main() {
|
||||
late AppDatabase db;
|
||||
|
||||
setUp(() => db = newTestDatabase());
|
||||
tearDown(() => db.close());
|
||||
|
||||
testWidgets('the lot tile opens the batch story, closed by its origin', (
|
||||
tester,
|
||||
) async {
|
||||
final repo = newTestRepository(db);
|
||||
final id = await repo.addQuickVariety(label: 'Maize');
|
||||
final lotId = await repo.addLot(
|
||||
varietyId: id,
|
||||
originName: 'María',
|
||||
originPlace: 'Aiako',
|
||||
);
|
||||
await repo.addGerminationTest(
|
||||
lotId: lotId,
|
||||
sampleSize: 10,
|
||||
germinatedCount: 9,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapDetail(
|
||||
repository: repo,
|
||||
varietyId: id,
|
||||
species: newTestSpeciesRepository(db),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(Key('lot.history.$lotId')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// The story: germination test (90%) first, creation-with-origin last.
|
||||
expect(find.text('Germination test — 90%'), findsOneWidget);
|
||||
expect(find.text('Added to your collection'), findsOneWidget);
|
||||
expect(find.text('From María · Aiako'), findsOneWidget);
|
||||
await disposeTree(tester);
|
||||
});
|
||||
|
||||
testWidgets('one tap records sown today and it shows up in the story', (
|
||||
tester,
|
||||
) async {
|
||||
final repo = newTestRepository(db);
|
||||
final id = await repo.addQuickVariety(label: 'Maize');
|
||||
final lotId = await repo.addLot(varietyId: id);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapDetail(
|
||||
repository: repo,
|
||||
varietyId: id,
|
||||
species: newTestSpeciesRepository(db),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(Key('lot.history.$lotId')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key('history.sowToday')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// One-shot .get() (NOT watch().first — hangs under the fake-async clock).
|
||||
final movements = await db.select(db.movements).get();
|
||||
expect(movements.single.type, MovementType.sown);
|
||||
expect(movements.single.lotId, lotId);
|
||||
expect(movements.single.occurredOn, isNotNull);
|
||||
|
||||
// And the story refreshed to show it.
|
||||
expect(find.text('Sown'), findsOneWidget);
|
||||
await disposeTree(tester);
|
||||
});
|
||||
|
||||
testWidgets('a plant lot offers harvest but not sowing', (tester) async {
|
||||
final repo = newTestRepository(db);
|
||||
final id = await repo.addQuickVariety(label: 'Rosemary');
|
||||
final lotId = await repo.addLot(varietyId: id, type: LotType.plant);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapDetail(
|
||||
repository: repo,
|
||||
varietyId: id,
|
||||
species: newTestSpeciesRepository(db),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(Key('lot.history.$lotId')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('history.sowToday')), findsNothing);
|
||||
expect(find.byKey(const Key('history.harvestToday')), findsOneWidget);
|
||||
await disposeTree(tester);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue