{"id":13550673,"url":"https://github.com/klisiewicz/flutter-bloc-patterns","last_synced_at":"2025-04-07T06:08:33.698Z","repository":{"id":42186915,"uuid":"196560163","full_name":"klisiewicz/flutter-bloc-patterns","owner":"klisiewicz","description":"A set of most common BLoC use cases built on top of flutter_bloc library","archived":false,"fork":false,"pushed_at":"2024-02-14T22:30:08.000Z","size":254,"stargazers_count":327,"open_issues_count":2,"forks_count":32,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T05:05:16.989Z","etag":null,"topics":["bloc","dart","dartlang","flutter","flutter-bloc","flutter-bloc-pattern","flutter-bloc-patterns","flutter-package","library","state-management"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/klisiewicz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-07-12T10:30:48.000Z","updated_at":"2025-03-29T03:20:34.000Z","dependencies_parsed_at":"2023-11-30T11:23:28.759Z","dependency_job_id":"ff312370-967a-4687-81b8-9674fb43f21b","html_url":"https://github.com/klisiewicz/flutter-bloc-patterns","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klisiewicz%2Fflutter-bloc-patterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klisiewicz%2Fflutter-bloc-patterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klisiewicz%2Fflutter-bloc-patterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klisiewicz%2Fflutter-bloc-patterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/klisiewicz","download_url":"https://codeload.github.com/klisiewicz/flutter-bloc-patterns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247601448,"owners_count":20964864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bloc","dart","dartlang","flutter","flutter-bloc","flutter-bloc-pattern","flutter-bloc-patterns","flutter-package","library","state-management"],"created_at":"2024-08-01T12:01:36.028Z","updated_at":"2025-04-07T06:08:33.680Z","avatar_url":"https://github.com/klisiewicz.png","language":"Dart","readme":"# Flutter BLoC patterns\n\n[![Codemagic build status](https://api.codemagic.io/apps/5d28ebe2db95112ead3bbeb9/5d28ebe2db95112ead3bbeb8/status_badge.svg)](https://codemagic.io/apps/5d28ebe2db95112ead3bbeb9/5d28ebe2db95112ead3bbeb8/latest_build) [![Star on GitHub](https://img.shields.io/github/stars/klisiewicz/flutter-bloc-patterns.svg?style=flat\u0026logo=github\u0026colorB=deeppink\u0026label=Stars)](https://github.com/klisiewicz/flutter-bloc-patterns) [![License: MIT](https://img.shields.io/badge/License-MIT-purple.svg)](https://opensource.org/licenses/MIT)\n\n---\nA set of most common BLoC use cases build on top [flutter_bloc](https://github.com/felangel/bloc/tree/master/packages/flutter_bloc) library.\n\n## Key contepts\n\n##### BLoC\n\nBLoC, aka **B**usiness **Lo**gic **C**omponent, is a state management system for Flutter. It's main goal is to separate business logic from the presentation layer. The BLoC handles user actions or any other events and generates new state for the view to render.\n\n##### Repository\n\nA `Repository` to handles data operations. It knows where to get the data from and what API calls to make when data is updated. A `Repository` can utilize a single data source as well as it can be a mediator between different data sources, such as database, web services and caches.\n\n##### ViewStateBuilder\n\n`ViewStateBuilder` is responsible for building the UI based on the view state. It's a wrapper over the `BlocBuilder` widget so it accepts a `bloc` object and a set of handy callbacks, which corresponds to each possible state:\n\n* `initial` - informs the presentation layer that view is in it's initial state, and no action has taken place yet,\n* `loading` - informs the presentation layer that the data is being loaded, so it can display a loading indicator,\n* `refreshing` - informs the presentation layer that the data is being refreshed, so it can display a refresh indicator or/and the current state of list items,\n* `data` - informs the presentation layer that the loading is completed and a `nonnull` and not empty data was retrieved,\n* `empty` - informs the presentation layer that the loading is completed, but `null` or empty data was retrieved,\n* `error` - informs the presentation layer that the loading or refreshing has ended with an error. It also provides an error that has occurred.\n\n##### ViewStateListener\n\n`ViewStateListener` is responsible for performing an action based on the view state. It should be used for functionality that needs to occur only in response to a state change such as navigation, showing a `SnackBar` etc. `ViewStateListener` is a wrapper over the `BlocListener` widget so it accepts a `bloc` object as well as a `child` widget and a set of handy callbacks corresponding to a given state:\n\n* `onLoading` - informs the presentation layer that the data is being loaded,\n* `onRefreshing` - informs the presentation layer that the data is being refreshed,\n* `onData` - informs the presentation layer that the loading is completed and a `nonnull` and not empty data was retrieved,\n* `onEmpty` - informs the presentation layer that the loading is completed, but `null` or empty data was retrieved,\n* `onError` - informs the presentation layer that the loading or refreshing has ended with an error. It also provides an error that has occurred.\n\n## Features\n\n### ListBloc\n\nThe most basic use case. Allows to fetch, refresh and display a list of items without filtering and pagination. Thus, `ListBloc` should be used only with a reasonable amount of data.\n\n`ListBloc` provides the methods for loading and refreshing data:\n\n* `loaditems()` - most suitable for initial data fetch or for retry action when the first fetch fails,\n* `refreshitems()` - designed for being called after the initial fetch succeeds.\n\nTo display the current view state `ListBloc` cooperates with `BlocBuilder` as well as `ViewStateBuilder`.\n\n##### ListRepository\n\nA `ListRepository` implementation should provide only one method:\n\n* `Future\u003cList\u003cT\u003e\u003e getAll();` - this method is responsible for providing all the data to the `ListBloc`.\n\nWhere:\n* `T` is the item type returned by this repository.\n\n##### Usage\n\n[List BLoC Sample App](example/lib/src/list_app.dart)\n\n### FilterListBloc\n\nAn extension to the `ListBloc` that allows filtering.\n\n##### FilterRepository\n\n`FilterListRepository` provides two methods:\n\n* `Future\u003cList\u003cT\u003e\u003e getAll();` - this method is called when a `null` filter is provided and should return all items,\n* `Future\u003cList\u003cT\u003e\u003e getBy(F filter);` - this method is called with `nonnull` filter and should return only items that match it.\n\nWhere:\n* `T` is the item type returned by this repository,\n* `F` is the filter type, which can be primitive as well as complex object.\n\n#### Usage\n\n[Filter List BLoC Sample App](example/lib/src/list_filter_app.dart)\n\n### PagedListBloc\n\nA list BLoC with pagination but without filtering. It works best with [Infinite Widgets](https://github.com/jaumard/infinite_widgets) but a custom presentation layer can be provided as well.\n\n#### Page\n\nContains information about the current page, this is `number` and `size`.\n\n#### PagedList\n\nList of items with information if there are more items or not.\n\n#### PagedListRepository\n\n`PagedListRepository` comes with only one method:\n\n* `Future\u003cList\u003cT\u003e\u003e getAll(Page page);` - this method retrieves items meeting the pagination restriction provided by the `page` object.\nWhen items are exceeded it should return an empty list or throw `PageNotFoundException`. `PagedListBloc` will handle both cases in the same way.\n\nWhere:\n* `T` is the item type returned by this repository.\n\n#### Usage\n\n[Paged List BLoC Sample App](example/lib/src/list_paged_app.dart)\n\n### PagedListFilterBloc\n\nA list BLoC with pagination and filtering. It works best with [Infinite Widgets](https://github.com/jaumard/infinite_widgets) but a custom presentation layer can be provided as well.\n\n#### Page\n\nContains information about the current page, this is `number` and `size`.\n\n#### PagedList\n\nList of items with information if there are more items or not.\n\n#### PagedListFilterRepository\n`PagedListFilterRepository` provides only two methods:\n\n* `Future\u003cList\u003cT\u003e\u003e getAll(Page page);` - retrieves items meeting the pagination restriction provided by the `page` object.\n* `Future\u003cList\u003cT\u003e\u003e getBy(Page page, F filter);` - retrieves items meeting pagination as well as the filter restrictions provided by the `page` and `filter` objects.\n\nWhen items are exceeded it should return an empty list or throw `PageNotFoundException`. `PagedListFilterBloc` will handle both cases in the same way.\n\nWhere:\n* `T` is the item type returned by this repository,\n* `F` is the filter type, which can be primitive as well as complex object.\n\n#### Usage\n\n[Paged List BLoC Sample App](example/lib/src/list_paged_filter_app.dart)\n\n### DetailsBloc\n\nA BLoC that allows to fetch a single item with given identifier.\n\n#### DetailsRepository\n\n`DetailsRepository` comes with only one method:\n\n* `Future\u003cT\u003e getById(I id);` - this method retrieves an item with given id. When there's no item matching the id the `null` should be returned. In this cases the `DetailsBloc` will emit `Empty` state.\n\nWhere:\n* `T` is the item type returned by this repository,\n* `I` is the id type, it can be primitive as well as a complex object.\n\n#### Usage:\n\n[List/Details BLoC Sample App](example/lib/src/list_details_app.dart)\n\n### ConnectionBloc\n\nA BLoC that exposes the Internet connection state to the UI.\n\n#### Connection\n\nThe Internet connection state. It can be either `online` or `offline`.\n\n#### ConnectionRepository\n\n`ConnectionRepository` notifies about connection state changes, such as going online or offline. \n\nPlease notice, that this is only a contract and a developer needs to provide an implementation. This can be done using one of many popular packages, like:\n\n* [connectivity_plus](https://pub.dev/packages/connectivity_plus)\n* [internet_connection_checker](https://pub.dev/packages/internet_connection_checker)\n\nOr whatever works for you. A sample implementation using `connectivity_plus` may look as follows:\n\n```dart\nclass ConnectivityPlusRepository implements ConnectionRepository {\n  @override\n  Stream\u003cConnection\u003e observe() {\n    // Required due to https://github.com/fluttercommunity/plus_plugins/issues/2527\n    return MergeStream([\n      Stream.fromFuture(_connectivity.checkConnectivity()),\n      _connectivity.onConnectivityChanged,\n    ]).map(\n          (ConnectivityResult result) =\u003e result != ConnectivityResult.none\n          ? Connection.online\n          : Connection.offline,\n    );\n  }\n}\n```\n\n#### ConnectionBuilder\n\n`ConnectionBuilder` is responsible for building the UI based `Connection` state.\n\nIt's a wrapper over the `BlocBuilder` widget so it accepts a `bloc` object and provides `WidgetBuilder` functions for possible states:\n\n* `online` - a builder for the the `Connection.online` state,\n* `offline` - a builder for the the `Connection.offline` state,\n\n#### ConnectionListener\n\n`ConnectionListener` is responsible for performing a one-time action based on the `Connection` state change.\n\nIt should be used for functionality that needs to occur only once in response to the `Connection` state change such as navigation, `SnackBar`, showing a `Dialog`, etc.\n\n`ConnectionListener` is a wrapper over the `BlocListener` widget so it accepts a `bloc` object as well as a `child` widget. It also takes `ConnectionCallback` functions for possible states:\n\n* `onOnline` - a callback for the the `Connection.online` state,\n* `onOffline` - a callback for the `Connection.offline` state.\n\n#### Usage:\n\n[Connection Sample App](example/lib/src/connection_app.dart)\n\n## Dart version\n\n- Dart 3: \u003e= 3.0.0\n\n## Author\n- [Karol Lisiewicz](https://github.com/klisiewicz)\n","funding_links":[],"categories":["Dart"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklisiewicz%2Fflutter-bloc-patterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fklisiewicz%2Fflutter-bloc-patterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklisiewicz%2Fflutter-bloc-patterns/lists"}