Fix: Passt das Verhalten der InputFelder an, dass sich diese wirklich verändern

This commit is contained in:
2026-01-01 23:19:49 +01:00
parent a937d34df2
commit 58cbd2a462
7 changed files with 85 additions and 62 deletions

View File

@@ -36,6 +36,7 @@ class _RecentTransactionsListState extends State<RecentTransactionsList> {
final Future<List<Transaction>> recentTransactions = _transactionRepository final Future<List<Transaction>> recentTransactions = _transactionRepository
.findBy( .findBy(
account: _accountController.selected.value, account: _accountController.selected.value,
dateTo: DateTime.now(),
limit: 5, limit: 5,
orderBy: 'dateDesc', orderBy: 'dateDesc',
); );

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../Services/date_service.dart';
import '../../Dialog/dialog_action.dart'; import '../../Dialog/dialog_action.dart';
import '../../Dialog/dialog_input_field.dart'; import '../../Dialog/dialog_input_field.dart';
import '../../Dialog/dialog_input_field_type_enum.dart'; import '../../Dialog/dialog_input_field_type_enum.dart';
@@ -9,16 +10,13 @@ import '../../Dialog/dynamic_dialog.dart';
class DateRangePicker extends StatefulWidget { class DateRangePicker extends StatefulWidget {
/// Initialisiert eine neue Instanz dieser Klasse /// Initialisiert eine neue Instanz dieser Klasse
const DateRangePicker({ const DateRangePicker({
this.controller,
this.autofocus = false, this.autofocus = false,
super.key, super.key,
this.decoration, this.decoration,
this.initialValue,
this.onChanged, this.onChanged,
}); });
/// Der Initiale Wert des Input-Feldes
final DateTimeRange? initialValue;
/// Ob das Feld automatisch ausgewählt werden soll /// Ob das Feld automatisch ausgewählt werden soll
final bool autofocus; final bool autofocus;
@@ -28,42 +26,39 @@ class DateRangePicker extends StatefulWidget {
/// Die Dekoration, wie das Feld aussehen soll /// Die Dekoration, wie das Feld aussehen soll
final InputDecoration? decoration; final InputDecoration? decoration;
/// Der Controller über den der Wert des Inputfeldes gesetzt
/// und ausgelesen werden kann
final TextEditingController? controller;
@override @override
State<StatefulWidget> createState() => _DateRangePicker(); State<StatefulWidget> createState() => _DateRangePicker();
} }
class _DateRangePicker extends State<DateRangePicker> { class _DateRangePicker extends State<DateRangePicker> {
final ValueNotifier<DateTimeRange?> _value = ValueNotifier(null); final TextEditingController _valueController = TextEditingController();
@override @override
void initState() { void dispose() {
super.initState(); _valueController.dispose();
_value.value = widget.initialValue; super.dispose();
_value.addListener(() {
widget.onChanged?.call(_value.value);
});
} }
@override @override
Widget build(final BuildContext context) => TextField( Widget build(final BuildContext context) => TextField(
readOnly: true, readOnly: true,
controller: TextEditingController( controller: widget.controller ?? _valueController,
text: widget.initialValue != null
? '${widget.initialValue!.start.day}'
'.${widget.initialValue!.start.month}'
'.${widget.initialValue!.start.year}'
' - '
'${widget.initialValue!.end.day}'
'.${widget.initialValue!.end.month}'
'.${widget.initialValue!.end.year}'
: null,
),
decoration: widget.decoration, decoration: widget.decoration,
onTap: _pickDateRange, onTap: _pickDateRange,
); );
Future<void> _pickDateRange() async { Future<void> _pickDateRange() async {
final TextEditingController controller =
widget.controller ?? _valueController;
final DateTimeRange<DateTime>? dateTimeRange =
DateService.stringToDateTimeRange(controller.text);
await DynamicDialog( await DynamicDialog(
title: 'Zeitraum auswählen', title: 'Zeitraum auswählen',
inputFields: [ inputFields: [
@@ -72,14 +67,14 @@ class _DateRangePicker extends State<DateRangePicker> {
label: 'Startdatum', label: 'Startdatum',
keyboardType: TextInputType.datetime, keyboardType: TextInputType.datetime,
inputType: DialogInputFieldTypeEnum.date, inputType: DialogInputFieldTypeEnum.date,
initialValue: _value.value?.start, initialValue: dateTimeRange?.start,
), ),
DialogInputField( DialogInputField(
id: 'dateTo', id: 'dateTo',
label: 'Enddatum', label: 'Enddatum',
keyboardType: TextInputType.datetime, keyboardType: TextInputType.datetime,
inputType: DialogInputFieldTypeEnum.date, inputType: DialogInputFieldTypeEnum.date,
initialValue: _value.value?.end, initialValue: dateTimeRange?.end,
), ),
], ],
actions: [ actions: [
@@ -87,7 +82,8 @@ class _DateRangePicker extends State<DateRangePicker> {
DialogAction( DialogAction(
label: 'Leeren', label: 'Leeren',
onPressed: (_) { onPressed: (_) {
_value.value = null; controller.text = '';
widget.onChanged?.call(null);
}, },
), ),
DialogAction( DialogAction(
@@ -98,10 +94,13 @@ class _DateRangePicker extends State<DateRangePicker> {
values['dateFrom'] is DateTime && values['dateFrom'] is DateTime &&
values['dateTo'] != null && values['dateTo'] != null &&
values['dateTo'] is DateTime) { values['dateTo'] is DateTime) {
_value.value = DateTimeRange( final DateTimeRange<DateTime> timeRange = DateTimeRange(
start: values['dateFrom'], start: values['dateFrom'],
end: values['dateTo'], end: values['dateTo'],
); );
controller.text = DateService.dateTimeRangeToString(timeRange)!;
widget.onChanged?.call(timeRange);
} }
}, },
), ),

View File

@@ -1,6 +1,7 @@
import 'package:date_field/date_field.dart'; import 'package:date_field/date_field.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../Services/date_service.dart';
/// Ein Feld mit Popup über welches man Datumsfelder auswählen kann /// Ein Feld mit Popup über welches man Datumsfelder auswählen kann
class DynamicDateTimeField extends StatefulWidget { class DynamicDateTimeField extends StatefulWidget {
@@ -45,7 +46,7 @@ class _DynamicDateTimeFieldState extends State<DynamicDateTimeField> {
@override @override
Widget build(final BuildContext context) => DateTimeField( Widget build(final BuildContext context) => DateTimeField(
initialPickerDateTime: widget.initialValue, initialPickerDateTime: widget.initialValue,
dateFormat: DateFormat('d.M.y'), dateFormat: DateService.dateFormat,
value: _value, value: _value,
mode: widget.mode, mode: widget.mode,
autofocus: widget.autofocus, autofocus: widget.autofocus,

View File

@@ -62,7 +62,7 @@ class _MonthlyBalanceChart extends State<MonthlyBalanceChart> {
amountMin: widget.amountMin, amountMin: widget.amountMin,
amountMax: widget.amountMax, amountMax: widget.amountMax,
dateFrom: widget.dateFrom, dateFrom: widget.dateFrom,
dateTo: widget.dateTo, dateTo: (widget.dateTo != null) ? widget.dateTo : DateTime.now(),
), ),
builder: builder:
( (

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:routemaster/routemaster.dart'; import 'package:routemaster/routemaster.dart';
import '../../Services/date_service.dart';
import '../Misc/InputFields/date_range_picker.dart'; import '../Misc/InputFields/date_range_picker.dart';
/// Stellt die Inputfelder für die Verlaufsübersicht dar /// Stellt die Inputfelder für die Verlaufsübersicht dar
@@ -13,7 +14,6 @@ class InputFields extends StatefulWidget {
this.dateFrom, this.dateFrom,
this.dateTo, this.dateTo,
this.name, this.name,
this.onChanged,
}); });
/// Der Name der Transaktion, nach der gesucht werden soll /// Der Name der Transaktion, nach der gesucht werden soll
@@ -31,35 +31,54 @@ class InputFields extends StatefulWidget {
///Das Datum der Transaktionen, bis zu welchen beendet wurde ///Das Datum der Transaktionen, bis zu welchen beendet wurde
final DateTime? dateTo; final DateTime? dateTo;
/// Die Funktion, die bei Veränderung eines Wertes aufgerufen wird
final Function()? onChanged;
@override @override
State<StatefulWidget> createState() => _InputFields(); State<StatefulWidget> createState() => _InputFields();
} }
class _InputFields extends State<InputFields> { class _InputFields extends State<InputFields> {
String? _name; final TextEditingController _nameController = TextEditingController();
double? _amountMin; final TextEditingController _amountMinController = TextEditingController();
double? _amountMax; final TextEditingController _amountMaxController = TextEditingController();
DateTimeRange? _dateTimeRange; final TextEditingController _dateTimeController = TextEditingController();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_name = widget.name; if (widget.name != null) {
_amountMin = widget.amountMin; _nameController.text = widget.name!;
_amountMax = widget.amountMax; }
if (widget.amountMin != null) {
_amountMinController.text = widget.amountMin!.toString();
}
if (widget.amountMax != null) {
_amountMaxController.text = widget.amountMax!.toString();
}
if (widget.dateFrom != null && widget.dateTo != null) { if (widget.dateFrom != null && widget.dateTo != null) {
_dateTimeRange = DateTimeRange( final DateTimeRange dateTimeRange = DateTimeRange(
start: widget.dateFrom!, start: widget.dateFrom!,
end: widget.dateTo!, end: widget.dateTo!,
); );
_dateTimeController.text = DateService.dateTimeRangeToString(
dateTimeRange,
)!;
} }
} }
@override
void dispose() {
_nameController.dispose();
_amountMinController.dispose();
_amountMaxController.dispose();
_dateTimeController.dispose();
super.dispose();
}
@override @override
Widget build(final BuildContext context) { Widget build(final BuildContext context) {
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
@@ -68,12 +87,12 @@ class _InputFields extends State<InputFields> {
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: TextField( child: TextField(
controller: _nameController,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Name', labelText: 'Name',
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
onChanged: (final String value) { onChanged: (final String value) {
_name = value;
_updateUrl(); _updateUrl();
}, },
), ),
@@ -81,13 +100,13 @@ class _InputFields extends State<InputFields> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: TextField( child: TextField(
controller: _amountMinController,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Min Betrag €', labelText: 'Min Betrag €',
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
keyboardType: const TextInputType.numberWithOptions(decimal: true), keyboardType: const TextInputType.numberWithOptions(decimal: true),
onChanged: (final String value) { onChanged: (final String value) {
_amountMin = double.tryParse(value);
_updateUrl(); _updateUrl();
}, },
), ),
@@ -95,13 +114,13 @@ class _InputFields extends State<InputFields> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: TextField( child: TextField(
controller: _amountMaxController,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Max Betrag €', labelText: 'Max Betrag €',
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
keyboardType: const TextInputType.numberWithOptions(decimal: true), keyboardType: const TextInputType.numberWithOptions(decimal: true),
onChanged: (final String value) { onChanged: (final String value) {
_amountMax = double.tryParse(value);
_updateUrl(); _updateUrl();
}, },
), ),
@@ -109,9 +128,8 @@ class _InputFields extends State<InputFields> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: DateRangePicker( child: DateRangePicker(
initialValue: _dateTimeRange, controller: _dateTimeController,
onChanged: (final DateTimeRange? value) { onChanged: (final DateTimeRange? value) {
_dateTimeRange = value;
_updateUrl(); _updateUrl();
}, },
decoration: InputDecoration( decoration: InputDecoration(
@@ -127,10 +145,10 @@ class _InputFields extends State<InputFields> {
const SizedBox(width: 8), const SizedBox(width: 8),
IconButton( IconButton(
onPressed: () { onPressed: () {
_name = null; _nameController.text = '';
_amountMin = null; _amountMinController.text = '';
_amountMax = null; _amountMaxController.text = '';
_dateTimeRange = null; _dateTimeController.text = '';
_updateUrl(); _updateUrl();
}, },
@@ -142,18 +160,24 @@ class _InputFields extends State<InputFields> {
void _updateUrl() { void _updateUrl() {
final params = <String, String>{ final params = <String, String>{
if (_name != null && _name != '') 'name': _name!, if (_nameController.text != '') 'name': _nameController.text,
if (_amountMin != null) 'amountMin': _amountMin!.toString(), if (_amountMinController.text != '')
if (_amountMax != null) 'amountMax': _amountMax!.toString(), 'amountMin': _amountMinController.text,
if (_amountMaxController.text != '')
'amountMax': _amountMaxController.text,
}; };
if (_dateTimeRange != null) { if (_dateTimeController.text != '') {
params['dateFrom'] = _dateTimeRange!.start.toIso8601String(); final DateTimeRange<DateTime>? range = DateService.stringToDateTimeRange(
params['dateTo'] = _dateTimeRange!.end.toIso8601String(); _dateTimeController.text,
);
if (range != null) {
params['dateFrom'] = range.start.toIso8601String();
params['dateTo'] = range.end.toIso8601String();
}
} }
Routemaster.of(context).replace('/trend', queryParameters: params); Routemaster.of(context).replace('/trend', queryParameters: params);
widget.onChanged?.call();
} }
} }

View File

@@ -62,8 +62,9 @@ class _TransactionListState extends State<TransactionList> {
amountMin: widget.amountMin, amountMin: widget.amountMin,
amountMax: widget.amountMax, amountMax: widget.amountMax,
dateFrom: widget.dateFrom, dateFrom: widget.dateFrom,
dateTo: widget.dateTo, dateTo: (widget.dateTo != null) ? widget.dateTo : DateTime.now(),
account: _accountController.selected.value, account: _accountController.selected.value,
orderBy: 'dateDesc',
), ),
builder: builder:
( (

View File

@@ -44,9 +44,6 @@ class _TrendState extends State<Trend> {
amountMax: amountMax, amountMax: amountMax,
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
onChanged: () {
setState(() {});
},
), ),
const SizedBox(height: 24), const SizedBox(height: 24),