import 'dart:async'; import 'bloc.dart'; // --- state union --------------------------------------------------------- abstract class ItemState {} class ItemLoading extends ItemState {} class ItemLoaded extends ItemState {} class ItemError extends ItemState {} // --- events -------------------------------------------------------------- abstract class ItemEvent {} class LoadItems extends ItemEvent {} class LoadItemsSafely extends ItemEvent {} // --- bloc ---------------------------------------------------------------- class ItemBloc extends Bloc { ItemBloc() : super(ItemLoaded()); /// Two swallowed catches in ONE method: the loading state is in flight and /// neither catch resolves it. They must be two distinct findings, which is why /// this rule's identity carries the catch position. Future twoSwallowedAwaits() async { emit(ItemLoading()); try { await Future.delayed(Duration.zero); } catch (error) { // swallowed } try { await Future.delayed(Duration.zero); } catch (error) { // swallowed too } } void register() { // BAD: a loading state is emitted, the awaited call fails, and the catch // neither emits a terminal state nor rethrows, so the spinner sticks. on((event, emit) async { emit(ItemLoading()); try { await Future.delayed(Duration.zero); emit(ItemLoaded()); } catch (error) { // swallowed on purpose: this is the bug pipe must find. } }); // GOOD: the catch resolves the loading state. on((event, emit) async { emit(ItemLoading()); try { await Future.delayed(Duration.zero); emit(ItemLoaded()); } catch (error) { emit(ItemError()); } }); // GOOD: deliberate graceful degradation that leaves no loading state // outstanding and does not concern the user. on((event, emit) async { try { await Future.delayed(Duration.zero); } catch (_) { // best-effort call; nothing was in flight for the user. } }); } }