flutter_streamer 1.0.0 copy "flutter_streamer: ^1.0.0" to clipboard
flutter_streamer: ^1.0.0 copied to clipboard

A pure dart state management class based on standard Dart's Stream.

example/README.md

streamer_example #

The classic counter example to show how it's easy to use the streamer package.

Here we implemented the EASE pattern* with the streamer package.

*We defined Events, Actions, States & Errors classes to handle communication between our Logic class and our View through a stream.

Note: we used flutter_inject to inject our Logic class and stream_listener_widget to handle view's logic (showing dialogs).

main.dart #

    import 'package:flutter/material.dart';
    import 'package:flutter_inject/flutter_inject.dart';
    import 'package:stream_listener_widget/stream_listener_widget.dart';
    import 'package:streamer/streamer.dart';
    

    void main() => runApp(
      const MaterialApp(
        home: CounterView(initialValue: 5),
      ),
    );

    class CounterLogic extends Streamer<CounterIO> {
      int _value;
    
      CounterLogic(this._value) : super(CounterState(_value)) {
        on<Increment>(onIncrement);
        on<Decrement>(onDecrement);
      }
    
      set value(int newValue) {
        if (newValue >= 10) {
          emit(MaxReached());
        } else if (newValue < 0) {
          emit(UnauthorizedValue('A counter under zero is not allowed'));
        }
        _value = newValue;
      }
    
      int get value => _value;
    
      void onIncrement(Increment event) => emit(CounterState(++value));
      void onDecrement(Decrement event) => emit(CounterState(--value));
    }


    class CounterView extends StatelessWidget {
      final int initialValue;
    
      const CounterView({super.key, required this.initialValue});
    
      void _showDialog(BuildContext context, String message) => showDialog(
            context: context,
            barrierDismissible: true,
            builder: (context) {
              return Dialog(
                child: Padding(
                  padding: const EdgeInsets.all(20),
                  child: Text(message),
                ),
              );
            },
          );
    
      void _onMaxReached(BuildContext context) => _showDialog(context, 'Your counter has reached max value');
    
      void _onError(BuildContext context, CounterError event) => _showDialog(context, event.message);
    
      @override
      Widget build(BuildContext context) {
        // Here we use flutter_inject to simply inject view's dependencies (our logic class here)
        // Note that flutter_inject will automatically dispose injected dependencies :D
        return Inject<Streamer<CounterIO>>(
            factory: (context) => CounterLogic(initialValue),
            builder: (context) {
              final streamer = Dependency.get<Streamer<CounterIO>>(context);
              // Here we use stream_listener_widget package to listen stream without rebuilding child widget
              return StreamListener(
                listeners: [
                  (context) => streamer.on<MaxReached>((e) => _onMaxReached(context)),
                  (context) => streamer.on<CounterError>((e) => _onError(context, e)),
                ],
                child: Scaffold(
                  appBar: AppBar(title: const Text('Counter demo')),
                  body: Center(
                    child: StreamBuilder<CounterState>(
                      stream: streamer.select<CounterState>(),
                      builder: (context, snapshot) {
                        if (snapshot.hasError) return Text(snapshot.error.toString());
                        if (!snapshot.hasData) return const CircularProgressIndicator();
                        final state = snapshot.data!;
                        return Text('Counter: ${state.value}');
                      },
                    ),
                  ),
                  floatingActionButton: Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      FloatingActionButton(
                        onPressed: () => streamer.emit(Increment()),
                        child: const Icon(Icons.add),
                      ),
                      FloatingActionButton(
                        onPressed: () => streamer.emit(Decrement()),
                        child: const Icon(Icons.remove),
                      ),
                    ],
                  ),
                ),
              );
            });
      }
    }
    
    /// Here is an example of a simple implementation of the EASE pattern
    ///
    /// Events, States and Errors are always emitted from the Logic class
    /// Actions are always emitted from the View
    ///
    /// Note: to easily test Events equality we could use the freezed package
    ///
    
    /// Events
    sealed class CounterEvent extends CounterIO {}
    
    class MaxReached extends CounterEvent {}
    
    /// Actions
    sealed class CounterAction extends CounterIO {}
    
    class Increment extends CounterAction {}
    
    class Decrement extends CounterAction {}
    
    /// States
    class CounterState extends CounterIO {
      final int value;
      CounterState(this.value);
    }
    
    class Loading extends CounterState {
      Loading(super.value);
    }
    
    /// Errors
    sealed class CounterError extends CounterIO {
      final String message;
    
      CounterError(this.message);
    }
    
    class UnauthorizedValue extends CounterError {
      UnauthorizedValue(super.message);
    }
    
    class UnknownError extends CounterError {
      UnknownError(super.message);
    }
1
likes
0
pub points
36%
popularity

Publisher

unverified uploader

A pure dart state management class based on standard Dart's Stream.

Repository (GitLab)
View/report issues

License

unknown (license)

Dependencies

rxdart

More

Packages that depend on flutter_streamer