perf(market): paginate Nostr offer discovery, infinite scroll, memory cap
Bound market memory and let large areas page instead of loading everything: - DiscoveryQuery gains an until cursor; OfferTransport gains discoverPage() (one-shot, EOSE-bounded, newest-first) alongside the existing live discover() stream, which now accepts since so it only carries NEW offers going forward. - NostrOfferTransport.discoverPage sorts by created_at desc and derives the next cursor from the oldest event seen (not the oldest type-matched one, so filtering never skips a page). - OffersCubit: discover() fetches the first page + opens a since=now live sub; loadNextPage() pages further back; the in-memory list is capped at 400 offers (each can carry a ~40KB inline photo thumbnail, so unbounded growth in a busy area was a real OOM risk). - market_screen: infinite scroll via a scroll-position trigger + footer spinner, instead of a single unbounded ListView. - Added discoverPage unit tests (commons_core) and cubit pagination tests (first page/cursor, accumulation, cap, cross-page dedup).
This commit is contained in:
parent
3de01bd948
commit
f17ae7751c
9 changed files with 513 additions and 43 deletions
45
apps/app_seeds/test/ui/inventory_list_lazy_test.dart
Normal file
45
apps/app_seeds/test/ui/inventory_list_lazy_test.dart
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tane/ui/inventory_list_screen.dart';
|
||||
|
||||
import '../support/test_support.dart';
|
||||
|
||||
/// The inventory list must render lazily: with a large catalogue only the tiles
|
||||
/// near the viewport are built, not one widget per row. Guards the regression
|
||||
/// from `ListView(children: …)` (every tile built upfront) back in.
|
||||
void main() {
|
||||
testWidgets('builds only the on-screen tiles for a large inventory',
|
||||
(tester) async {
|
||||
final db = newTestDatabase();
|
||||
final repo = newTestRepository(db);
|
||||
// Enough rows that an eager list would build hundreds of tiles at once.
|
||||
for (var i = 0; i < 300; i++) {
|
||||
await repo.addQuickVariety(
|
||||
label: 'Variety ${i.toString().padLeft(3, '0')}',
|
||||
category: i.isEven ? 'Poaceae' : 'Fabaceae',
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapScreen(repository: repo, child: const InventoryListScreen()),
|
||||
);
|
||||
// Let the debounced inventory stream emit and the async load resolve
|
||||
// (bounded pumps — the screen holds a live Drift stream, so pumpAndSettle
|
||||
// would hang; see testing.md).
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 400));
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
// Every variety tile is a ListTile; a lazy list builds only a viewport-worth.
|
||||
final built = find.byType(ListTile).evaluate().length;
|
||||
expect(built, greaterThan(0), reason: 'the list rendered some tiles');
|
||||
expect(
|
||||
built,
|
||||
lessThan(50),
|
||||
reason: 'lazy list should build ~a screenful, not all 300 ($built built)',
|
||||
);
|
||||
|
||||
await disposeTree(tester);
|
||||
await db.close();
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue