Flutter Starter: Guide to Building a GitHub Repo List App

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 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

To learn more about this example, visit the GitHub Repo List App page.

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

//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:

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:

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:

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:

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:

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:

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:

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:

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

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 and our other examples. If you would like to learn more about Flutter Starter, please visit our official documentation.

This article was written by Sumant Raj and Madhav B. Edited by Kavya V.

Flutter-Starter-Banner1.png