From 531e819c69daede0274b6fa37fd470d6b93e3c1c Mon Sep 17 00:00:00 2001 From: DragonSlayer_14 Date: Mon, 5 Jan 2026 17:22:08 +0100 Subject: [PATCH] =?UTF-8?q?Feat:=20Passt=20App=20f=C3=BCr=20kleinere=20Bil?= =?UTF-8?q?dschirme=20an?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/Pages/Dashboard/dashboard.dart | 40 ++-- lib/Pages/Dialog/dynamic_dialog.dart | 27 ++- lib/Pages/Misc/monthly_balance_chart.dart | 11 +- lib/Pages/Trend/input_fields.dart | 230 +++++++++++++++------- 4 files changed, 207 insertions(+), 101 deletions(-) diff --git a/lib/Pages/Dashboard/dashboard.dart b/lib/Pages/Dashboard/dashboard.dart index 35457e0..8bf607a 100644 --- a/lib/Pages/Dashboard/dashboard.dart +++ b/lib/Pages/Dashboard/dashboard.dart @@ -20,27 +20,29 @@ class Dashboard extends StatelessWidget { body: SafeArea( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - CurrentBalance(), - SizedBox(height: 32), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CurrentBalance(), + SizedBox(height: 32), - Text( - 'Kontostand pro Monat', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - SizedBox(height: 12), - MonthlyBalanceChart(), + Text( + 'Kontostand pro Monat', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 12), + MonthlyBalanceChart(), - SizedBox(height: 32), - Text( - 'Letzte Transaktionen', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - SizedBox(height: 12), - RecentTransactionsList(), - ], + SizedBox(height: 32), + Text( + 'Letzte Transaktionen', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 12), + RecentTransactionsList(), + ], + ), ), ), ), diff --git a/lib/Pages/Dialog/dynamic_dialog.dart b/lib/Pages/Dialog/dynamic_dialog.dart index 1eff527..cb06192 100644 --- a/lib/Pages/Dialog/dynamic_dialog.dart +++ b/lib/Pages/Dialog/dynamic_dialog.dart @@ -111,17 +111,24 @@ class DynamicDialog { ), ], ), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (content != null) content!, - ...inputFields.map( - (final DialogInputField field) => Padding( - padding: const EdgeInsets.symmetric(vertical: 6), - child: _getInputField(field, primaryAction), - ), + content: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(ctx).size.height * 0.7, + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (content != null) content!, + ...inputFields.map( + (final DialogInputField field) => Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: _getInputField(field, primaryAction), + ), + ), + ], ), - ], + ), ), actions: actions .map( diff --git a/lib/Pages/Misc/monthly_balance_chart.dart b/lib/Pages/Misc/monthly_balance_chart.dart index c96ab3d..fefaa62 100644 --- a/lib/Pages/Misc/monthly_balance_chart.dart +++ b/lib/Pages/Misc/monthly_balance_chart.dart @@ -70,6 +70,7 @@ class _MonthlyBalanceChart extends State { final AsyncSnapshot>> snapshot, ) { final ThemeData theme = Theme.of(context); + final MediaQueryData mediaQuery = MediaQuery.of(context); if (snapshot.hasData) { final List> monthlyBalances = snapshot.data!; @@ -109,7 +110,15 @@ class _MonthlyBalanceChart extends State { final DateTime date = value['date']; final DateFormat format = DateFormat('MMMM'); - return format.format(date); + String month = format.format(date); + + if (mediaQuery.size.width < 470) { + month = month.substring(0, 1); + } else if (mediaQuery.size.width < 920) { + month = month.substring(0, 3); + } + + return month; }).toList(); if (value.toInt() >= 0 && diff --git a/lib/Pages/Trend/input_fields.dart b/lib/Pages/Trend/input_fields.dart index 6eb81d4..c0b4d1a 100644 --- a/lib/Pages/Trend/input_fields.dart +++ b/lib/Pages/Trend/input_fields.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:routemaster/routemaster.dart'; @@ -41,6 +43,8 @@ class _InputFields extends State { final TextEditingController _amountMaxController = TextEditingController(); final TextEditingController _dateTimeController = TextEditingController(); + static const double _filterBreakpoint = 600; + @override void initState() { super.initState(); @@ -83,81 +87,165 @@ class _InputFields extends State { Widget build(final BuildContext context) { final ThemeData theme = Theme.of(context); - return Row( - children: [ - Expanded( - child: TextField( - controller: _nameController, - decoration: const InputDecoration( - labelText: 'Name', - border: OutlineInputBorder(), - ), - onChanged: (final String value) { - _updateUrl(); - }, - ), - ), - const SizedBox(width: 8), - Expanded( - child: TextField( - controller: _amountMinController, - decoration: const InputDecoration( - labelText: 'Min Betrag €', - border: OutlineInputBorder(), - ), - keyboardType: const TextInputType.numberWithOptions(decimal: true), - onChanged: (final String value) { - _updateUrl(); - }, - ), - ), - const SizedBox(width: 8), - Expanded( - child: TextField( - controller: _amountMaxController, - decoration: const InputDecoration( - labelText: 'Max Betrag €', - border: OutlineInputBorder(), - ), - keyboardType: const TextInputType.numberWithOptions(decimal: true), - onChanged: (final String value) { - _updateUrl(); - }, - ), - ), - const SizedBox(width: 8), - Expanded( - child: DateRangePicker( - controller: _dateTimeController, - onChanged: (final DateTimeRange? value) { - _updateUrl(); - }, - decoration: InputDecoration( - labelText: 'Zeitraum', - border: const OutlineInputBorder(), - suffixIcon: Icon( - Icons.calendar_month, - color: theme.colorScheme.onSurface, - ), - ), - ), - ), - const SizedBox(width: 8), - IconButton( - onPressed: () { - _nameController.text = ''; - _amountMinController.text = ''; - _amountMaxController.text = ''; - _dateTimeController.text = ''; + return LayoutBuilder( + builder: (final context, final constraints) { + if (constraints.maxWidth < _filterBreakpoint) { + return _buildFilterButton(context, theme); + } - _updateUrl(); - }, - icon: const Icon(Icons.clear), - ), - ], + return _buildInlineFilters(theme); + }, ); } + Widget _buildInlineFilters(final ThemeData theme) => Row( + children: [ + Expanded( + child: TextField( + controller: _nameController, + decoration: const InputDecoration( + labelText: 'Name', + border: OutlineInputBorder(), + ), + onChanged: (_) => _updateUrl(), + ), + ), + const SizedBox(width: 8), + Expanded( + child: TextField( + controller: _amountMinController, + decoration: const InputDecoration( + labelText: 'Min Betrag €', + border: OutlineInputBorder(), + ), + keyboardType: const TextInputType.numberWithOptions(decimal: true), + onChanged: (_) => _updateUrl(), + ), + ), + const SizedBox(width: 8), + Expanded( + child: TextField( + controller: _amountMaxController, + decoration: const InputDecoration( + labelText: 'Max Betrag €', + border: OutlineInputBorder(), + ), + keyboardType: const TextInputType.numberWithOptions(decimal: true), + onChanged: (_) => _updateUrl(), + ), + ), + const SizedBox(width: 8), + Expanded( + child: DateRangePicker( + controller: _dateTimeController, + onChanged: (_) => _updateUrl(), + decoration: InputDecoration( + labelText: 'Zeitraum', + border: const OutlineInputBorder(), + suffixIcon: Icon( + Icons.calendar_month, + color: theme.colorScheme.onSurface, + ), + ), + ), + ), + const SizedBox(width: 8), + IconButton(onPressed: _clear, icon: const Icon(Icons.clear)), + ], + ); + + Widget _buildFilterButton( + final BuildContext context, + final ThemeData theme, + ) => Align( + alignment: Alignment.centerLeft, + child: ElevatedButton.icon( + icon: const Icon(Icons.filter_alt), + label: const Text('Filter'), + onPressed: () => _openFilterDialog(context), + ), + ); + + void _openFilterDialog(final BuildContext context) { + unawaited( + showDialog( + context: context, + builder: (final context) => AlertDialog( + title: const Text('Filter'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: _nameController, + decoration: const InputDecoration( + labelText: 'Name', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 12), + TextField( + controller: _amountMinController, + decoration: const InputDecoration( + labelText: 'Min Betrag €', + border: OutlineInputBorder(), + ), + keyboardType: const TextInputType.numberWithOptions( + decimal: true, + ), + ), + const SizedBox(height: 12), + TextField( + controller: _amountMaxController, + decoration: const InputDecoration( + labelText: 'Max Betrag €', + border: OutlineInputBorder(), + ), + keyboardType: const TextInputType.numberWithOptions( + decimal: true, + ), + ), + const SizedBox(height: 12), + DateRangePicker( + controller: _dateTimeController, + onChanged: (_) {}, + decoration: const InputDecoration( + labelText: 'Zeitraum', + border: OutlineInputBorder(), + ), + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + _clear(); + Navigator.of(context).pop(); + }, + child: const Text('Zurücksetzen'), + ), + ElevatedButton( + onPressed: () { + _updateUrl(); + Navigator.of(context).pop(); + }, + child: const Text('Anwenden'), + ), + ], + ), + ), + ); + } + + void _clear() { + _nameController.clear(); + _amountMinController.clear(); + _amountMaxController.clear(); + _dateTimeController.clear(); + _updateUrl(); + } + void _updateUrl() { final params = { if (_nameController.text != '') 'name': _nameController.text,