import 'bloc.dart'; // --- a handler registered on the event BASE -------------------------------- // // `on` with a switch inside handles every subclass. Matching handlers // to dispatches by exact name would report every dispatched subclass as // unhandled (error severity) and the base handler itself as dead. This is the // regression guard for handler coverage following the event hierarchy. sealed class SyncEvent { const SyncEvent(); } class SyncStarted extends SyncEvent { const SyncStarted(); } class SyncCancelled extends SyncEvent { const SyncCancelled(); } /// An intermediate group: `on` covers [RetryNow] only. abstract class RetryEvent extends SyncEvent { const RetryEvent(); } class RetryNow extends RetryEvent { const RetryNow(); } class SyncState { const SyncState(); } class SyncBloc extends Bloc { SyncBloc() : super(const SyncState()); void register() { on((event, emit) { switch (event) { case SyncStarted(): case SyncCancelled(): case RetryEvent(): emit(const SyncState()); } }); } void start() => add(const SyncStarted()); } // A second bloc whose only handler is on an intermediate group, so the rule must // credit dispatches of the group's subclasses to it, and still report a sibling // outside the group. sealed class UploadEvent { const UploadEvent(); } abstract class UploadRetry extends UploadEvent { const UploadRetry(); } class UploadRetryNow extends UploadRetry { const UploadRetryNow(); } /// Dispatched, and outside the handled `UploadRetry` group: truly unhandled. class UploadAbandoned extends UploadEvent { const UploadAbandoned(); } class UploadBloc extends Bloc { UploadBloc() : super(const SyncState()); void register() { on((event, emit) => emit(const SyncState())); } void retry() => add(const UploadRetryNow()); void abandon() => add(const UploadAbandoned()); } // --- two blocs sharing one event type --------------------------------------- // // Keeping only the first owner of an event type ignored the second bloc's // handlers: an event only the second bloc handles was reported unhandled (error // severity), and a dead handler in the second bloc was never seen. sealed class ShareEvent { const ShareEvent(); } class SharePressed extends ShareEvent { const SharePressed(); } class ShareDismissed extends ShareEvent { const ShareDismissed(); } /// Handled only by [ShareBetaBloc], and never dispatched: dead there. class ShareExpired extends ShareEvent { const ShareExpired(); } class ShareAlphaBloc extends Bloc { ShareAlphaBloc() : super(const SyncState()); void register() { on((event, emit) => emit(const SyncState())); } void press() => add(const SharePressed()); } class ShareBetaBloc extends Bloc { ShareBetaBloc() : super(const SyncState()); void register() { on((event, emit) => emit(const SyncState())); on((event, emit) => emit(const SyncState())); } void dismiss() => add(const ShareDismissed()); }