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