import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_sticky_header/flutter_sticky_header.dart'; import 'package:intl/intl.dart'; import '../../Controller/account_controller.dart'; import '../../Controller/transaction_controller.dart'; import '../../Entities/drift_database.dart'; import '../../Repositories/transaction_repository.dart'; /// Stellt eine filterbare Liste der Transaktionen dar class TransactionList extends StatefulWidget { /// Erstellt eine neue Instanz dieser Klasse const TransactionList({ 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() => _TransactionListState(); } class _TransactionListState extends State { final TransactionController _transactionController = TransactionController(); final AccountController _accountController = AccountController(); final TransactionRepository _transactionRepository = TransactionRepository(); @override void initState() { super.initState(); _transactionController.transactions.addListener(() { if (mounted) { setState(() {}); } }); } @override Widget build(final BuildContext context) => FutureBuilder( future: _transactionRepository.findBy( name: widget.name, amountMin: widget.amountMin, amountMax: widget.amountMax, dateFrom: widget.dateFrom, dateTo: (widget.dateTo != null) ? widget.dateTo : DateTime.now(), account: _accountController.selected.value, orderBy: 'dateDesc', ), builder: ( final BuildContext context, final AsyncSnapshot> snapshot, ) { final ThemeData theme = Theme.of(context); if (snapshot.hasData) { final transactionsByMonth = >{}; for (final Transaction transaction in snapshot.data!) { final DateTime date = transaction.date!; final DateFormat format = DateFormat('MMMM'); final monthName = '${format.format(date)} ${date.year}'; transactionsByMonth .putIfAbsent(monthName, () => []) .add(transaction); } return Expanded( child: CustomScrollView( slivers: transactionsByMonth.entries .map( ( final MapEntry> entry, ) => SliverStickyHeader( header: Container( color: theme.colorScheme.surface, padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), alignment: Alignment.centerLeft, child: Text( entry.key, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), ), sliver: SliverList( delegate: SliverChildBuilderDelegate(( final BuildContext context, final int index, ) { final Transaction transaction = entry.value[index]; return ListTile( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), onTap: () { unawaited( _transactionController.editTransactionHandler( transaction.id, ), ); }, contentPadding: EdgeInsets.zero, title: Text( transaction.name, style: (transaction.checked) ? const TextStyle() : TextStyle(color: theme.colorScheme.error), ), subtitle: Text( '${transaction.date?.day}' '.${transaction.date?.month}' '.${transaction.date?.year}', ), trailing: Text( '${transaction.amount.abs().toStringAsFixed(2)}' ' €', style: TextStyle( color: transaction.amount >= 0 ? Colors.red : Colors.green, fontWeight: FontWeight.bold, ), ), ); }, childCount: entry.value.length), ), ), ) .toList(), ), ); } else if (snapshot.hasError) { return Center( child: Column( children: [ Icon(Icons.error, color: theme.colorScheme.error), const Text('Fehler beim holen der Transaktionen!'), ], ), ); } else { return const Center(child: CircularProgressIndicator()); } }, ); }