import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; /// Eine Seite, die das Dashboard der App darstellt. /// /// Diese Seite zeigt eine Übersicht über den aktuellen Kontostand, /// die Entwicklung des Kontostands der letzten Monate sowie /// die letzten Transaktionen. class Dashboard extends StatelessWidget { /// Erstellt eine neue Instanz der Dashboard-Seite. const Dashboard({super.key}); /// Baut das Dashboard-Widget auf. /// [context] ist der Build-Kontext @override Widget build(final BuildContext context) { const double currentBalance = 4820.75; const double previousMonthBalance = 4300; final Map monthlyBalance = { 'Jan': 1200.0, 'Feb': 900.0, 'Mär': 1100.0, 'Apr': 950.0, 'Mai': 1300.0, 'Jun': 1050.0, }; final List> recentTransactions = >[ {'name': 'Supermarkt', 'amount': -45.50}, {'name': 'Gehalt', 'amount': 2500.00}, {'name': 'Miete', 'amount': -900.00}, {'name': 'Streaming', 'amount': -12.99}, {'name': 'Kaffee', 'amount': -4.50}, ]; return Scaffold( body: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _currentBalance(currentBalance, previousMonthBalance, context), const SizedBox(height: 32), const Text( 'Kontostand pro Monat', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 12), _monthlyBalance(monthlyBalance, context), const SizedBox(height: 32), const Text( 'Letzte Transaktionen', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 12), ..._recentTransactions(recentTransactions), ], ), ), ), ); } /// Baut das Widget für den aktuellen Kontostand /// und die Differenz zum Vormonat auf. /// /// [currentBalance] ist der aktuelle Kontostand /// [previousBalance] ist der Kontostand des Vormonats /// [context] ist der Build-Kontext Widget _currentBalance( final double currentBalance, final double previousBalance, final BuildContext context, ) { final ThemeData theme = Theme.of(context); final double diff = currentBalance - previousBalance; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: theme.colorScheme.primaryContainer, borderRadius: BorderRadius.circular(16), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Aktuell', style: theme.textTheme.bodyMedium), const SizedBox(height: 8), Text( '${currentBalance.toStringAsFixed(2)} €', style: theme.textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, ), ), ], ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( 'Differenz zum Vormonat', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurface, ), ), const SizedBox(height: 8), Row( children: [ Icon( diff >= 0 ? Icons.arrow_upward : Icons.arrow_downward, color: diff >= 0 ? Colors.green : Colors.red, ), const SizedBox(width: 4), Text( '${diff.abs().toStringAsFixed(2)} €', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, color: diff >= 0 ? Colors.green : Colors.red, ), ), ], ), ], ), ], ), ); } /// Baut das Widget für die Entwicklung /// des Kontostands der letzten Monate auf. /// /// [monthlyBalance] ist ein Map mit den Monaten als Schlüssel und /// den dazugehörigen Kontoständen als Werte. /// [context] ist der Build-Kontext. Widget _monthlyBalance( final Map monthlyBalance, final BuildContext context, ) { final ThemeData theme = Theme.of(context); final double maxY = monthlyBalance.values.reduce( (final double a, final double b) => a > b ? a : b, ) + 200; return SizedBox( height: 180, child: LineChart( LineChartData( minY: 0, maxY: maxY, 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 = monthlyBalance.keys.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( monthlyBalance.length, (final int index) => FlSpot( index.toDouble(), monthlyBalance.values.elementAt(index), ), ), isCurved: true, barWidth: 3, color: theme.colorScheme.primary, ), ], ), ), ); } /// Erstellt Widgets für die letzten Transaktionen. /// /// [recentTransactions] ist eine Liste von Transaktionen, /// wobei jede Transaktion ein Map mit den Keys 'name' (String) /// und 'amount' (double) ist. /// Die Funktion gibt eine Liste von Widgets zurück, /// die die Transaktionen anzeigen. List _recentTransactions( final List> recentTransactions, ) => recentTransactions .map( (final Map tx) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: ListTile( contentPadding: EdgeInsets.zero, title: Text((tx['name'] ?? '') as String), trailing: Text( '${((tx['amount'] ?? 0) as double).abs().toStringAsFixed(2)} €', style: TextStyle( color: ((tx['amount'] ?? 0) as double) >= 0 ? Colors.green : Colors.red, fontWeight: FontWeight.bold, ), ), ), ), ) .toList(); }