Feat: Macht die Dashboard-Seite funktional
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../Misc/monthly_balance_chart.dart';
|
||||
import 'current_balance.dart';
|
||||
import 'recent_transactions_list.dart';
|
||||
|
||||
/// Eine Seite, die das Dashboard der App darstellt.
|
||||
///
|
||||
/// Diese Seite zeigt eine Übersicht über den aktuellen Kontostand,
|
||||
@@ -13,227 +16,33 @@ class Dashboard extends StatelessWidget {
|
||||
/// Baut das Dashboard-Widget auf.
|
||||
/// [context] ist der Build-Kontext
|
||||
@override
|
||||
Widget build(final BuildContext context) {
|
||||
const currentBalance = 4820.75;
|
||||
const double previousMonthBalance = 4300;
|
||||
Widget build(final BuildContext context) => const Scaffold(
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
CurrentBalance(),
|
||||
SizedBox(height: 32),
|
||||
|
||||
final monthlyBalance = <String, double>{
|
||||
'Jan': 1200.0,
|
||||
'Feb': 900.0,
|
||||
'Mär': 1100.0,
|
||||
'Apr': 950.0,
|
||||
'Mai': 1300.0,
|
||||
'Jun': 1050.0,
|
||||
};
|
||||
|
||||
final recentTransactions = <Map<String, Object>>[
|
||||
<String, Object>{'name': 'Supermarkt', 'amount': -45.50},
|
||||
<String, Object>{'name': 'Gehalt', 'amount': 2500.00},
|
||||
<String, Object>{'name': 'Miete', 'amount': -900.00},
|
||||
<String, Object>{'name': 'Streaming', 'amount': -12.99},
|
||||
<String, Object>{'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: <Widget>[
|
||||
_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: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text('Aktuell', style: theme.textTheme.bodyMedium),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${currentBalance.toStringAsFixed(2)} €',
|
||||
style: theme.textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
Text(
|
||||
'Kontostand pro Monat',
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
MonthlyBalanceChart(),
|
||||
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Differenz zum Vormonat',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
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<String, double> 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<String> 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>[
|
||||
LineChartBarData(
|
||||
spots: List<FlSpot>.generate(
|
||||
monthlyBalance.length,
|
||||
(final int index) => FlSpot(
|
||||
index.toDouble(),
|
||||
monthlyBalance.values.elementAt(index),
|
||||
),
|
||||
),
|
||||
isCurved: true,
|
||||
barWidth: 3,
|
||||
color: theme.colorScheme.primary,
|
||||
SizedBox(height: 32),
|
||||
Text(
|
||||
'Letzte Transaktionen',
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
RecentTransactionsList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 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<Widget> _recentTransactions(
|
||||
final List<Map<String, Object>> recentTransactions,
|
||||
) => recentTransactions
|
||||
.map(
|
||||
(final Map<String, Object> 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();
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user