LCOV - code coverage report
Current view: top level - lib/notifiers - bloc_notifier.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 29 29 100.0 %
Date: 2023-10-11 10:27:27 Functions: 0 0 -

          Line data    Source code
       1             : // ignore_for_file: library_private_types_in_public_api
       2             : 
       3             : import 'dart:async';
       4             : import 'package:meta/meta.dart';
       5             : 
       6             : import 'state_notifier.dart';
       7             : 
       8             : /// A class to allow us implement the BLoC pattern
       9             : abstract class Bloc<Event, State> extends StateNotifier<State> {
      10           1 :   Bloc(super.initialState);
      11             : 
      12             :   final _handlers = <_Handler>[];
      13             : 
      14             :   /// Register an event handler for an event of type `E`.
      15             :   /// There should only ever be one event handler per event type `E`.
      16           1 :   void on<E extends Event>(
      17             :     _HandlerFn<E, State> fn,
      18             :   ) {
      19           5 :     final registered = _handlers.any((handler) => handler.type == E);
      20             :     assert(
      21           1 :       !registered,
      22             :       'on<$E> was called multiple times.', // coverage:ignore-line
      23             :     );
      24           2 :     _handlers.add(
      25           1 :       _Handler(
      26           2 :         isType: (e) => e is E,
      27             :         type: E,
      28             :         fn: fn,
      29             :       ),
      30             :     );
      31             :   }
      32             : 
      33             :   /// Notifies the [Bloc] of a new [event] which triggers
      34             :   /// all corresponding handlers.
      35             :   ///
      36             :   /// * An [AssertionError] will be thrown if there is no event handler
      37             :   /// registered for the incoming [event].
      38           1 :   void add(Event event) {
      39           5 :     final index = _handlers.indexWhere((e) => e.isType(event));
      40           1 :     final eventType = event.runtimeType;
      41             :     assert(
      42           3 :       index != -1,
      43           1 :       'on<$eventType>(...) must be called before add($eventType)',
      44             :     );
      45             : 
      46           3 :     final fn = _handlers[index].fn;
      47           1 :     final emitter = Emitter<State>(
      48           2 :       (newState) => state = newState,
      49             :     );
      50             : 
      51           1 :     final result = fn(event, emitter) as FutureOr<void>;
      52             : 
      53             :     /// disable the emitter after handler has been completed
      54           1 :     if (result is Future) {
      55           1 :       result.then(
      56           2 :         (_) => emitter._disable(),
      57             :       );
      58             :     } else {
      59           1 :       emitter._disable();
      60             :     }
      61             :   }
      62             : 
      63           1 :   @visibleForTesting
      64             :   @override
      65           1 :   set state(State newState) => super.state = newState;
      66             : }
      67             : 
      68             : typedef _HandlerFn<E, State> = FutureOr<void> Function(
      69             :   E event,
      70             :   Emitter<State> emit,
      71             : );
      72             : 
      73             : class _Handler {
      74           1 :   const _Handler({
      75             :     required this.isType,
      76             :     required this.type,
      77             :     required this.fn,
      78             :   });
      79             :   final bool Function(dynamic value) isType;
      80             :   final Type type;
      81             :   final Function fn;
      82             : }
      83             : 
      84             : /// An [Emitter] is a class which is capable of emitting new states.
      85             : class Emitter<State> {
      86           1 :   Emitter(this._updater);
      87             :   final void Function(State newState) _updater;
      88             : 
      89             :   bool _enabled = true;
      90             : 
      91           1 :   void call(State newState) {
      92             :     assert(
      93           1 :       _enabled,
      94             :       '''\n\n
      95             : emit was called after an event handler completed normally.
      96             : This is usually due to an unawaited future in an event handler.
      97             :   **BAD**
      98             :   on<Event>((event, emit) {
      99             :     future.whenComplete(() => emit(...));
     100             :   });
     101             :   **GOOD**
     102             :   on<Event>((event, emit) async {
     103             :     await future.whenComplete(() => emit(...));
     104             :   });
     105             : ''',
     106             :     );
     107           2 :     _updater(newState);
     108             :   }
     109             : 
     110           1 :   void _disable() {
     111           1 :     _enabled = false;
     112             :   }
     113             : }

Generated by: LCOV version 1.16