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<B extends StateStreamable<S>, S, T> extends SingleChildStatelessWidget { const BlocListenerT({ super.key, required this.selector, required this.listener, }); @override Widget buildWithChild(BuildContext context, Widget? child) { return BlocListener<B, S>( listenWhen: (previous, current) => selector(previous) != selector(current), listener: (context, state) => listener(context, selector(state)), child: child, ); } final BlocWidgetSelector<S, T> 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<State> on Emitter<State> { Future<void> forEachIgnoreError<T>( Stream<T> stream, { required State Function(T data) onData, }) => onEach<T>( stream, onData: (data) => call(onData(data)), onError: (_, __) {}, ); } extension BlocExtension<E, S> on Bloc<E, S> { void safeAdd(E event) { if (!isClosed) { add(event); } } }