DEV Community

Cover image for Building a Crypto Price Tracker with Flutter
Francis
Francis

Posted on

Building a Crypto Price Tracker with Flutter

Introduction

In this article, we will be building a crypto currency price tracker using flutter and Coingecko API. Flutter is google UI framework used to develop beautiful and high performance app.

Note: There are tons of other API similar to coingecko with similar JSON format such as coinmarket cap api, nomics api etc. I selected coingecko API because it does not require an API key so we can just dive straight into building our application.

Building the app

  1. I will name the app price_tracker
flutter create price_tracker
Enter fullscreen mode Exit fullscreen mode
  1. Using JSON fomatter to fomat the api data, this is the forrmat of the http response we get from Coingecko api. This will enable us understand the data and decide how to consume the API
  {
    "id": "bitcoin",
    "symbol": "btc",
    "name": "Bitcoin",
    "image": "https://assets.coingecko.com/coins/images/1/large/bitcoin.png?1547033579",
    "current_price": 20745,
    "market_cap": 398249682812,
    "market_cap_rank": 1,
    "fully_diluted_valuation": 435734103282,
    "total_volume": 28619200860,
    "high_24h": 20939,
    "low_24h": 20662,
    "price_change_24h": -9.171288688139612,
    "price_change_percentage_24h": -0.04419,
    "market_cap_change_24h": 605958922,
    "market_cap_change_percentage_24h": 0.15239,
    "circulating_supply": 19193456,
    "total_supply": 21000000,
    "max_supply": 21000000,
    "ath": 69045,
    "ath_change_percentage": -69.94973,
    "ath_date": "2021-11-10T14:24:11.849Z",
    "atl": 67.81,
    "atl_change_percentage": 30497.91006,
    "atl_date": "2013-07-06T00:00:00.000Z",
    "roi": null,
    "last_updated": "2022-10-30T12:11:45.415Z"
  }
Enter fullscreen mode Exit fullscreen mode
  1. Then create a model class (CryptoTracker) for JSON deserialization of the http response body. Note use the num datatype for the currentPrice, marketCap and totalVolume because the values could be either int or double at any time. Theen create an empty list (cryptoList) which after decoding the response from our request, will pass the necessary data into the list.

import 'dart:convert';

List<dynamic> cryptoTrackerFromJson(String str) => List<CryptoTracker>.from(
    json.decode(str).map((x) => CryptoTracker.fromJson(x)));
var cryptoList = [];

class CryptoTracker {
  CryptoTracker({
    required this.id,
    required this.symbol,
    required this.name,
    required this.image,
    required this.currentPrice,
    required this.marketCap,
  });

  String id;
  String symbol;
  String name;
  String image;
  num currentPrice;
  num marketCap;

  factory CryptoTracker.fromJson(Map<String, dynamic> json) => CryptoTracker(
        id: json["id"],
        symbol: json["symbol"],
        name: json["name"],
        image: json["image"],
        currentPrice: json["current_price"],
        marketCap: json["market_cap"],
      );
}

Enter fullscreen mode Exit fullscreen mode
  1. Create the homepage and write the API services function (trackerData()). Then pass the response to the cryptoList (we created this previously in our model file).
 Future<List<dynamic>?> trackerData() async {
    String apiEndpoint =
        "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false";
    var url = Uri.parse(apiEndpoint);
    var response = await http.get(url);
    if (response.statusCode == 200) {
      var res = response.body;
      cryptoList = cryptoTrackerFromJson(res);
      setState(() {
        cryptoList;
      });
      return cryptoList;
    } else {
      return null;
    }
  }

Enter fullscreen mode Exit fullscreen mode
  1. In the initState pass the trackerData()to make sure the function is initialised when the homepage is opened. Also add a Timer to run the function after 4 seconds; this is to get the updated JSON response from the Coingecko API automatically without refreshing the application.

  void initState() {
    trackerData();
    Timer.periodic(const Duration(seconds: 4), (timer) => trackerData());

    super.initState();
  }
Enter fullscreen mode Exit fullscreen mode
  1. Then create the rest of the body and add a refresh indicator to be able to refresh the app.
 @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("Crypto Price Tracker"),
          centerTitle: true,
          backgroundColor: Colors.black,
          elevation: 0.0,
          leading: const Icon(Icons.monetization_on_outlined),
        ),
        body: RefreshIndicator(
          onRefresh: trackerData,
          child: ListView.builder(
            itemCount: cryptoList.length,
            itemBuilder: (context, index) {
              if (cryptoList.isNotEmpty) {
                var snap = cryptoList[index];
                return CryptoCard(
                  name: snap.name,
                  symbol: snap.symbol,
                  image: snap.image,
                  currentPrice: snap.currentPrice.toDouble(),
                  marketCap: snap.marketCap.toDouble(),
                );
              } else {
                return const Center(
                  child: Text('Check your network,\n Pull to refresh'),
                );
              }
            },
          ),
        ));

Enter fullscreen mode Exit fullscreen mode
  1. Then create a custom crypto card widget which we pass into our home page to display the data recieved from the API.
import 'package:flutter/material.dart';

class CryptoCard extends StatelessWidget {
  CryptoCard({
    Key? key,
    required this.name,
    required this.symbol,
    required this.image,
    required this.currentPrice,
    required this.marketCap,
  }) : super(key: key);

  String name;
  String symbol;
  String image;
  double currentPrice;
  double marketCap;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 15, left: 10, right: 10),
      child: Container(
        decoration: BoxDecoration(
          color: Colors.grey,
          borderRadius: BorderRadius.circular(20),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.max,
          children: [
            Row(
              children: [
                Padding(
                  padding: const EdgeInsets.all(15.0),
                  child: Container(
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(20),
                      //
                    ),
                    height: 60,
                    width: 60,
                    child: Padding(
                      padding: const EdgeInsets.all(10.0),
                      child: Image.network(image),
                    ),
                  ),
                ),
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      FittedBox(
                        fit: BoxFit.scaleDown,
                        child: Text(
                          name,
                          style: TextStyle(
                            color: Colors.grey[900],
                            fontSize: 25,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                      Text(
                        symbol,
                        style: TextStyle(
                          color: Colors.grey[900],
                          fontSize: 20,
                        ),
                      ),
                    ],
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(15.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Text(
                        "\$${currentPrice.toDouble().toString()}",
                        style: TextStyle(
                          color: Colors.grey[900],
                          fontSize: 20,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                const Text(
                  "Market Cap: ",
                  style: TextStyle(
                    color: Colors.black54,
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  "\$${marketCap.toDouble().toString()}",
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ],
            )
          ],
        ),
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

Voila we have our crypto price tracker ready.

Final note: The data returned by the API is bulky but we picked the ones we will be working with and built a model to assist in consuming only the data we require. If you are building a production ready application, consider using an API that will return data at a faster rate as the API we consumed updated price and other data at a much slower rate.

Download code:
GitHub Link

Link to original article at CodenJobs

To know more about codenjobs click [CodenJobs]((https://www.codenjobs.com)

Want to Connect?

This article is also published at codenjobs.com .
Enter fullscreen mode Exit fullscreen mode

Oldest comments (0)