Files
dragon_ledger/lib/Pages/Trend/input_fields.dart

272 lines
7.7 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:routemaster/routemaster.dart';
import '../../Services/date_service.dart';
import '../Misc/InputFields/date_range_picker.dart';
/// Stellt die Inputfelder für die Verlaufsübersicht dar
class InputFields extends StatefulWidget {
/// Erstellt eine neue Instanz dieser Klasse
const InputFields({
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<StatefulWidget> createState() => _InputFields();
}
class _InputFields extends State<InputFields> {
final TextEditingController _nameController = TextEditingController();
final TextEditingController _amountMinController = TextEditingController();
final TextEditingController _amountMaxController = TextEditingController();
final TextEditingController _dateTimeController = TextEditingController();
static const double _filterBreakpoint = 600;
@override
void initState() {
super.initState();
if (widget.name != null) {
_nameController.text = widget.name!;
}
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) {
final DateTimeRange dateTimeRange = DateTimeRange(
start: widget.dateFrom!,
end: widget.dateTo!,
);
_dateTimeController.text = DateService.dateTimeRangeToString(
dateTimeRange,
)!;
}
}
@override
void dispose() {
_nameController.dispose();
_amountMinController.dispose();
_amountMaxController.dispose();
_dateTimeController.dispose();
super.dispose();
}
@override
Widget build(final BuildContext context) {
final ThemeData theme = Theme.of(context);
return LayoutBuilder(
builder: (final context, final constraints) {
if (constraints.maxWidth < _filterBreakpoint) {
return _buildFilterButton(context, theme);
}
return _buildInlineFilters(theme);
},
);
}
Widget _buildInlineFilters(final ThemeData theme) => Row(
children: <Widget>[
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 = <String, String>{
if (_nameController.text != '') 'name': _nameController.text,
if (_amountMinController.text != '')
'amountMin': _amountMinController.text,
if (_amountMaxController.text != '')
'amountMax': _amountMaxController.text,
};
if (_dateTimeController.text != '') {
final DateTimeRange<DateTime>? range = DateService.stringToDateTimeRange(
_dateTimeController.text,
);
if (range != null) {
params['dateFrom'] = range.start.toIso8601String();
params['dateTo'] = range.end.toIso8601String();
}
}
Routemaster.of(context).replace('/trend', queryParameters: params);
}
}