diff --git a/apps/app_seeds/lib/data/variety_repository.dart b/apps/app_seeds/lib/data/variety_repository.dart index 2377043..b043057 100644 --- a/apps/app_seeds/lib/data/variety_repository.dart +++ b/apps/app_seeds/lib/data/variety_repository.dart @@ -365,6 +365,27 @@ class VarietyRepository { return triggers.asyncMap((_) => _loadInventory()); } + /// The whole inventory screen in one reactive subscription: the catalogued + /// list and the draft tray, from a single [StreamGroup]. The cubit MUST use + /// this rather than subscribing to [watchInventory] and [watchDrafts] + /// separately — two overlapping StreamGroups (both watching `attachments`) + /// re-emit in a tight loop that starves the event loop and hangs widget + /// tests' `pumpAndSettle`. + Stream<({List items, List drafts})> + watchInventoryView() { + final triggers = StreamGroup.merge([ + (_db.select( + _db.varieties, + )..where((v) => v.isDeleted.equals(false))).watch().map((_) {}), + _db.select(_db.attachments).watch().map((_) {}), + _db.select(_db.species).watch().map((_) {}), + _db.select(_db.lots).watch().map((_) {}), + ]); + return triggers.asyncMap( + (_) async => (items: await _loadInventory(), drafts: await _loadDrafts()), + ); + } + Future> _loadInventory() async { final rows = await (_db.select(_db.varieties) diff --git a/apps/app_seeds/lib/state/inventory_cubit.dart b/apps/app_seeds/lib/state/inventory_cubit.dart index f539880..4908312 100644 --- a/apps/app_seeds/lib/state/inventory_cubit.dart +++ b/apps/app_seeds/lib/state/inventory_cubit.dart @@ -121,17 +121,20 @@ class InventoryState extends Equatable { /// automatically after a quick-add — no manual refresh. class InventoryCubit extends Cubit { InventoryCubit(this._repo) : super(const InventoryState()) { - _sub = _repo.watchInventory().listen( - (items) => emit(state.copyWith(items: items, loading: false)), - ); - _draftsSub = _repo.watchDrafts().listen( - (drafts) => emit(state.copyWith(drafts: drafts)), + // One combined subscription (list + draft tray). Two separate StreamGroups + // here re-emit in a loop that hangs widget tests — see watchInventoryView. + _sub = _repo.watchInventoryView().listen( + (view) => emit( + state.copyWith(items: view.items, drafts: view.drafts, loading: false), + ), ); } final VarietyRepository _repo; - late final StreamSubscription> _sub; - late final StreamSubscription> _draftsSub; + late final StreamSubscription< + ({List items, List drafts}) + > + _sub; void search(String query) => emit(state.copyWith(query: query)); @@ -171,7 +174,6 @@ class InventoryCubit extends Cubit { @override Future close() async { await _sub.cancel(); - await _draftsSub.cancel(); return super.close(); } }