import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/single_child_widget.dart'; mixin BlocLogger { String? get tag => null; bool Function(dynamic currentState, dynamic nextState)? get shouldLog => null; } class BlocListenerT, S, T> extends SingleChildStatelessWidget { const BlocListenerT({ super.key, required this.selector, required this.listener, }); @override Widget buildWithChild(BuildContext context, Widget? child) { return BlocListener( listenWhen: (previous, current) => selector(previous) != selector(current), listener: (context, state) => listener(context, selector(state)), child: child, ); } final BlocWidgetSelector selector; final void Function(BuildContext context, T state) listener; } /// Wrap around a string such that two strings with the same value will fail /// the identical check class StateMessage { StateMessage(this.value); final String value; } extension EmitterExtension on Emitter { Future forEachIgnoreError( Stream stream, { required State Function(T data) onData, }) => onEach( stream, onData: (data) => call(onData(data)), onError: (_, __) {}, ); } extension BlocExtension on Bloc { void safeAdd(E event) { if (!isClosed) { add(event); } } }