{"id":19858569,"url":"https://github.com/danreynolds/endless","last_synced_at":"2026-02-22T03:01:32.890Z","repository":{"id":43031582,"uuid":"410447368","full_name":"danReynolds/endless","owner":"danReynolds","description":"An infinite scroll view library with out of the box widgets for loading using pagination, streams and Firestore streams.","archived":false,"fork":false,"pushed_at":"2023-03-16T15:18:43.000Z","size":782,"stargazers_count":3,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-01T01:02:04.713Z","etag":null,"topics":["firestore","flutter","grid","hacktoberfest","lists"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/endless","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/danReynolds.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}},"created_at":"2021-09-26T04:15:03.000Z","updated_at":"2024-04-18T01:38:54.000Z","dependencies_parsed_at":"2024-01-16T12:49:11.611Z","dependency_job_id":"ba0b7591-4a4c-4ee6-ba66-379b814307cb","html_url":"https://github.com/danReynolds/endless","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/danReynolds/endless","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danReynolds%2Fendless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danReynolds%2Fendless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danReynolds%2Fendless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danReynolds%2Fendless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danReynolds","download_url":"https://codeload.github.com/danReynolds/endless/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danReynolds%2Fendless/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29704400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T23:35:04.139Z","status":"online","status_checked_at":"2026-02-22T02:00:08.193Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["firestore","flutter","grid","hacktoberfest","lists"],"created_at":"2024-11-12T14:23:57.027Z","updated_at":"2026-02-22T03:01:32.866Z","avatar_url":"https://github.com/danReynolds.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Endless\n\nA scroll view library with out of the box widgets for infinite loading using [pagination](#pagination), [streams](#streams) and [Firestore streams](https://pub.dev/packages/endless_firestore). Built on top of [CustomScrollView](https://api.flutter.dev/flutter/widgets/CustomScrollView-class.html).\n\n![Demo](./demo.gif)\n\n# Features\n\n1. **Data loading**: Many scrollable lists should be populated with an initial set of items and then load more data as a user scrolls down the list. The main job of the library is to abstract that logic into an easy to use API for building infinite scroll views that dynamically load more data.\n2. **Common scrollable elements**: Many scroll view widgets have a common set of UI elements that are baked into the library including builders for *headers*, *footers*, *loading indicators*, and *empty states*.\n3. **Multiple data sources**: Support for multiple types of data sources out of the box like paginated APIs and streams in order to minimize the amount of data massaging clients have to do when working with scroll views.\n4. **Lists + Grids**: For Flutter mobile apps, the majority of the time scrollable views use lists, while on desktop, the added screen real estate is ideal for displaying items in grids. The library comes with both list and grid views with shared APIs.\n\n# Pagination\n\nThe most common data source for infinite lists is generally some sort of paginated API. The library comes with two pagination widgets `EndlessPaginationListView` and `EndlessPaginationGridView` for working with this type of data. Let's take a look at some basic examples: \n## Basic List Example\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:endless/endless.dart';\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        appBar: AppBar(title: Text('Endless pagination list view')),\n        body: EndlessPaginationListView\u003cString\u003e(\n          // An async function that returns a list of items to be added to the scroll view. When you scroll past the configurable\n          // `extentAfterFactor`, it calls `loadMore` to get more items.\n          loadMore: (pageIndex) async =\u003e {...},\n          // The pagination configuration for the scroll view determines when to stop fetching items.\n          // The scroll view will stop fetching more data for either of these reasons:\n          // 1. The number of items returned from loadMore is smaller than the given `pageSize`.\n          // 2. It has fetched the optional `maxPages` max number of specified pages.\n          paginationDelegate: EndlessPaginationDelegate(\n            pageSize: 5,\n            maxPages: 10,\n          ),\n          itemBuilder: (\n            context, {\n            required item,\n            required index,\n            required totalItems,\n          }) {\n            return Text(item);\n          },\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Basic Grid Example\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:endless/endless.dart';\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        appBar: AppBar(title: Text('Endless pagination grid view')),\n        body: EndlessPaginationGridView\u003cString\u003e(\n          loadMore: (pageIndex) async =\u003e {...},\n          paginationDelegate: EndlessPaginationDelegate(\n            pageSize: 5,\n            maxPages: 10,\n          ),\n          // The only difference between the basic list and grid view is that a grid specifies its delegate such as how many items\n          // to put in the cross axis.\n          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(\n            crossAxisCount: 3,\n          ),\n          itemBuilder: (\n            context, {\n            required item,\n            required index,\n            required totalItems,\n          }) {\n            return Text(item);\n          },\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Advanced Example\n\n`Endless` scroll views support a set of optional builder functions to build complex infinite scrolling lists with the following top-to-bottom UI:\n\n```text\nHeader -\u003e headerBuilder\nItems -\u003e itemBuilder\nEmpty state -\u003e emptyBuilder\nLoading spinner -\u003e loadingBuilder\nLoad more widget (such as a TextButton) -\u003e loadMoreBuilder\nFooter -\u003e footerBuilder\n```\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:endless/endless.dart';\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        appBar: AppBar(title: Text('Endless grid view')),\n        body: EndlessPaginationListView\u003cString\u003e(\n          loadMore: (pageIndex) async =\u003e {...},\n          paginationDelegate: EndlessPaginationDelegate(\n            pageSize: 5,\n            maxPages: 10,\n          ),\n          headerBuilder: () =\u003e Container(\n            color: Colors.blue,\n            child: const Text('Header'),\n          ),\n          itemBuilder: (\n            context, {\n            required item,\n            required index,\n            required totalItems,\n          }) {\n            return Text(item);\n          },\n        ),\n      ),\n    );\n  }\n}\n```\n\nIn this example, we've added a header to our list. Now what if we only wanted to show our header once we've loaded items? `Endless` scroll views use the `StateProperty` pattern found in\nFlutter Material's core widgets such as [Material State Property](https://api.flutter.dev/flutter/material/MaterialStateProperty-class.html).\n\nThe Material UI uses this pattern to let consumers of core widgets like `ElevatedButton` style it differently when it is in one more states (hover, pressed, etc). The basic example from the docs looks like this:\n\n```dart\nElevatedButton(\n  style: ButtonStyle(\n    // Use the color green as the background color for all button states.\n    backgroundColor: MaterialStateProperty.all\u003cColor\u003e(Colors.green),\n  ),\n);\n\nElevatedButton(\n  style: ButtonStyle(\n    backgroundColor: MaterialStateProperty.resolveWith\u003cColor\u003e(\n      // The state property passes all the current states the button is in\n      // so that the button style can be customized.\n      (Set\u003cMaterialState\u003e states) {\n        // Lighten the button color when it is in the pressed state. \n        if (states.contains(MaterialState.pressed))\n          return Theme.of(context).colorScheme.primary.withOpacity(0.5);\n        return null;\n      },\n    ),\n  ),\n);\n```\n\nWe use this same pattern to support customization by the state of the scroll view. The possible states are:\n\n```dart\nenum EndlessState { empty, loading, done }\n```\n\nWe can then check the current states of the scroll view to customize our header:\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:endless/endless.dart';\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        appBar: AppBar(title: Text('Endless pagination list view')),\n        body: EndlessPaginationListView\u003cString\u003e(\n          loadMore: (pageIndex) async =\u003e {...},\n          paginationDelegate: EndlessPaginationDelegate(\n            pageSize: 5,\n            maxPages: 10,\n          ),\n          // Each builder has a corresponding state property builder for state-dependent UI.\n          headerBuilderState: EndlessStateProperty.resolveWith((states) {\n            if (states.contains(EndlessState.empty)) {\n              return null;\n            }\n\n            return Container(\n              color: Colors.blue,\n              child: const Text('Header'),\n            );\n          }),\n          itemBuilder: (\n            context, {\n            required item,\n            required index,\n            required totalItems,\n          }) {\n            return Text(item);\n          },\n        ),\n      ),\n    );\n  }\n}\n```\n\nThe full list of endless state property helpers are given below:\n\n* `EndlessStateProperty.all`\n* `EndlessStateProperty.loading`\n* `EndlessStateProperty.empty`\n* `EndlessStateProperty.done`\n* `EndlessStateProperty.never`\n* `EndlessStateProperty.resolveWith`\n\n\nSome builder functions have default state property behaviors. The `emptyBuilder` parameter for example is automatically wrapped in an `emptyStateBuilder` defined to only be built if the scroll view is empty and not loading as shown below:\n\n```dart\nEndlessStateProperty\u003cWidget?\u003e resolveEmptyBuilderToStateProperty(\n  Builder\u003cWidget\u003e? builder,\n) {\n  return _resolveBuilderToStateProperty\u003cWidget\u003e(\n    builder,\n    (Builder\u003cWidget\u003e builder) =\u003e\n        EndlessStateProperty.resolveWith\u003cWidget\u003e((context, states) {\n      if (states.contains(EndlessState.empty) \u0026\u0026\n          !states.contains(EndlessState.loading)) {\n        return builder(context);\n      }\n      return null;\n    }),\n  );\n}\n```\n\nThe goal of these defaults like for the `empty` state is to provide typical behavior for an endless scroll view. If that's not the default you would like for your empty state, no problem! You can always provide your own `emptyBuilderState` to override it.\n\n# Streams\n\n## Basic Example\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:endless/endless.dart';\n\nfinal streamController = StreamController\u003cList\u003cString\u003e\u003e();\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        appBar: AppBar(title: Text('Endless stream list view')),\n        body: EndlessStreamListView\u003cString\u003e(\n          // A function called when you scroll past the configurable `extentAfterFactor` to tell the stream to add more items.\n          loadMore: () =\u003e {...},\n          // Items emitted on the stream are added to the scroll view. The scroll view knows to not try and fetch any more items\n          // once the stream has completed.\n          stream: streamController.stream,\n          itemBuilder: (\n            context, {\n            required item,\n            required index,\n            required totalItems,\n          }) {\n            return Text(item);\n          },\n        ),\n      ),\n    );\n  }\n}\n```\n\nAll other APIs for streams are the same as in the first examples with pagination, so check out a grid view and advanced example under the [pagination](#pagination) section.\n\n# 3rd Party Extensions\n\n## Firestore\n\nThe Endless Firestore extension is available as a [separate package](https://pub.dev/packages/endless_firestore).\n\n## Working Example\n\nRun the [example](https://github.com/danReynolds/endless/tree/master/example/example) to give it a try and play around with the config options.\n\n## Feedback \u0026 Extensions\n\nIt's pretty straightforward to add support for other scroll view loading patterns (in addition pagination and streaming) or 3rd party extensions `endless_firestore` so make an issue if you have a new use case you're interested in seeing added.\n\nHappy coding!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanreynolds%2Fendless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanreynolds%2Fendless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanreynolds%2Fendless/lists"}