From 05a5bddf09e596eed6fa34e5e143ec20cb47da01 Mon Sep 17 00:00:00 2001 From: DragonSlayer_14 Date: Thu, 25 Dec 2025 16:23:01 +0100 Subject: [PATCH] Feat: Macht die Kontoauswahl funktional --- lib/Controller/account_controller.dart | 25 +++++- lib/Pages/Misc/account_select.dart | 66 +++++++++++++++ lib/Pages/Misc/floating_creation_button.dart | 65 +++++++++++++++ lib/Pages/home_page.dart | 87 ++------------------ 4 files changed, 162 insertions(+), 81 deletions(-) create mode 100644 lib/Pages/Misc/account_select.dart create mode 100644 lib/Pages/Misc/floating_creation_button.dart diff --git a/lib/Controller/account_controller.dart b/lib/Controller/account_controller.dart index 3c95ce4..b24ac52 100644 --- a/lib/Controller/account_controller.dart +++ b/lib/Controller/account_controller.dart @@ -12,8 +12,11 @@ import '../Repositories/account_repository.dart'; /// Steuert die Interaktion mit den Accounts class AccountController { + /// Gibt die aktuell gültige Instanz der Klasse zurück + factory AccountController() => _instance; + /// Erstellt eine neue Instanz dieser Klasse - AccountController() { + AccountController._internal() { _newAccountDialog = DynamicDialog( title: 'Neues Konto erstellen', icon: Icons.account_balance_wallet, @@ -45,14 +48,32 @@ class AccountController { ); } + static final AccountController _instance = AccountController._internal(); BuildContext? _buildContext; - final AccountRepository _accountRepository = AccountRepository(); DynamicDialog? _newAccountDialog; DynamicDialog? _errorNameEmptyDialog; DynamicDialog? _accountCreatedDialog; + Account? _selected; + + /// Stellt das ausgewählte Konto dar, das angezeigt wird + Future get selected async => _selected ??= (await getAccounts())[0]; + + set selected(final Account selected) { + _selected = selected; + } + + /// Gibt die gespeicherten Konten als Liste zurück + Future> getAccounts() async { + final List accounts = await _accountRepository.findBy( + orderBy: 'nameAsc', + ); + + return accounts; + } + /// Startet den Prozess um ein neues Konto anzulegen void newAccountHandler(final BuildContext buildContext) { _buildContext = buildContext; diff --git a/lib/Pages/Misc/account_select.dart b/lib/Pages/Misc/account_select.dart new file mode 100644 index 0000000..b352d14 --- /dev/null +++ b/lib/Pages/Misc/account_select.dart @@ -0,0 +1,66 @@ +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/material.dart'; + +import '../../Controller/account_controller.dart'; +import '../../Entities/drift_database.dart'; + +/// Ein Dropdown, mit welchem man das Konto auswählen kann +class AccountSelect extends StatefulWidget { + /// Erstellt eine neue Instanz dieser Klasse + const AccountSelect({super.key}); + + @override + State createState() => _AccountSelectState(); +} + +class _AccountSelectState extends State { + final AccountController _accountController = AccountController(); + + @override + Widget build(final BuildContext context) { + final Future selected = _accountController.selected; + + return FutureBuilder( + future: selected, + builder: + (final BuildContext context, final AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return DropdownSearch( + items: (final f, final cs) => _accountController.getAccounts(), + selectedItem: snapshot.data, + onChanged: (final Account? account) { + if (account != null) { + _accountController.selected = account; + } + }, + + itemAsString: (final Account account) => account.name, + compareFn: (final Account a1, final Account a2) => + a1.id == a2.id, + popupProps: const PopupProps.menu( + showSearchBox: true, + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: 'Konto suchen...', + contentPadding: EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + ), + ), + ), + ); + } else if (snapshot.hasError) { + return const Row( + children: [ + Icon(Icons.error, color: Colors.red), + Text('Fehler beim Laden der Konten!'), + ], + ); + } else { + return const CircularProgressIndicator(); + } + }, + ); + } +} diff --git a/lib/Pages/Misc/floating_creation_button.dart b/lib/Pages/Misc/floating_creation_button.dart new file mode 100644 index 0000000..bad9231 --- /dev/null +++ b/lib/Pages/Misc/floating_creation_button.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; + +import '../../Controller/account_controller.dart'; + +/// Ein Floating Action Button, der beim Klicken ein expandierendes Menü öffnet, +/// um neue Transaktionen oder Konten anzulegen. +class FloatingCreationButton extends StatefulWidget { + /// Erstellt eine neue Instanz dieser Klasse + const FloatingCreationButton({super.key}); + + @override + State createState() => _FloatingCreationButtonState(); +} + +class _FloatingCreationButtonState extends State { + final AccountController _accountController = AccountController(); + + @override + Widget build(final BuildContext context) => ExpandableFab( + openButtonBuilder: RotateFloatingActionButtonBuilder( + child: const Icon(Icons.add), + ), + type: ExpandableFabType.up, + childrenAnimation: ExpandableFabAnimation.none, + distance: 70, + children: [ + _expandableButton( + label: 'Neue Transaktion', + icon: Icons.add, + onPressed: () {}, + ), + _expandableButton( + label: 'Neues Konto', + icon: Icons.account_balance_wallet, + onPressed: () { + _accountController.newAccountHandler(context); + }, + ), + ], + ); + + Widget _expandableButton({ + required final String label, + required final IconData icon, + required final VoidCallback onPressed, + }) => GestureDetector( + onTap: onPressed, + child: Row( + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)), + child: Text(label), + ), + const SizedBox(width: 12), + FloatingActionButton.small( + heroTag: null, + onPressed: onPressed, + child: Icon(icon), + ), + ], + ), + ); +} diff --git a/lib/Pages/home_page.dart b/lib/Pages/home_page.dart index 05bda12..2f9cec5 100644 --- a/lib/Pages/home_page.dart +++ b/lib/Pages/home_page.dart @@ -1,28 +1,19 @@ -import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/material.dart'; import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:routemaster/routemaster.dart'; -import '../Controller/account_controller.dart'; +import 'Misc/account_select.dart'; +import 'Misc/floating_creation_button.dart'; /// Eine Seite, die als Container für die verschiedenen Tabs der App dient. /// /// Diese Seite enthält eine App-Bar mit einer Kontoauswahl sowie ein /// Bottom-Navigation-Bar für die Navigation zwischen /// Dashboard, Verlauf und Einstellungen. -class HomePage extends StatefulWidget { - /// Erstellt eine neue Instanz der HomePage. +class HomePage extends StatelessWidget { + /// Erstellt eine neue Instanz dieser Klasse const HomePage({super.key}); - @override - State createState() => _HomePageState(); -} - -class _HomePageState extends State { - final AccountController _accountController = AccountController(); - - String selected = 'Konto 1'; - @override Widget build(final BuildContext context) { final TabPageState tabPage = TabPage.of(context); @@ -31,9 +22,9 @@ class _HomePageState extends State { appBar: AppBar( centerTitle: true, titleSpacing: 0, - title: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: _accountSelect(), + title: const Padding( + padding: EdgeInsets.symmetric(horizontal: 12), + child: AccountSelect(), ), ), @@ -53,7 +44,7 @@ class _HomePageState extends State { bottomNavigationBar: _bottomNav(tabPage), floatingActionButtonLocation: ExpandableFab.location, - floatingActionButton: _floatingActionButton(), + floatingActionButton: const FloatingCreationButton(), ); } @@ -69,66 +60,4 @@ class _HomePageState extends State { ), ], ); - - Widget _accountSelect() => DropdownSearch( - items: (final String filter, final LoadProps? infiniteScrollProps) => - ['Konto 1', 'Konto 2', 'Konto 3', 'Konto 4'], - selectedItem: selected, - onChanged: (final String? value) => setState(() => selected = value!), - popupProps: const PopupProps.menu( - showSearchBox: true, - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: 'Suchen...', - contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), - ), - ), - ), - ); - - Widget _floatingActionButton() => ExpandableFab( - openButtonBuilder: RotateFloatingActionButtonBuilder( - child: const Icon(Icons.add), - ), - type: ExpandableFabType.up, - childrenAnimation: ExpandableFabAnimation.none, - distance: 70, - children: [ - _expandableButton( - label: 'Neue Transaktion', - icon: Icons.add, - onPressed: () {}, - ), - _expandableButton( - label: 'Neues Konto', - icon: Icons.account_balance_wallet, - onPressed: () { - _accountController.newAccountHandler(context); - }, - ), - ], - ); - - Widget _expandableButton({ - required final String label, - required final IconData icon, - required final VoidCallback onPressed, - }) => GestureDetector( - onTap: onPressed, - child: Row( - children: [ - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)), - child: Text(label), - ), - const SizedBox(width: 12), - FloatingActionButton.small( - heroTag: null, - onPressed: onPressed, - child: Icon(icon), - ), - ], - ), - ); }