flutter_bloc_pattern 2.0.0
flutter_bloc_pattern: ^2.0.0 copied to clipboard

Bloc provider. Provides bloc to descendant widget (O(1)), and the bloc is disposed appropriately by state which the bloc_provider holds internally.

flutter_bloc_pattern #

Base class, BLoC provider and rxdart builder for BLoC pattern in Flutter.

Flutter test Pub Pub codecov GitHub Style

Getting Started #

1. Add this to your package's pubspec.yaml file: #

dependencies:
  flutter_bloc_pattern: <latest_version>

2. Now in your Dart code, you can use: #

import 'package:flutter_bloc_pattern/flutter_bloc_pattern.dart';

3. Implements BaseBloc: #

class MyBloc implements BaseBloc {
  Stream<String> get stream;

  @override
  void dispose() {}
}

4. Consume BLoC: #

 final bloc = BlocProvider.of<MyBloc>(context);
 return RxStreamBuilder(
  stream: bloc.stream,
  builder: (context, data) {
    return ...;
  },
);

Example: A port of the standard "Counter Button" example from Flutter #

1. File counter_bloc.dart: #

import 'dart:async';

import 'package:distinct_value_connectable_stream/distinct_value_connectable_stream.dart';
import 'package:flutter_bloc_pattern/flutter_bloc_pattern.dart';
import 'package:rxdart_ext/rxdart_ext.dart';

class CounterBloc extends DisposeCallbackBaseBloc {
  /// Inputs
  final void Function() increment;

  /// Outputs
  final DistinctValueStream<int> state;

  CounterBloc._({
    required void Function() dispose,
    required this.increment,
    required this.state,
  }) : super(dispose);

  factory CounterBloc() {
    // ignore: close_sinks
    final incrementController = StreamController<void>();

    final state = incrementController.stream
        .scan<int>((acc, _, __) => acc! + 1, 0)
        .publishValueDistinct(0);
    final connection = state.connect();

    return CounterBloc._(
      dispose: () async {
        await connection.cancel();
        await incrementController.close();
        print('>>> disposed');
      },
      increment: () => incrementController.add(null),
      state: state,
    );
  }
}

2. File main.dart: #

import 'package:example/bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc_pattern/flutter_bloc_pattern.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter bloc pattern',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: StartPage(),
    );
  }
}

class StartPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: TextButton(
          onPressed: () => Navigator.of(context).push(
            MaterialPageRoute(
              builder: (context) {
                return BlocProvider<CounterBloc>(
                  child: MyHomePage(),
                  initBloc: () => CounterBloc(),
                );
              },
            ),
          ),
          child: Text('GO TO HOME'),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: const <Widget>[
            Text('You have pushed the button this many times:'),
            TextCounter1(),
            TextCounter2(),
          ],
        ),
      ),
      floatingActionButton: const IncrementButton(),
    );
  }
}

class TextCounter1 extends StatelessWidget {
  const TextCounter1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final bloc = BlocProvider.of<CounterBloc>(context);

    return RxStreamBuilder<int>(
      stream: bloc.state,
      builder: (context, data) {
        return Text(
          'COUNTER 1: $data',
          style: Theme.of(context).textTheme.headline4,
        );
      },
    );
  }
}

class TextCounter2 extends StatelessWidget {
  const TextCounter2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final bloc = context.bloc<CounterBloc>();

    return RxStreamBuilder<int>(
      stream: bloc.state,
      builder: (context, data) {
        return Text(
          'COUNTER 2: $data',
          style: Theme.of(context).textTheme.headline4,
        );
      },
    );
  }
}

class IncrementButton extends StatelessWidget {
  const IncrementButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final bloc = context.bloc<CounterBloc>();

    return FloatingActionButton(
      onPressed: bloc.increment,
      tooltip: 'Increment',
      child: Icon(Icons.add),
    );
  }
}
2
likes
130
pub points
72%
popularity

Bloc provider. Provides bloc to descendant widget (O(1)), and the bloc is disposed appropriately by state which the bloc_provider holds internally.

Repository (GitHub)
View/report issues

Documentation

API reference

Uploader

hoc081098@gmail.com

License

MIT (LICENSE)

Dependencies

flutter, flutter_provider, rxdart

More

Packages that depend on flutter_bloc_pattern