{"componentChunkName":"component---src-templates-lesson-post-js","path":"/lesson/using-stream-builders-with-blocs","result":{"data":{"strapiLesson":{"id":"Lesson_95","author":{"email":"eric@ericwindmill.com","username":"Eric Windmill","twitter":"ericwindmill"},"content":"Now, it's time to jump into some Flutter specific code, where we can consume the `TodoListBloc` data with a `StreamBuilder` widget.  Specifically, let's start by looking at the `TodoList` widget that I made for that project.\n\n<img src=\"images/calendar_app/calendar_app_todo_list_annotation.png\" alt=\"calendar app\" style=\"width:500px;border-radius: 0\"/>\n\n### Bloc code reminder\n\nHere's the bloc code that we care about, as a reminder before we dive into the Flutter code.\n\n```dart\nimport 'dart:async';\n\nimport 'package:calendar_app_repository/calendar_app_repository.dart';\nimport 'package:rxdart/rxdart.dart';\n\nclass TodoListBloc {\n  final TodoRepository _repository;\n\n  TodoListBloc(this._repository) {\n    // ...\n  }\n\n  // inputs\n  void toggleTaskComplete(Task todo) async {\n    final toggled = todo.toggleComplete();\n    // the output of this bloc will emit a new stream event\n    // when the [_repository] is finished.\n    return await _repository.updateTodo(toggled);\n  }\n\n  BehaviorSubject<DateTime> selectedDateControllerSink = BehaviorSubject<DateTime>();\n  BehaviorSubject<List<Task>> tasksForDate = BehaviorSubject<List<Task>>();\n\n  // outputs\n  // NB:  This is the output that we care about in this example\n  Stream<List<Task>> get todos {\n    return _repository.todos;\n  }\n\n  Stream<DateTime> get selectedDate => selectedDateControllerSink.stream;\n\n  void dispose() {\n    selectedDateControllerSink.close();\n  }\n}\n```\n\n### Adding a StreamBuilder\n\n`StreamBuilder` is a widget that knows to re-build and re-render each time a stream it's listening to emits a new event. You'll tell it what stream to listen to, and what widgets to build when that stream is updated. Using a `StreamBuilder` will be familiar is you know the `builder` pattern used in Flutter. \n\n<div class=\"aside\">\nAs a recap, `builder` is a pattern on many Flutter widgets that allow you to use a callback to create widgets, rather than the standard means of passing a widget to `Widget.child` in the build method. \n</div>\n\n```dart\nimport 'package:blocs_without_libraries/app/bloc_provider.dart';\nimport 'package:calandar_app_ui/widgets/widgets.dart';\nimport 'package:calendar_app_repository/calendar_app_repository.dart';\nimport 'package:flutter/material.dart';\n\nclass TodoList extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    // Grab a reference to the bloc using the bloc provider\n    final bloc = BlocProvider.of(context).todoListBloc;\n\n    // return a StreamBuilder\n    // which requires a `builder` callback to be passed in\n    // as well as `stream` to listen to\n    // The type declaration on StreamBuilder is used to tell \n    // it what type of data to expect from the Stream\n    return StreamBuilder<List<Task>>(\n      // pass it the `todos` stream on the bloc\n      stream: bloc.todos,\n      // Builder callback will be passed the BuildContext,\n      // as well as an [AsyncSnapshot], which is _current_ data\n      // emitted from the Stream (in this case a List of Tasks\n      builder: (BuildContext context, AsyncSnapshot snapshot) {\n        // If there isn't any data, return early to prevent the app from crashing\n        if (!snapshot.hasData) return Center(child: CircularProgressIndicator());\n  \n        // ListView.builder is another widget that relies on the builder pattern\n        return ListView.builder(\n          // `snapshot.data` is the actual List<Task> object from the stream.\n          itemCount: snapshot.data.length,\n          // `itemBuilder` is required, and should return a widget \n          // that's used created for each iteration of the `ListView.builder`\n          // the index that's passed in to this callback will be increased with\n          // each iteration\n          itemBuilder: (BuildContext context, int index) {\n            // grab a reference to the task for brevity\n            // remember that the `snapshot.data` is a list of todos.\n            Task todo = snapshot.data[index];\n            // now we can finally use the task object itself\n            // which we're getting from the Bloc.todos stream.\n            return TodoListTile(\n              task: todo,\n              onCheckboxToggle: (bool v) => bloc.toggleTaskComplete(todo),\n              onRefreshed: () => bloc.refreshTaskDate(todo),\n            );\n          },\n        );\n      },\n    );\n  }\n}\n```\n\n`StreamBuilder` is used several times in this app. You can find many more examples in the <a href=\"https://github.com/ericwindmill/flutter_by_example/tree/master/examples/calendar_app/blocs_without_libraries/lib\">source code</a>.","updated_at":"Saturday, 25th of July, 2020","slug":"using-stream-builders-with-blocs","strapiId":95,"title":"Using StreamBuilders with blocs","tutorial":{"category":"Flutter","title":"State Management: Blocs without Libraries"}},"strapiTutorial":{"lessons":[{"author":1,"content":"This is going to be extremely similar to the previous example. It's just more examples so you can get used to seeing stream builders in action.\n\n```dart\n/// The container for the screen is similar to the previous example.\n/// In this example, though, you can see both blocs being used in one widget\nclass AddAndEditTodoScreen extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    // grab a reference to this bloc here, because \n    // it's the primary bloc used in this screen. It\n    // will provide the stream we need in the stream builder.\n    final bloc = BlocProvider.of(context).editTodoBloc;\n    return StreamBuilder<Task>(\n      // use the bloc\n      stream: bloc.todo,\n      builder: (context, snapshot) {\n        // protect against null data\n        if (!snapshot.hasData) return CircularProgressIndicator();\n        return ScreenContainer(\n          title: Text('Add Todo'),\n          // Most of the logic is in this widget,\n          // which you can see on github at https://github.com/ericwindmill/flutter_by_example/tree/master/examples/calendar_app/blocs_without_libraries/lib/screens/add_todo_screen\n          body: FormContainer(),\n          floatingActionButton: FloatingActionButton.extended(\n            label: Padding(\n              padding: const EdgeInsets.all(16.0),\n              child: Text('Save'),\n            ),\n            // This is the interesting part in which we use two blocs\n            onPressed: () {\n              // The [TodoListBloc] is the only one that communicates with the\n              // repository. Therefor, we'll use it to add the new task to\n              // the repository when the floating action button is tapped.\n              BlocProvider.of(context).todoListBloc.addTask(bloc.todo.value);\n              // we also need to clear the form, so that it's blank\n              // when we return to this screen to add another task\n              // this is done on the primary bloc for this screen, the EditTodoBloc\n              bloc.clearAddEditForm();\n              // finally, pop back to the todolist page.\n              Navigator.of(context).pop();\n            },\n          ),\n        );\n      },\n    );\n  }\n}\n```\n\n","created_at":"2020-07-25T14:59:55.408Z","id":97,"slug":"consume-the-second-bloc-s-streams","title":"Consume the second bloc's streams","tutorial":10,"updated_at":"2020-07-25T14:59:55.416Z"},{"author":1,"content":"<div class=\"aside\">This portion of FlutterByExample is all about state management. Thus, we'll dive right into blocs in this tutorial, and not focus much on UI. If you're not familiar with Flutter as a UI library, I suggest you go back and start at an earlier tutorial.</div>\n\nIn this app, there are two blocs: a `TodoListBloc` and an `AddTodoBloc`. \n\nThe todo list bloc is responsible for connecting a repository to the the todo list page of the app. In other words, the UI will get all of it's state about which tasks exist from this bloc, which will pull it's data from an API. It is also responsible for telling the API whenever a task is marked as complete (or incomplete). In short, it's the middleman between the data (source of truth) and the UI displaying that data.\n\n<img src=\"images/calendar_app/calendar_app_home.png\" alt=\"drawing\" style=\"width:400px;\"/>\n\nLooking at the finished app, we know that this bloc needs to handle a few tasks:\n\n* fetching all tasks from the repository, and delivering them to the UI\n* marking tasks as complete or incomplete, \n* ensuring the UI is displaying the correct tasks when a date is selected on the calendar\n\nFor now, let's only worry about creating a bloc that can handle the simplest task: fetching tasks from the repository and emitting them via _streams_.\n\n### The initial bloc stream\n\n```dart\nclass TodoListBloc {\n  // The [TodoRepository] class represents a service that\n  // handles the data. It could be a class that talks to an\n  // API or directly to Firebase. In this case, it talks\n  // to a _reactive_ data store similar to Firestore. \n  final TodoRepository _repository;\n  // inputs\n  // TODO:\n\n  // outputs\n  // This output is a [Stream] that simply emits a list of tasks\n  // when the _repository is aware of new todos, it emits them. The bloc\n  // in this case, is a middleman. As this bloc grows, you'll see why this\n  // is better than the repository being exposed to the UI directly.\n  Stream<List<Task>> get todos =>  _repository.todos;\n}\n```\n\n### Add a sink to the bloc\n\nNow that we can emit a list of todos, which will be eventually used by the UI, we need a way to toggle the completion status of the todos. This will be done via a `Sink`, which we'll add the previous TodoListBloc code.\n\n```dart\nclass TodoListBloc {\n  final TodoRepository _repository;\n  // inputs\n  void toggleTaskComplete(Task todo) async {\n    // toggleComplete is a method on the `Task` class which returns\n    // a new instance of `Task` that is the same, except Task.completed\n    // is flipped from false to true (or vise-versa).\n    final toggled = todo.toggleComplete();\n\n    // When the repository is updated, it will then\n    // emit a new event via it's `TodoRepository.todos` stream property.\n    // Thus, we don't need to return anything here, because we're consuming\n    // the repository todos in the output below.\n    _repository.updateTodo(toggled);\n  }\n\n  // outputs\n  // when `toggleTaskComplete` is called, the repository\n  // will emit a new event\n  Stream<List<Task>> get todos =>  _repository.todos;\n}\n```\n\n### A second sink and stream\n\nFinally, here's additional code, used to manage which date on the calendar is selected in the app UI. We will return to this code later in the tutorial.\n\n```dart\nclass TodoListBloc {\n  final TodoRepository _repository;\n  // inputs\n  void toggleTaskComplete(Task todo) async {\n    final toggled = todo.toggleComplete();\n    _repository.updateTodo(toggled);\n  }\n\n  /// [BehaviorSubject] is a class from the `rxdart` package. It's similar to a \n  /// StreamController, with a few extra perks. We'll return to this later.\n  BehaviorSubject<DateTime> selectedDateControllerSink = BehaviorSubject<DateTime>();\n\n  // outputs\n  Stream<List<Task>> get todos =>  _repository.todos;\n  Stream<DateTime> get selectedDate => selectedDateControllerSink.stream;\n}\n```","created_at":"2020-07-25T14:57:38.670Z","id":93,"slug":"create-bloc-one","title":"Create bloc one","tutorial":10,"updated_at":"2020-07-25T14:57:38.699Z"},{"author":1,"content":"<div class=\"aside\"> This text is a snippit from the book <a href=\"https://www.manning.com/books/flutter-in-action\">Flutter in Action</a>, written by Eric Windmill and published by Manning Publications.</div>\n\n_B.L.o.C._ stands for Business Logic Components (or simply _blocs_ from here on out). This pattern was first revealed at Dart Conference 2018, aka DartConf, and it's purpose is to make UI business logic highly reusable. Specifically at DartConf, it was presented as a nice way to share all UI logic between Flutter and AngularDart.\n\nThe bloc pattern's mantra is that widgets should be as dumb as possible, and the business logic should live in separate components. This in itself isn't unique, compared to other approaches, but the devil is in the details. In general, blocs are what they are for two main reasons:\n\n* Their public API consists of simple inputs and outputs only.\n* Blocs should be _injectable_, which means platform agnostic. This means you can use the same blocs for Flutter, AngularDart, on the server, etc.\n\nThose are broad ideas, of course, but they're made clearer by the following _non-negotiable_ rules. These rules were described in the original talk at DartConf 2018 and live in two categories: application design and UI rules.\n\nFor application design:\n\n. Inputs and outputs are sinks and streams only! No functions, no constants, no variables! (Although, you'll see that this rule is \"broken\" quite often to make code more concise. More on that later.)\n. Dependencies must be injectable. If you're importing any Flutter libraries into the bloc, then that's UI work, not business logic, and those should be moved into the UI.\n. Platform-branching is not allowed. If you find yourself in a bloc writing `if (device == browser)...`, then you need to reconsider.\n. Do whatever else you want, so long as you follow these rules.\n\nFor UI functionality:\n\n. In general, blocs and top-level Flutter pages have a one-to-one (1:1) relationship. In reality, the point is that each logical state subject has its own bloc. For example, in a Todo List app, you might have a bloc for the 'Todo List' page, and a bloc for the \"Add Todo\" page.\n. Components should send inputs as is, because there shouldn't be business logic in the widget! If you need to format text or serialize a model, it should be done in the bloc.\n. Outputs should be passed to widgets ready to use. For example, if you have a number that needs to be converted into displayable currency, that should be done in the bloc.\n. Any branching should be based on simple bloc boolean logic. You should limit yourself to a single boolean stream in the bloc. For example, in Flutter, it's acceptable to write `color: bloc.isDestructive ? Colors.red : Colors.blue`. It is considered wrong if you have to use complex boolean clauses like `if (bloc.buttonIsDestructive && bloc.buttonIsEnabled && bloc.userIsAdmin) { ...`. If you find yourself doing this, you can probably move this logic to the bloc.\n\nWherever possible, your widgets should be dumb, stateless widgets whose only job is rebuilding when it's told to. \n\n### 'Counter App' using blocs\n\n```run-dartpad:mode-flutter:theme-dark\n\nimport 'package:flutter/material.dart';\nimport 'dart:async';\n\nvoid main() => runApp(MyApp());\n\nclass CounterBloc {\n  // this sink is the 'input'.\n  // sinks should be the _only_ way that \n  // outside object can interact with blocs. \n  StreamController<int> todoCompleteSink = StreamController();\n\n  // this stream is the 'output'\n  // it's the only property that outside\n  // objects can use to consume this blocs data.\n  Stream<int> get todoCompleteStream => todoCompleteSink.stream;\n\n  CounterBloc() {\n    todoCompleteSink.add(0);\n  }\n  \n  dispose() {\n    todoCompleteSink.close();\n  }\n}\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Flutter Demo',\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: MyHomePage(),\n    );\n  }\n}\n\nclass MyHomePage extends StatelessWidget {\n  final CounterBloc bloc = CounterBloc();\n\n  @override\n  Widget build(BuildContext context) {\n    return StreamBuilder<int>(\n      // here the bloc data is being consumed by the UI \n      stream: bloc.todoCompleteStream,\n      builder: (context, snapshot) {\n        return Scaffold(\n          appBar: AppBar(\n            title: Text(\"Flutter Demo Home Page\"),\n          ),\n          body: Center(\n            child: Column(\n              mainAxisAlignment: MainAxisAlignment.center,\n              children: <Widget>[\n                Text(\n                  'You have pushed the button this many times:',\n                ),\n                Text(\n                  '${snapshot?.data ?? 0}',\n                  style: Theme.of(context).textTheme.display1,\n                ),\n              ],\n            ),\n          ),\n          floatingActionButton: FloatingActionButton(\n            // here the sink is being used to tell\n            // the bloc it should update it's state\n            onPressed: () => bloc.todoCompleteSink.add(snapshot.data + 1),\n            tooltip: 'Increment',\n            child: Icon(Icons.add),\n          ),\n        );\n      },\n    );\n  }\n}\n```\n\nThe above example is the most simple possible Flutter / Bloc example I can think of. It's so simple that it may not answer many questions you have about blocs. The rest of this example app will show a more complicated example, which uses complex data, multiple blocs working in unison, and talking to repositories outside of the app.","created_at":"2020-07-25T14:56:35.995Z","id":91,"slug":"what-are-blocs","title":"What are blocs?","tutorial":10,"updated_at":"2020-07-25T14:56:36.013Z"},{"author":1,"content":"<a href='https://github.com/ericwindmill/flutter_by_example/tree/master/examples/calendar_app'>The complete source code can be found here.</a>","created_at":"2020-07-25T15:00:25.108Z","id":98,"slug":"blocs-without-libs-complete-source-code","title":"Complete source code","tutorial":10,"updated_at":"2020-07-25T15:30:50.518Z"},{"author":1,"content":"In order to use the blocs in your Flutter UI, you need to be able to access the blocs through-out your app. For example, you want to be able to do something like this in a widget:\n\n```dart\nclass MyWidget extends StatelessWidget {\n\n  Widget build(BuildContext context) {\n    var myBloc = ???; // todo: access bloc somehow\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n\nThere are a couple ways you could accomplish this. For example, you could create an instance of the bloc in the widget you're using:\n\n```dart\nclass MyWidget extends StatelessWidget {\n\n  Widget build(BuildContext context) {\n    var myBloc = TodoListBloc(repository: TodoRepository());\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n\nThis won't work. What if you want to update a todo in a different widget? You'd be using a new instance of `TodoRepository` each time, so your data wouldn't persist from one piece of the app to another. \n\nTo solve that problem, we can \"lift state up\" -- or create the bloc and repository high in the widget tree, and then pass it down the tree to the widgets that need it.\n\n```dart\nclass MyWidget extends StatelessWidget {\n  final TodoListBloc bloc;\n\n  MyWidget(this.bloc);\n\n  Widget build(BuildContext context) {\n    var myBloc = TodoListBloc(repository: TodoRepository());\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n\nThis will work. *However*, it's very cumbersome. You'd need to be passing the bloc through every widget in-between the root of your app and the leaf widgets that need the bloc. \n\nLuckily, Flutter's `InheritedWidget` is designed to solve this exact problem. I'll use an `InheritedWidget` to create a _bloc provider_. Provider is a term you'll see a lot in the Flutter world. In Flutter, it's used to describe a class that is used to inject other objects throughout your widget tree or scope, even when you're much further down the widget tree than where the objects are created. \n\nIn the calendar app, this is the `BlocProvider` class:\n\n```dart\nimport 'package:blocs_without_libraries/app/blocs/edit_todo_bloc.dart';\nimport 'package:blocs_without_libraries/app/blocs/todos_bloc.dart';\nimport 'package:flutter/material.dart';\n\n// InheritedWidget objects have the ability to be\n// searched for anywhere 'below' them in the widget tree.\nclass BlocProvider extends InheritedWidget {\n\n  // these blocs are the objects that we want to access throughout the app\n  final TodoListBloc todoListBloc;\n  final EditTodoBloc editTodoBloc;\n\n  /// Inherited widgets require a child widget\n  /// which they implicitly return in the same way\n  /// all widgets return other widgets in their 'Widget.build' method.\n  const BlocProvider({\n    Key key,\n    @required Widget child,\n    this.todoListBloc,\n    this.editTodoBloc,\n  })  : assert(child != null),\n        super(key: key, child: child);\n\n  /// this method is used to access an instance of\n  /// an inherited widget from lower in the tree.\n  /// `BuildContext.dependOnInheritedWidgetOfExactType` is a built in\n  /// Flutter method that does the hard work of traversing the tree for you\n  static BlocProvider of(BuildContext context) {\n    return context.dependOnInheritedWidgetOfExactType<BlocProvider>();\n  }\n\n  @override\n  bool updateShouldNotify(BlocProvider old) {\n    return true;\n  }\n}\n```\n\nYou also must add an instance of this `BlocProvider` to the app. This is done in the `main.dart` file in the calendar app.\n\n```dart\nvoid main() {\n  var _repository = TodoRepository(WebClient());\n\n  runApp(\n    /// Bloc provider is a widget, so it can be used\n    /// as the root of your Flutter app!\n    BlocProvider(\n      todoListBloc: TodoListBloc(_repository),\n      editTodoBloc: EditTodoBloc(seed: Task('')),\n      child: BlocsWithoutLibrariesApp(),\n    ),\n  );\n}\n```\n\nAnd finally, you need to access your blocs via the `BlocProvider` throughout your app.\n\n```dart\nclass MyWidget extends StatelessWidget {\n\n  Widget build(BuildContext context) {\n    /// So long as there is an instance of `BlocProvider` above this widget\n    /// in the widget tree, and that `BlocProvider` is a subclass of `InheritedWidget`\n    /// this method will look up the tree, find the first occurrence of this widget\n    /// and return it. [todoListBloc] is just a property on that widget.\n    var myBloc = BlocProvider.of(context).todoListBloc;\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n","created_at":"2020-07-25T14:58:07.644Z","id":94,"slug":"create-a-bloc-provider","title":"Create a bloc provider","tutorial":10,"updated_at":"2020-07-25T14:58:07.652Z"},{"author":1,"content":"Now, it's time to jump into some Flutter specific code, where we can consume the `TodoListBloc` data with a `StreamBuilder` widget.  Specifically, let's start by looking at the `TodoList` widget that I made for that project.\n\n<img src=\"images/calendar_app/calendar_app_todo_list_annotation.png\" alt=\"calendar app\" style=\"width:500px;border-radius: 0\"/>\n\n### Bloc code reminder\n\nHere's the bloc code that we care about, as a reminder before we dive into the Flutter code.\n\n```dart\nimport 'dart:async';\n\nimport 'package:calendar_app_repository/calendar_app_repository.dart';\nimport 'package:rxdart/rxdart.dart';\n\nclass TodoListBloc {\n  final TodoRepository _repository;\n\n  TodoListBloc(this._repository) {\n    // ...\n  }\n\n  // inputs\n  void toggleTaskComplete(Task todo) async {\n    final toggled = todo.toggleComplete();\n    // the output of this bloc will emit a new stream event\n    // when the [_repository] is finished.\n    return await _repository.updateTodo(toggled);\n  }\n\n  BehaviorSubject<DateTime> selectedDateControllerSink = BehaviorSubject<DateTime>();\n  BehaviorSubject<List<Task>> tasksForDate = BehaviorSubject<List<Task>>();\n\n  // outputs\n  // NB:  This is the output that we care about in this example\n  Stream<List<Task>> get todos {\n    return _repository.todos;\n  }\n\n  Stream<DateTime> get selectedDate => selectedDateControllerSink.stream;\n\n  void dispose() {\n    selectedDateControllerSink.close();\n  }\n}\n```\n\n### Adding a StreamBuilder\n\n`StreamBuilder` is a widget that knows to re-build and re-render each time a stream it's listening to emits a new event. You'll tell it what stream to listen to, and what widgets to build when that stream is updated. Using a `StreamBuilder` will be familiar is you know the `builder` pattern used in Flutter. \n\n<div class=\"aside\">\nAs a recap, `builder` is a pattern on many Flutter widgets that allow you to use a callback to create widgets, rather than the standard means of passing a widget to `Widget.child` in the build method. \n</div>\n\n```dart\nimport 'package:blocs_without_libraries/app/bloc_provider.dart';\nimport 'package:calandar_app_ui/widgets/widgets.dart';\nimport 'package:calendar_app_repository/calendar_app_repository.dart';\nimport 'package:flutter/material.dart';\n\nclass TodoList extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    // Grab a reference to the bloc using the bloc provider\n    final bloc = BlocProvider.of(context).todoListBloc;\n\n    // return a StreamBuilder\n    // which requires a `builder` callback to be passed in\n    // as well as `stream` to listen to\n    // The type declaration on StreamBuilder is used to tell \n    // it what type of data to expect from the Stream\n    return StreamBuilder<List<Task>>(\n      // pass it the `todos` stream on the bloc\n      stream: bloc.todos,\n      // Builder callback will be passed the BuildContext,\n      // as well as an [AsyncSnapshot], which is _current_ data\n      // emitted from the Stream (in this case a List of Tasks\n      builder: (BuildContext context, AsyncSnapshot snapshot) {\n        // If there isn't any data, return early to prevent the app from crashing\n        if (!snapshot.hasData) return Center(child: CircularProgressIndicator());\n  \n        // ListView.builder is another widget that relies on the builder pattern\n        return ListView.builder(\n          // `snapshot.data` is the actual List<Task> object from the stream.\n          itemCount: snapshot.data.length,\n          // `itemBuilder` is required, and should return a widget \n          // that's used created for each iteration of the `ListView.builder`\n          // the index that's passed in to this callback will be increased with\n          // each iteration\n          itemBuilder: (BuildContext context, int index) {\n            // grab a reference to the task for brevity\n            // remember that the `snapshot.data` is a list of todos.\n            Task todo = snapshot.data[index];\n            // now we can finally use the task object itself\n            // which we're getting from the Bloc.todos stream.\n            return TodoListTile(\n              task: todo,\n              onCheckboxToggle: (bool v) => bloc.toggleTaskComplete(todo),\n              onRefreshed: () => bloc.refreshTaskDate(todo),\n            );\n          },\n        );\n      },\n    );\n  }\n}\n```\n\n`StreamBuilder` is used several times in this app. You can find many more examples in the <a href=\"https://github.com/ericwindmill/flutter_by_example/tree/master/examples/calendar_app/blocs_without_libraries/lib\">source code</a>.","created_at":"2020-07-25T14:58:48.960Z","id":95,"slug":"using-stream-builders-with-blocs","title":"Using StreamBuilders with blocs","tutorial":10,"updated_at":"2020-07-25T14:58:48.968Z"},{"author":1,"content":"For the state management portion of FlutterByExample, we've created a twist on the classic Todo app. In addition to working like a basic todo app, it also has 'due date' and 'repeating' task features.  \n\nThese images show the todo app in it's most basic form: with a list of todos -- some checked and some not.\n\n<img src=\"images/calendar_app/calendar_app_home.png\" alt=\"drawing\" style=\"width:200px;\"/>\n<img src=\"images/calendar_app/calendar_app_home_2.png\" alt=\"drawing\" style=\"width:200px;\"/>\n\nNotice the calendar at the top of the screen. When one of the days are tapped, it displays only the tasks that are due that day.\n\n<img src=\"images/calendar_app/calendar_app_friday_selected.png\" alt=\"drawing\" style=\"width:200px;\"/>\n\nYou can also add new todos. When adding new todos, you can set a one time due date (using the DatePicker widget), or you can set the todo to be a repeating task, and select the days it should repeat.\n\n<img src=\"images/calendar_app/calendar_app_add_todo.png\" alt=\"drawing\" style=\"width:200px;\"/>\n<img src=\"images/calendar_app/calendar_app_add_todo_datepicker.png\" alt=\"drawing\" style=\"width:200px;\"/>\n<img src=\"images/calendar_app/calendar_app_add_todo_repeating_true.png\" alt=\"drawing\" style=\"width:200px;\"/>\n \n \nOnce you create a new todo, you'll see it appear in the list. In this image, you can see that it repeats every Friday:\n\n<img src=\"images/calendar_app/calendar_app_friday_selected_2.png\" alt=\"drawing\" style=\"width:200px;\"/>\n\n### Using a mock back-end\n\nThis calendar app, regardless of the state-management pattern being used, communicates with outside API's via a class called the `TodoRepository`. It's job is to talk to the data store on behalf of the Flutter app, and then return the responses to the app. This class looks like this:\n\n<div class=\"aside\">For now, the implementation of this class isn't important. I'm showing you this only so you have context in future lessons that will refer to this repository. The important note is that this repository is _reactive_, and closely imitates Firestore. Whenever the data store is updated, it emits new information via a Stream of a List of Tasks.</div>\n\n```dart\nimport 'package:calendar_app_repository/src/mock_web_client.dart';\nimport 'package:rxdart/subjects.dart';\nimport 'model/todo.dart';\n\n/// This is a _reactive_ class that talks to a web-client.\n/// The API of this class is written in a way that allows your\n/// app to consume the data in a reactive way, which means\n/// it behaves similarly to Firestore.\nclass TodoRepository {\n  final WebClient client;\n  final BehaviorSubject<List<Task>> _subject;\n  bool _loaded = false;\n\n  TodoRepository(this.client, {List<Task> seed})\n      : _subject = BehaviorSubject<List<Task>>.seeded(seed ?? []);\n\n  Stream<List<Task>> get todos {\n    if (!_loaded) _loadTodos();\n\n    return _subject.stream;\n  }\n\n  List<Task> get snapshot => _subject.value ?? [];\n\n  void _loadTodos() {\n    _loaded = true;\n\n    client.fetchTodos().then((todos) {\n      _subject.add([..._subject?.value, ...todos]);\n    });\n  }\n\n  Future<void> addNewTodo(Task todo) async {\n    final newTodos = [..._subject.value, todo];\n    _subject.add([..._subject.value, todo]);\n    await client.postTodos(newTodos);\n  }\n\n  Future<void> deleteTodo(Task todo) async {\n    final newTodos = _subject.value.where((t) => t.description != todo.description);\n    _subject.add(newTodos);\n    await client.postTodos(newTodos);\n  }\n\n  Future<void> updateTodo(Task todo) async {\n    final todos = _subject.value;\n    final todoToUpdate = todos.firstWhere((t) => t.description == todo.description);\n    final index = todos.indexOf(todoToUpdate);\n    todos.replaceRange(index, index + 1, [todo]);\n    _subject.add(todos);\n    await client.postTodos(todos);\n  }\n}\n```","created_at":"2020-07-25T14:57:03.087Z","id":92,"slug":"calendar-app-introduction","title":"Calendar App introduction","tutorial":10,"updated_at":"2020-07-25T15:29:51.654Z"},{"author":1,"content":"In this lesson, I'd like to simply show a second example of a bloc, as well as where the bloc is consumed. This is meant to be a another example, and because it's lessons are similar to the previous bloc lesson in this tutorial, it will be light in the explanation.\n\nThere are three differences in this bloc that are worth pointing out:\n\n1. This bloc uses an _imperative_ approach. It defines state that can live a long time. It updates this state right in the bloc, and then emits the changes.\n2. This bloc deals entirely with editing a task _in memory_. It isn't concerned with any repositories or outside API. It's only inputs come from the UI, and it's only consumers are also the UI. Therefor, there is more logic happening right in the bloc than before.\n3. It's inputs aren't _technically_ streams. This is an instance in which I've broken the rules. The inputs are instance methods. Importantly, though, these methods defer to streams.  The purpose of this is to make the code more readable (both in the UI and in the bloc) while still only using one StreamController. Because this bloc deals only with outputs that are single `Task` objects, but the inputs are caused by different events, these functions all funnel into the same stream controller. In this sense, the inputs are more or less still just sinks. None of the functions return any values to be used by the UI, which is the greater point. \n\n\n```dart\nimport 'package:calendar_app_repository/calendar_app_repository.dart';\nimport 'package:rxdart/rxdart.dart';\n\n\nclass EditTodoBloc {\n  // This bloc uses an imperative approach, in order to show a different style.\n  // importantly, though, it's inputs are still sinks and outputs still streams\n  Task _newTask;\n\n  // BehaviorSubject is a super-powered StreamController in the rxdart package:\n  // \n  // A broadcast StreamController that caches the latest added value or error. \n  // When a new listener subscribes to the Stream, the latest value or error \n  // will be emitted to the listener. Furthermore, you can synchronously \n  // read the last emitted value.\n  // \n  BehaviorSubject<Task> _todoSink;\n  ValueStream<Task> todo;\n\n  // The sink and stream are created in the \n  // constructor in order to use the `seeded` factory\n  // on BehaviorSubject. It ensures that there's always \n  // a value in the stream, even before anything has been added\n  EditTodoBloc({Task seed}) {\n    _newTask = seed ?? Task('');\n    _todoSink = BehaviorSubject<Task>.seeded(seed ?? _newTask);\n    todo = _todoSink.stream;\n  }\n\n  // all of these methods work similarly\n  // they copy the task with a new value for a given\n  // property, and then they add that new task to the sink.\n  void updateTodoDescription(String updatedDescription) {\n    _newTask = _newTask.copyWith(description: updatedDescription);\n    _todoSink.add(_newTask);\n  }\n\n  void updateDueByDate(DateTime dueDate) {\n    _newTask = _newTask.copyWith(dueDate: dueDate);\n    _todoSink.add(_newTask);\n  }\n\n  void toggleRepetitionDay(DayOfWeek day, bool v) {\n    var currentRepetitionDays = _newTask.repeatingDays..add(day);\n    if (!v) currentRepetitionDays.remove(day);\n\n    _newTask = _newTask.copyWith(repeatingDays: currentRepetitionDays);\n    _todoSink.add(_newTask);\n  }\n\n  void toggleIsRepeating(bool v) {\n    _newTask = _newTask.copyWith(isRepeating: v);\n    _todoSink.add(_newTask);\n  }\n\n  void clearAddEditForm() {\n    _newTask = Task(\n      '',\n      dueDate: null,\n      repeatingDays: null,\n      isRepeating: false,\n    );\n    _todoSink.add(_newTask);\n  }\n\n  void dispose() {\n    _todoSink.close();\n  }\n}\n``` \n","created_at":"2020-07-25T14:59:19.712Z","id":96,"slug":"create-bloc-two-add-edit-tasks","title":"Create bloc two: Add/Edit Tasks","tutorial":10,"updated_at":"2020-07-25T14:59:19.718Z"}]},"strapiTableOfContents":{"contents":"{\n  \"Dart\": {\n    \"Getting Started with Dart\": [\n      \"About Dart\",\n      \"Install Dart on your machine\",\n      \"Dartpad\",\n      \"Text Editors: Intellij and VSCode\",\n      \"Resources: Documentation and Pub.dev\",\n      \"Hello World\",\n      \"The main function\",\n      \"Print to the console\"\n    ],\n    \"Dart Fundamentals\": [\n      \"Values and variables\",\n      \"Comments\",\n      \"const and final variables\",\n      \"Arithmetic and Comparison Operators\",\n      \"Assignment Operators\",\n      \"Logical Operators\",\n      \"Null Aware Operators\",\n      \"Type Test Operators\",\n      \"Bitwise and Shift Operators\",\n      \"Control Flow: if, else, else if\",\n      \"Switch statements and case\",\n      \"Ternary Conditional operator\",\n      \"Loops: for and while\",\n      \"Anatomy of Dart Functions\",\n      \"Arrow functions\",\n      \"Function arguments: default, optional, named\",\n      \"Lexical Scope\",\n      \"Cascade notation\"\n    ],\n    \"Data Types\": [\n      \"Intro to Dart's Type System\",\n      \"Numbers\",\n      \"Strings\",\n      \"Booleans\",\n      \"dynamic\",\n      \"lists\",\n      \"sets\",\n      \"maps\"\n    ],\n    \"Object-Oriented Programming\": [\n      \"Intro to OOP\",\n      \"Classes\",\n      \"Constructors\",\n      \"Properties and methods\",\n      \"Methods: static, private, etc\",\n      \"Getters and setters\",\n      \"Extending classes (inheritance)\",\n      \"Initializer lists and final properties\",\n      \"Factory methods\",\n      \"Singletons\",\n      \"Abstract classes (and interfaces)\",\n      \"Mixins\",\n      \"Extension methods\"\n    ],\n    \"Iterables, Iterators, and Collections\": [\n      \"What are collections (and iterables)?\",\n      \"Looping: for-in and forEach\",\n      \"Reading elements pt 1: first, last\",\n      \"Adding elements: add and insert (all)\",\n      \"Checking for elements: contains, indexOf, any, every\",\n      \"Removing elements: remove, clear, removeWhere\",\n      \"Filtering elements: where, takeWhile, and skipWhile\",\n      \"Changing elements: map and expand\",\n      \"Deriving values from elements: fold, reduce, join\",\n      \"Type casting collections: cast, as, retype, toSet, toList\",\n      \"Iterators: understanding and creating your own\",\n      \"Iterable-like methods on maps (and putIfAbsent)\"\n    ]\n  },\n  \"Flutter\": {\n    \"Getting started with Flutter\": [\n      \"About Flutter\",\n      \"IDEs and resources\"\n    ],\n    \"Widgets\": [\n      \"Intro to Widgets\",\n      \"Widget types: Stateful and Stateless\",\n      \"StatefulWidget lifecycle\",\n      \"The Widget tree\",\n      \"BuildContext\",\n      \"Inherited Widgets\",\n      \"Thinking in widgets\"\n    ],\n    \"Intro Flutter App\": [\n      \"Intro and Setup\",\n      \"Data Model and HTTP\",\n      \"Build a custom widget\",\n      \"ListView and builder pattern\",\n      \"Gradient Backgrounds\",\n      \"Routing: Add a detail page\",\n      \"Routing 2: Add a form page\",\n      \"User Input\",\n      \"Sliders and Buttons\",\n      \"Snackbars and Dialogs\",\n      \"Built-in Animation: AnimatedCrossFade\",\n      \"Built-in Animation: Hero transition\"\n    ],\n    \"Custom Animation: Progress Indicator\": [\n      \"Intro and Overview\",\n      \"Build the example app boiler-plate\",\n      \"Custom Widget: Peg\",\n      \"Tween and AnimationController classes\",\n      \"Tween by example\",\n      \"Using Tweens and Intervals\",\n      \"Wrap the Pegs in AnimatedWidgets\",\n      \"Bring it all together\"\n    ],\n    \"State Management: Blocs without Libraries\": [\n      \"What are blocs?\",\n      \"Calendar App introduction\",\n      \"Create bloc one\",\n      \"Create a bloc provider\",\n      \"Using StreamBuilders with blocs\",\n      \"Create bloc two: Add/Edit Tasks\",\n      \"Consume the second bloc's streams\",\n      \"Complete source code\"\n    ],\n    \"State Management: Provider\": [\n      \"What is Provider?\",\n      \"The most basic example using Provider\",\n      \"ChangeNotifierProvider\",\n      \"Rebuilding widgets with Consumer\",\n      \"Finer build control with Selector\",\n      \"Future Provider\",\n      \"MultiProvider micro lesson\",\n      \"Stream Provider\",\n      \"Using context extensions for more control\",\n      \"ProxyProvider\",\n      \"Using .value constructors\",\n      \"The final example (A shopping cart app)\",\n      \"For the curious: How is provider implemented\"\n    ],\n    \"Handling Data with Brick: Offline First with Rest\": [\n      \"About Brick and setup\",\n      \"Adding a Repository\",\n      \"Adding a Model\",\n      \"Generating Code\",\n      \"Rendering Models\",\n      \"Adding an Association\"\n    ]\n  }\n}"}},"pageContext":{"slug":"using-stream-builders-with-blocs","tutorialTitle":"State Management: Blocs without Libraries","previous":{"author":1,"content":"In order to use the blocs in your Flutter UI, you need to be able to access the blocs through-out your app. For example, you want to be able to do something like this in a widget:\n\n```dart\nclass MyWidget extends StatelessWidget {\n\n  Widget build(BuildContext context) {\n    var myBloc = ???; // todo: access bloc somehow\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n\nThere are a couple ways you could accomplish this. For example, you could create an instance of the bloc in the widget you're using:\n\n```dart\nclass MyWidget extends StatelessWidget {\n\n  Widget build(BuildContext context) {\n    var myBloc = TodoListBloc(repository: TodoRepository());\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n\nThis won't work. What if you want to update a todo in a different widget? You'd be using a new instance of `TodoRepository` each time, so your data wouldn't persist from one piece of the app to another. \n\nTo solve that problem, we can \"lift state up\" -- or create the bloc and repository high in the widget tree, and then pass it down the tree to the widgets that need it.\n\n```dart\nclass MyWidget extends StatelessWidget {\n  final TodoListBloc bloc;\n\n  MyWidget(this.bloc);\n\n  Widget build(BuildContext context) {\n    var myBloc = TodoListBloc(repository: TodoRepository());\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n\nThis will work. *However*, it's very cumbersome. You'd need to be passing the bloc through every widget in-between the root of your app and the leaf widgets that need the bloc. \n\nLuckily, Flutter's `InheritedWidget` is designed to solve this exact problem. I'll use an `InheritedWidget` to create a _bloc provider_. Provider is a term you'll see a lot in the Flutter world. In Flutter, it's used to describe a class that is used to inject other objects throughout your widget tree or scope, even when you're much further down the widget tree than where the objects are created. \n\nIn the calendar app, this is the `BlocProvider` class:\n\n```dart\nimport 'package:blocs_without_libraries/app/blocs/edit_todo_bloc.dart';\nimport 'package:blocs_without_libraries/app/blocs/todos_bloc.dart';\nimport 'package:flutter/material.dart';\n\n// InheritedWidget objects have the ability to be\n// searched for anywhere 'below' them in the widget tree.\nclass BlocProvider extends InheritedWidget {\n\n  // these blocs are the objects that we want to access throughout the app\n  final TodoListBloc todoListBloc;\n  final EditTodoBloc editTodoBloc;\n\n  /// Inherited widgets require a child widget\n  /// which they implicitly return in the same way\n  /// all widgets return other widgets in their 'Widget.build' method.\n  const BlocProvider({\n    Key key,\n    @required Widget child,\n    this.todoListBloc,\n    this.editTodoBloc,\n  })  : assert(child != null),\n        super(key: key, child: child);\n\n  /// this method is used to access an instance of\n  /// an inherited widget from lower in the tree.\n  /// `BuildContext.dependOnInheritedWidgetOfExactType` is a built in\n  /// Flutter method that does the hard work of traversing the tree for you\n  static BlocProvider of(BuildContext context) {\n    return context.dependOnInheritedWidgetOfExactType<BlocProvider>();\n  }\n\n  @override\n  bool updateShouldNotify(BlocProvider old) {\n    return true;\n  }\n}\n```\n\nYou also must add an instance of this `BlocProvider` to the app. This is done in the `main.dart` file in the calendar app.\n\n```dart\nvoid main() {\n  var _repository = TodoRepository(WebClient());\n\n  runApp(\n    /// Bloc provider is a widget, so it can be used\n    /// as the root of your Flutter app!\n    BlocProvider(\n      todoListBloc: TodoListBloc(_repository),\n      editTodoBloc: EditTodoBloc(seed: Task('')),\n      child: BlocsWithoutLibrariesApp(),\n    ),\n  );\n}\n```\n\nAnd finally, you need to access your blocs via the `BlocProvider` throughout your app.\n\n```dart\nclass MyWidget extends StatelessWidget {\n\n  Widget build(BuildContext context) {\n    /// So long as there is an instance of `BlocProvider` above this widget\n    /// in the widget tree, and that `BlocProvider` is a subclass of `InheritedWidget`\n    /// this method will look up the tree, find the first occurrence of this widget\n    /// and return it. [todoListBloc] is just a property on that widget.\n    var myBloc = BlocProvider.of(context).todoListBloc;\n    return Text(myBloc.titleStream.value);\n  }\n}\n```\n","created_at":"2020-07-25T14:58:07.644Z","id":94,"slug":"create-a-bloc-provider","title":"Create a bloc provider","tutorial":10,"updated_at":"2020-07-25T14:58:07.652Z"},"next":{"author":1,"content":"For the state management portion of FlutterByExample, we've created a twist on the classic Todo app. In addition to working like a basic todo app, it also has 'due date' and 'repeating' task features.  \n\nThese images show the todo app in it's most basic form: with a list of todos -- some checked and some not.\n\n<img src=\"images/calendar_app/calendar_app_home.png\" alt=\"drawing\" style=\"width:200px;\"/>\n<img src=\"images/calendar_app/calendar_app_home_2.png\" alt=\"drawing\" style=\"width:200px;\"/>\n\nNotice the calendar at the top of the screen. When one of the days are tapped, it displays only the tasks that are due that day.\n\n<img src=\"images/calendar_app/calendar_app_friday_selected.png\" alt=\"drawing\" style=\"width:200px;\"/>\n\nYou can also add new todos. When adding new todos, you can set a one time due date (using the DatePicker widget), or you can set the todo to be a repeating task, and select the days it should repeat.\n\n<img src=\"images/calendar_app/calendar_app_add_todo.png\" alt=\"drawing\" style=\"width:200px;\"/>\n<img src=\"images/calendar_app/calendar_app_add_todo_datepicker.png\" alt=\"drawing\" style=\"width:200px;\"/>\n<img src=\"images/calendar_app/calendar_app_add_todo_repeating_true.png\" alt=\"drawing\" style=\"width:200px;\"/>\n \n \nOnce you create a new todo, you'll see it appear in the list. In this image, you can see that it repeats every Friday:\n\n<img src=\"images/calendar_app/calendar_app_friday_selected_2.png\" alt=\"drawing\" style=\"width:200px;\"/>\n\n### Using a mock back-end\n\nThis calendar app, regardless of the state-management pattern being used, communicates with outside API's via a class called the `TodoRepository`. It's job is to talk to the data store on behalf of the Flutter app, and then return the responses to the app. This class looks like this:\n\n<div class=\"aside\">For now, the implementation of this class isn't important. I'm showing you this only so you have context in future lessons that will refer to this repository. The important note is that this repository is _reactive_, and closely imitates Firestore. Whenever the data store is updated, it emits new information via a Stream of a List of Tasks.</div>\n\n```dart\nimport 'package:calendar_app_repository/src/mock_web_client.dart';\nimport 'package:rxdart/subjects.dart';\nimport 'model/todo.dart';\n\n/// This is a _reactive_ class that talks to a web-client.\n/// The API of this class is written in a way that allows your\n/// app to consume the data in a reactive way, which means\n/// it behaves similarly to Firestore.\nclass TodoRepository {\n  final WebClient client;\n  final BehaviorSubject<List<Task>> _subject;\n  bool _loaded = false;\n\n  TodoRepository(this.client, {List<Task> seed})\n      : _subject = BehaviorSubject<List<Task>>.seeded(seed ?? []);\n\n  Stream<List<Task>> get todos {\n    if (!_loaded) _loadTodos();\n\n    return _subject.stream;\n  }\n\n  List<Task> get snapshot => _subject.value ?? [];\n\n  void _loadTodos() {\n    _loaded = true;\n\n    client.fetchTodos().then((todos) {\n      _subject.add([..._subject?.value, ...todos]);\n    });\n  }\n\n  Future<void> addNewTodo(Task todo) async {\n    final newTodos = [..._subject.value, todo];\n    _subject.add([..._subject.value, todo]);\n    await client.postTodos(newTodos);\n  }\n\n  Future<void> deleteTodo(Task todo) async {\n    final newTodos = _subject.value.where((t) => t.description != todo.description);\n    _subject.add(newTodos);\n    await client.postTodos(newTodos);\n  }\n\n  Future<void> updateTodo(Task todo) async {\n    final todos = _subject.value;\n    final todoToUpdate = todos.firstWhere((t) => t.description == todo.description);\n    final index = todos.indexOf(todoToUpdate);\n    todos.replaceRange(index, index + 1, [todo]);\n    _subject.add(todos);\n    await client.postTodos(todos);\n  }\n}\n```","created_at":"2020-07-25T14:57:03.087Z","id":92,"slug":"calendar-app-introduction","title":"Calendar App introduction","tutorial":10,"updated_at":"2020-07-25T15:29:51.654Z"}}},"staticQueryHashes":["2185715291","3564968493","63159454"]}