# Flutter Starter: Guide to Building a GitHub Repo List App

As an app developer, you know that creating a production-level mobile app from scratch is time-consuming, tedious and costly. Look no further devs! **[Flutter Starter](https://flutter-starter.github.io/?utm_source=Flutter%20Starter&utm_medium=Blog&utm_campaign=2nd%20Tutorial%20Article)** is a kit that will accelerate your creation process. 

Bootstrap your projects with the required modules such as State Management, API calls, Styleguide, etc and build production-ready apps in a jiffy. Flutter Starter also enables you to handle everything at one place so you don't have to rewrite code. Here's a quick look at the kit:

![Flutter_Starter.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608825163659/eaGcfC-Aw.gif)

To learn more about this example, visit the [GitHub Repo List App](https://github.com/GeekyAnts/flutter-starter/tree/master/examples/github-repository-list?utm_source=Flutter%20Starter&utm_medium=Blog&utm_campaign=2nd%20Tutorial%20Article) page.

The API URL is in `api-constants.dart.` Go to your GitHub account and create a personal access token:

```dart
//For the graphql.
import 'package:graphql/client.dart';

OptimisticCache cache = OptimisticCache(
  dataIdFromObject: typenameDataIdFromObject,
);
GraphQLClient client() {
  final HttpLink _httpLink = HttpLink(
    uri: 'https://api.github.com/graphql',
  );

  final AuthLink _authLink = AuthLink(
    getToken: () => 'Bearer <YOUR GITHUB API TOKEN>',
  );

  final Link _link = _authLink.concat(_httpLink);

  return GraphQLClient(
    cache: cache,
    link: _link,
  );
}

//For the Rest
Map<String, String> apiConstants = {"auth": "https://reqres.in/api"};

```

The following code in *graphql_handler.dart* defines the method which will return the *QueryResult* for *getRepositories* method:

```dart
Future<QueryResult> getRepositories(int numOfRepositories) async {
    final WatchQueryOptions _options = WatchQueryOptions(
      documentNode: parseString(queries.readRepositories),
      variables: <String, dynamic>{
        'nRepositories': numOfRepositories,
      },
      pollInterval: 4,
      fetchResults: true,
    );

    return await client.query(_options);
  }
```

In *main.dart,* we need a function *fetchGithubRepoGraphQl* that takes *numOfRespositories* as the argument and gets the GitHub repositories as a response:

```dart
static fetchGithubRepoGraphQl(numOfRepositories) async {
    final GraphqlQlHandler githubRepository =
        GraphqlQlHandler(client: client());
    final response = await githubRepository.getRepositories(numOfRepositories);
    return response;
  }
```

The API SDK is now a black box from which we will just call the method *fetchGithubRepoGraphQl* which will return a JSON response.

Now that we have the data, it needs to be called, parsed and stored. Proceed to the *shared* folder which contains *blocs*, *models* and *resources*.

**Resources:**

In *github_repo_resouces.dart,* the getData function will call API SDK method to fetch GitHub repositories and create a list of *Repo* models defined in *models*/*repo.dart:*

```dart
class GithubRepoResources {
  static Future<List<Repo>> getData() async {
    final response = await ApiSdk.fetchGithubRepoGraphQl(10);
    final List<dynamic> repos =
        response.data['viewer']['repositories']['nodes'] as List<dynamic>;

    final List<Repo> listOfRepos = repos
        .map((dynamic e) => Repo(
              id: e['id'] as String,
              name: e['name'] as String,
              viewerHasStarred: e['viewerHasStarred'] as bool,
            ))
        .toList();

    return listOfRepos;
  }
}
```

The *repo.dart* file in the *models* folder contains the following code:

```dart
class Repo {
  const Repo({
    this.id,
    this.name,
    this.viewerHasStarred,
    this.isLoading: false,
  });

  final String id;
  final String name;
  final bool viewerHasStarred;
  final bool isLoading;
}
```

We have used *GithubRepoResources* to call getData in *github_repo_bloc.dart*:

```dart
if (event is GithubRepoDataLoadingEvent) {
      yield GithubRepoStateLoading();
      var fetchedData = await GithubRepoResources.getData();
      yield GithubRepoDataLoadedState(repositoryData: fetchedData);
    }
```

Now that we have the data, we will create an instance of GithubRepoBloc in *github_repo_bloc_controller.dart* as shown below:

```dart
class GithubRepoBlocController {
  GithubRepoBlocController._();
  static GithubRepoBlocController _instance = GithubRepoBlocController._();
  factory GithubRepoBlocController() => _instance;

  // ignore: close_sinks
  GithubRepoBloc authenticationBloc = GithubRepoBloc();
}
```

We can now move on to the app.

In *github_repo_list_screen.dart*, we will get the instance of GithubRepoBloc in its initState:

```dart
void initState() {
    githubRepoBloc = GithubRepoBlocController().authenticationBloc;
    githubRepoBloc.add(GithubRepoDataLoadingEvent());
    super.initState();
  }
```

Finally, use BlocBuilder in *github_repo_list_screen.dart* to build the required widget according to the states:

```dart
Widget build(BuildContext context) {
    return BlocBuilder<GithubRepoBloc, GithubRepoState>(
        cubit: githubRepoBloc,
        builder: (BuildContext context, GithubRepoState state) {
          if (state is GithubRepoStateLoading) {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
          if (state is GithubRepoDataLoadedState) {
            return ListView.builder(
              shrinkWrap: true,
              itemCount: state.repositoryData.length,
              itemBuilder: (BuildContext context, int index) {
                return Column(
                  children: [
                    ListTile(
                      title: Text(
                        state.repositoryData[index].name.toUpperCase(),
                        style: Theme.of(context).textTheme.bodyText2,
                      ),
                      trailing: state.repositoryData[index].viewerHasStarred
                          ? Icon(Icons.star)
                          : SizedBox(),
                    ),
                    Divider(
                      height: 10.0,
                    )
                  ],
                );
              },
            );
          }
          return SizedBox();
        });
  }
```

**Your app should look like this:**

![Github (1).gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608824967405/eF1FGjXde.gif)

Ta-da! You've created your very own GitHub Repo List app. Interested in creating more apps with Flutter Starter? Check out our guide to building a [Hacker News app](https://techblog.geekyants.com/flutter-starter-guide-to-building-a-hacker-news-app?utm_source=Flutter%20Starter&utm_medium=Blog&utm_campaign=2nd%20Tutorial%20Article) and our [other examples](https://github.com/GeekyAnts/flutter-starter/tree/master/examples?utm_source=Flutter%20Starter&utm_medium=Blog&utm_campaign=2nd%20Tutorial%20Article). If you would like to learn more about Flutter Starter, please visit our [official documentation](https://flutter-starter.github.io/?utm_source=Flutter%20Starter&utm_medium=Blog&utm_campaign=2nd%20Tutorial%20Article).

This article was written by [Sumant Raj](https://twitter.com/sumantraj2611?lang=en) and [Madhav B](https://twitter.com/madhavb23). Edited by Kavya V.


[![Flutter-Starter-Banner1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608824971712/wzpIhzPFA.png)](https://flutter-starter.github.io/?utm_source=Flutter%20Starter&utm_medium=Blog&utm_campaign=2nd%20Tutorial%20Article)

