{"id":17638864,"url":"https://github.com/verygoodopensource/very_good_infinite_list","last_synced_at":"2025-04-12T18:52:36.827Z","repository":{"id":37766471,"uuid":"337882111","full_name":"VeryGoodOpenSource/very_good_infinite_list","owner":"VeryGoodOpenSource","description":"A Very Good Infinite List Widget created by Very Good Ventures. Great for activity feeds, news feeds, and more. 🦄","archived":false,"fork":false,"pushed_at":"2025-03-03T13:13:54.000Z","size":1706,"stargazers_count":191,"open_issues_count":5,"forks_count":31,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-03T22:08:08.039Z","etag":null,"topics":["dart","flutter","flutter-package","infinite-list","infinite-scroll"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/very_good_infinite_list","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/VeryGoodOpenSource.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":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-10T23:28:27.000Z","updated_at":"2025-03-04T21:28:49.000Z","dependencies_parsed_at":"2022-08-29T06:50:54.376Z","dependency_job_id":"a3b80836-e6da-4d0a-9cc8-212942774bf9","html_url":"https://github.com/VeryGoodOpenSource/very_good_infinite_list","commit_stats":{"total_commits":57,"total_committers":11,"mean_commits":5.181818181818182,"dds":0.543859649122807,"last_synced_commit":"1bd52bdfa10c6a2d32ae3c7bc8a76a01135cb322"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VeryGoodOpenSource%2Fvery_good_infinite_list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VeryGoodOpenSource%2Fvery_good_infinite_list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VeryGoodOpenSource%2Fvery_good_infinite_list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VeryGoodOpenSource%2Fvery_good_infinite_list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VeryGoodOpenSource","download_url":"https://codeload.github.com/VeryGoodOpenSource/very_good_infinite_list/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248618243,"owners_count":21134200,"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":["dart","flutter","flutter-package","infinite-list","infinite-scroll"],"created_at":"2024-10-23T04:05:14.660Z","updated_at":"2025-04-12T18:52:36.800Z","avatar_url":"https://github.com/VeryGoodOpenSource.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Very Good Infinite List\n\n[![Very Good Ventures][logo_black]][very_good_ventures_link_light]\n[![Very Good Ventures][logo_white]][very_good_ventures_link_dark]\n\nDeveloped with 💙 by [Very Good Ventures][very_good_ventures_link] 🦄\n\n[![ci][ci_badge]][ci_link]\n[![coverage][coverage_badge]][ci_link]\n[![pub package][pub_badge]][pub_link]\n[![License: MIT][license_badge]][license_link]\n[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_badge_link]\n\n---\n\nA library for easily displaying paginated data, created by [Very Good Ventures][very_good_ventures_link].\n\n`InfiniteList` comes in handy when building features like activity feeds, news feeds, or anywhere else where you need to lazily fetch and render content for users to consume.\n\n## Example\n\n\u003ca href=\"https://github.com/VeryGoodOpenSource/very_good_infinite_list/blob/main/example/lib/main.dart\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_infinite_list/main/art/infinite_list.gif\" height=\"400\"/\u003e\u003c/a\u003e\n\n## Usage\n\nThe `InfiniteList` API is very similar to that of `ListView.builder`. A basic implementation requires four parameters:\n\n- An `itemCount` that represents the amount of items that should be rendered using the `itemBuilder`.\n- An `itemBuilder` that is responsible for returning a widget for every index of the `itemCount`.\n- A `hasReachedMax` flag that indicates if any more data is available.\n- An `onFetchData` callback that's triggered whenever new data should be fetched.\n\n## Example\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:very_good_infinite_list/very_good_infinite_list.dart';\n\nvoid main() =\u003e runApp(MyApp());\n\nclass MyApp extends StatefulWidget {\n  @override\n  _MyAppState createState() =\u003e _MyAppState();\n}\n\nclass _MyAppState extends State\u003cMyApp\u003e {\n  var _items = \u003cString\u003e[];\n  var _isLoading = false;\n\n  void _fetchData() async {\n    setState(() {\n      _isLoading = true;\n    });\n\n    await Future.delayed(const Duration(seconds: 1));\n\n    if (!mounted) {\n      return;\n    }\n\n    setState(() {\n      _isLoading = false;\n      _items = List.generate(_items.length + 10, (i) =\u003e 'Item $i');\n    });\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Simple Example'),\n      ),\n      body: InfiniteList(\n        itemCount: _items.length,\n        isLoading: _isLoading,\n        onFetchData: _fetchData,\n        separatorBuilder: (context, index) =\u003e const Divider(),\n        itemBuilder: (context, index) {\n          return ListTile(\n            dense: true,\n            title: Text(_items[index]),\n          );\n        },\n      ),\n    );\n  }\n}\n```\n\n### Customizations\n\n#### InfiniteList\n\n`InfiniteList` has multiple optional parameters which allow you to customize the loading and error behavior.\n\n```dart\nInfiniteList\u003cString\u003e(\n  itemCount: 3,\n  hasReachedMax: false,\n  onFetchData: () =\u003e _fetchData(),\n  itemBuilder: (context, index) =\u003e ListTile(title: Text('$index')),\n\n  // An optional [ScrollController] this [InfiniteList] will attach to.\n  // It's used to detect when the list has scrolled to the appropriate position\n  // to call [onFetchData].\n  //\n  // Is optional and mostly used only for testing. If set to `null`, an\n  // internal [ScrollController] is used instead.\n  scrollController: _scrollController,\n\n  // Indicates if new items are currently being loaded.\n  //\n  // While set to `true`, the [onFetchData] callback will not be triggered\n  // and the [loadingBuilder] will be rendered.\n  //\n  // Is set to `false` by default.\n  isLoading: false,\n\n  // Indicates if an error has occurred.\n  //\n  // While set to `true`, the [onFetchData] callback will not be triggered\n  // and the [errorBuilder] will be rendered.\n  //\n  // Is set to `false` by default.\n  hasError: false,\n\n  // Indicates if the list should be reversed.\n  //\n  // If set to `true`, the list of items, [loadingBuilder] and [errorBuilder]\n  // will be rendered from bottom to top.\n  //\n  // Is set to `false` by default.\n  reverse: false,\n\n  // The duration with which calls to [onFetchData] will be debounced.\n  //\n  // Is set to a duration of 100 milliseconds by default.\n  debounceDuration: const Duration(milliseconds: 100),\n\n  // The offset, in pixels, that the internal [ScrollView] must be scrolled over\n  // to trigger [onFetchData].\n  // \n  // Defaults to the same as [RenderAbstractViewport.defaultCacheExtent], which is 250.\n  cacheExtent: 250.0,\n\n  // The amount of space by which to inset the list of items.\n  //\n  // Is optional and can be `null`.\n  padding: const EdgeInsets.all(16.0),\n\n  // An optional builder that's shown when the list of items is empty.\n  //\n  // If `null`, nothing is shown.\n  emptyBuilder: (context) =\u003e const Center(child: Text('No items.')),\n  \n  // Flag used to center the empty builder, it is optional and defaults to false\n  centerEmpty: true,\n\n  // An optional builder that's shown at the end of the list when [isLoading]\n  // is `true`.\n  //\n  // If `null`, a default builder is used that renders a centered\n  // [CircularProgressIndicator].\n  loadingBuilder: (context) =\u003e const Center(child: CircularProgressIndicator()),\n\n  // Flag used to center the loading builder, it is optional and defaults to false\n  centerLoading: true,\n\n  // An optional builder that's shown when [hasError] is not `null`.\n  //\n  // If `null`, a default builder is used that renders the text `\"Error\"`.\n  errorBuilder: (context) =\u003e const Center(child: Text('Error')),\n\n  // Flag used to center the error builder, it is optional and defaults to false\n  centerError: true,\n\n  // An optional builder that, when provided, is used to show a widget in\n  // between every pair of items.\n  //\n  // If the [itemBuilder] returns a [ListTile], this is commonly used to render\n  // a [Divider] between every tile.\n  //\n  // Is optional and can be `null`.\n  separatorBuilder: (context, index) =\u003e const Divider(),\n\n  // An optional [Axis] to be used by the internal [ScrollView] that defines\n  // the axis of scroll. \n  //\n  // Is set to `Axis.vertical` by default.\n  scrollDirection: Axis.vertical,\n\n  // An optional [ScrollPhysics] to be used by the internal [ScrollView].\n  //\n  // Default to tha same as [ScrollView].\n  physics: const AlwaysScrollableScrollPhysics(),\n);\n```\n\nRefer to the [example](https://github.com/VeryGoodOpenSource/very_good_infinite_list/blob/main/example/lib/main.dart) to see both basic and complex usage of `InfiniteList`.\n\n[ci_badge]: https://github.com/VeryGoodOpenSource/very_good_infinite_list/workflows/ci/badge.svg\n[ci_link]: https://github.com/VeryGoodOpenSource/very_good_infinite_list/actions\n[coverage_badge]: https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_infinite_list/main/coverage_badge.svg\n[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg\n[license_link]: https://opensource.org/licenses/MIT\n[logo_black]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_black.png#gh-light-mode-only\n[logo_white]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_white.png#gh-dark-mode-only\n[pub_badge]: https://img.shields.io/pub/v/very_good_infinite_list.svg\n[pub_link]: https://pub.dartlang.org/packages/very_good_infinite_list\n[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg\n[very_good_analysis_badge_link]: https://pub.dev/packages/very_good_analysis\n[very_good_ventures_link]: https://verygood.ventures\n[very_good_ventures_link_dark]: https://verygood.ventures#gh-dark-mode-only\n[very_good_ventures_link_light]: https://verygood.ventures#gh-light-mode-only\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverygoodopensource%2Fvery_good_infinite_list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fverygoodopensource%2Fvery_good_infinite_list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverygoodopensource%2Fvery_good_infinite_list/lists"}