flutterasynchronousgoogle-cloud-firestoresyncfusionsyncfusion-chart

type 'Future<List<ChartSeries<BarChartModel, String>>>' is not a subtype of type 'List<ChartSeries<dynamic, dynamic>>'


I'm having a problem using Firestore and Syncfusion Flutter Charts in Flutter. I'm querying from firestore some documents, awaiting the result so the function must be a Future, but I need it to be a List, not a Future<List>. This is my code:

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: SfCartesianChart(
        primaryXAxis: CategoryAxis(
          majorGridLines: const MajorGridLines(width: 0),
          axisLine: const AxisLine(width: 0),
        ),
        primaryYAxis: NumericAxis(
          majorGridLines: const MajorGridLines(width: 0),
          axisLine: const AxisLine(width: 0),
        ),
        plotAreaBorderWidth: 0,
        series: getData(),
      ),
    );
  }

  String getcurrentMonth() {
    DateTime date = DateTime.now();
    return DateFormat.MMMM().format(date).substring(0, 3);
  }

  List<String> getOtherMonths() {
    List<String> otherMonths = [];
    DateTime date = DateTime.now();
    for (var i = 1; i < 5; i++) {
      DateTime prev = DateTime(date.year, date.month - i, date.day);
      otherMonths.add(DateFormat.MMMM().format(prev).substring(0, 3));
    }
    return otherMonths;
  }

  Future<List<double>> getTotalByMonth() async {
    List<double> totals = [];
    DateTime date = DateTime.now();
    for (var i = 0; i < 5; i++) {
      var lastDay = DateTime(date.year, date.month - i + 1, 0);
      DateTime startOfMonth = DateTime(date.year, date.month - i, 1);
      DateTime endOfMonth =
          DateTime(date.year, date.month - i, lastDay.day, 23, 59, 59, 999);
      Timestamp startTimestamp = Timestamp.fromDate(startOfMonth);
      Timestamp endTimestamp = Timestamp.fromDate(endOfMonth);
      await FirebaseFirestore.instance
          .collection('users/$uid/receipts')
          .where('date', isGreaterThanOrEqualTo: startTimestamp)
          .where('date', isLessThanOrEqualTo: endTimestamp)
          .get()
          .then((doc) {
        double monthTot = 0;
        doc.docs.forEach((element) {
          monthTot += element.data()['total'];
        });
        totals.add(monthTot);
      });
    }
    return totals;
  }

  Future<List<ChartSeries<BarChartModel, String>>> getData() async {
    String currentMonth = getcurrentMonth();
    List<String> months = getOtherMonths();
    months.insert(0, currentMonth);
    months = months.reversed.toList();
    List<double> totals = await getTotalByMonth();
    List<BarChartModel> data = [];
    for (var i = 0; i < 5; i++) {
      var obj = BarChartModel(months[i], totals[i],
          i % 2 == 0 ? const Color(0xff003f9a) : const Color(0xff468fea));
      data.add(obj);
    }
    return <ChartSeries<BarChartModel, String>>[
      ColumnSeries<BarChartModel, String>(
        dataSource: data,
        xValueMapper: (BarChartModel data, _) => data.month,
        yValueMapper: (BarChartModel data, _) => data.total,
        pointColorMapper: (BarChartModel data, _) => data.month == currentMonth
            ? const Color(0xffeaa146)
            : data.barColor,
        animationDuration: 1000,
        borderRadius: const BorderRadius.only(
          topRight: Radius.circular(5),
          topLeft: Radius.circular(5),
        ),
      ),
    ];
  }

And this is the model:

class BarChartModel {
  final String month;
  final double total;
  final Color barColor;

  BarChartModel(this.month, this.total, this.barColor);
}

This is the error I get when I reload the app:

type 'Future<List<ChartSeries<BarChartModel, String>>>' is not a subtype of type 'List<ChartSeries<dynamic, dynamic>>'

What's the best way to get rid of the Future type in this case?


Solution

  • A FutureBuilder widget will help here.

    Check out https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html for how to use a FutureBuilder.

    Basic idea: FutureBuilder will load the data that you want to show. During loading you will show a progressIndicator. When loading is finished the data can be showed, which will not be a future anymore, but the actual data.