import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../../Controller/account_controller.dart'; import '../../Controller/transaction_controller.dart'; import '../../Repositories/transaction_repository.dart'; /// Stellt einen Chart des Monats-Kontostands dar class MonthlyBalanceChart extends StatefulWidget { /// Erstellt eine neue Instanz dieser Klasse const MonthlyBalanceChart({ super.key, this.amountMax, this.amountMin, this.dateFrom, this.dateTo, this.name, }); /// Der Name der Transaktion, nach der gesucht werden soll final String? name; /// Der Mindestbetrag der Transaktion, nach der gesucht werden soll final double? amountMin; /// Der Maximalbetrag der Transaktion, nach der gesucht werden soll final double? amountMax; /// Das Datum der Transaktionen, ab dem gestartet wurde final DateTime? dateFrom; ///Das Datum der Transaktionen, bis zu welchen beendet wurde final DateTime? dateTo; @override State createState() => _MonthlyBalanceChart(); } class _MonthlyBalanceChart extends State { final TransactionRepository _transactionRepository = TransactionRepository(); final AccountController _accountController = AccountController(); final TransactionController _transactionController = TransactionController(); @override void initState() { _transactionRepository.monthlyBalances( account: _accountController.selected.value, name: widget.name, amountMin: widget.amountMin, amountMax: widget.amountMax, dateFrom: widget.dateFrom, dateTo: widget.dateTo, ); super.initState(); _transactionController.transactions.addListener(() { if (mounted) { setState(() {}); } }); } @override Widget build(final BuildContext context) => FutureBuilder( future: _transactionRepository.monthlyBalances( account: _accountController.selected.value, name: widget.name, amountMin: widget.amountMin, amountMax: widget.amountMax, dateFrom: widget.dateFrom, dateTo: widget.dateTo, ), builder: ( final BuildContext context, final AsyncSnapshot>> snapshot, ) { final ThemeData theme = Theme.of(context); if (snapshot.hasData) { final List> monthlyBalances = snapshot.data!; double maxBalance = 0; double minBalance = 0; for (final value in monthlyBalances) { if (maxBalance < value['balance']) { maxBalance = value['balance']; } if (minBalance > value['balance']) { minBalance = value['balance']; } } return SizedBox( height: 180, child: LineChart( LineChartData( minY: minBalance, maxY: maxBalance, titlesData: FlTitlesData( topTitles: const AxisTitles(), rightTitles: const AxisTitles(), bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 28, interval: 1, getTitlesWidget: (final double value, final TitleMeta meta) { final List months = monthlyBalances.map(( final value, ) { final DateTime date = value['date']; final DateFormat format = DateFormat('MMMM'); return format.format(date); }).toList(); if (value.toInt() >= 0 && value.toInt() < months.length) { return Text(months[value.toInt()]); } return const Text(''); }, ), ), leftTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 50, getTitlesWidget: (final double value, final TitleMeta meta) => Text( '${value.toInt()} €', style: const TextStyle(fontSize: 12), ), ), ), ), lineBarsData: [ LineChartBarData( spots: List.generate( monthlyBalances.length, (final int index) => FlSpot( index.toDouble(), monthlyBalances[index]['balance'], ), ), isCurved: true, barWidth: 3, color: theme.colorScheme.primary, ), ], ), ), ); } else if (snapshot.hasError) { return Center( child: Column( children: [ Icon(Icons.error, color: theme.colorScheme.error), const Text('Fehler beim holen der Monatsübersicht!'), ], ), ); } else { return const Center(child: CircularProgressIndicator()); } }, ); }