Commit 80ecab9
Changed files (4)
lib
components
screens
subsettings
lib/components/dialoges/input_dialoge.dart
@@ -5,11 +5,17 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
// TODO: redo dialoges in flutter style
class InputDialoge extends StatefulWidget {
final String hintText;
+ final String? initialValue;
final void Function(String text) onSubmit;
final List<TextInputFormatter>? inputFormatters;
final TextInputType? keyboardType;
- const InputDialoge({super.key, required this.hintText, required this.onSubmit, this.inputFormatters, this.keyboardType});
+ const InputDialoge({super.key,
+ required this.hintText,
+ required this.onSubmit,
+ this.inputFormatters,
+ this.keyboardType,
+ this.initialValue});
@override
State<InputDialoge> createState() => _InputDialogeState();
@@ -22,11 +28,17 @@ class _InputDialogeState extends State<InputDialoge> {
@override
void dispose() {
- // Clean up the controller when the widget is disposed.
controller.dispose();
super.dispose();
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller.text = widget.initialValue ?? '';
+ }
+
@override
Widget build(BuildContext context) {
inputFocusNode.requestFocus();
@@ -37,7 +49,10 @@ class _InputDialogeState extends State<InputDialoge> {
controller: controller,
inputFormatters: widget.inputFormatters,
keyboardType: widget.keyboardType,
- decoration: InputDecoration(hintText: widget.hintText),
+ decoration: InputDecoration(
+ hintText: widget.hintText
+ ),
+ onFieldSubmitted: widget.onSubmit,
),
actions: [
ElevatedButton(
@@ -51,23 +66,32 @@ class _InputDialogeState extends State<InputDialoge> {
}
}
+typedef NumberInputResult = void Function(double result);
+
class NumberInputDialoge extends StatelessWidget {
final String hintText;
- final void Function(int text) onParsableSubmit;
+ final NumberInputResult onParsableSubmit;
+ final String? initialValue;
- const NumberInputDialoge({super.key, required this.hintText, required this.onParsableSubmit});
+ const NumberInputDialoge({
+ super.key,
+ required this.hintText,
+ required this.onParsableSubmit,
+ this.initialValue});
@override
Widget build(BuildContext context) {
return InputDialoge(
hintText: hintText,
- inputFormatters: [FilteringTextInputFormatter.digitsOnly],
+ inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'([0-9]+(\.([0-9]*))?)')),],
keyboardType: TextInputType.number,
+ initialValue: initialValue,
onSubmit: (text) {
- if (text.isEmpty || (int.tryParse(text) == null)) {
+ double? value = double.tryParse(text);
+ value ??= int.tryParse(text)?.toDouble();
+ if (text.isEmpty || value == null) {
return;
}
- int value = int.parse(text);
onParsableSubmit(value);
}
);
lib/components/settings_widgets.dart
@@ -1,6 +1,6 @@
import 'package:blood_pressure_app/components/color_picker.dart';
+import 'package:blood_pressure_app/components/dialoges/input_dialoge.dart';
import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
class SettingsTile extends StatelessWidget {
final Widget title;
@@ -206,81 +206,53 @@ class _SliderSettingsTileState extends State<SliderSettingsTile> {
}
}
-class InputSettingsTile extends StatefulWidget {
- final Widget title;
- final Widget? leading;
- final Widget? description;
- final bool disabled;
-
- final double inputWidth;
- final String? initialValue;
- final InputDecoration? decoration;
- final void Function(String?)? onEditingComplete;
- final TextInputType? keyboardType;
- final List<TextInputFormatter>? inputFormatters;
-
- const InputSettingsTile(
+/// Widget for editing numbers in a list tile.
+class NumberInputListTile extends StatelessWidget {
+ /// Creates a widget for editing numbers in a list tile.
+ const NumberInputListTile(
{super.key,
- required this.title,
- required this.inputWidth,
- this.leading,
- this.description,
- this.disabled = false,
- this.initialValue,
- this.decoration,
- this.onEditingComplete,
- this.keyboardType,
- this.inputFormatters});
+ required this.label,
+ this.leading,
+ this.initialValue,
+ required this.onParsableSubmit,});
- @override
- State<StatefulWidget> createState() => _InputSettingsTileState();
-}
+ /// Short label describing the required field contents.
+ ///
+ /// This will be both the title of the list tile as well as the hint text in the input dialoge.
+ final String label;
-class _InputSettingsTileState extends State<InputSettingsTile> {
- late String _value;
+ /// Widget to display before the label in the list tile.
+ final Widget? leading;
- @override
- void initState() {
- super.initState();
- _value = widget.initialValue ?? "";
- }
+ /// Initial content of the input field.
+ final num? initialValue;
+
+ /// Gets called once the user submits a new valid number to the field.
+ final NumberInputResult onParsableSubmit;
@override
Widget build(BuildContext context) {
- final focusNode = FocusNode();
-
- return SettingsTile(
- title: widget.title,
- description: widget.description,
- leading: widget.leading,
- disabled: widget.disabled,
- onPressed: (context) {
- focusNode.requestFocus();
- },
- trailing: Row(
- children: [
- SizedBox(
- width: widget.inputWidth,
- child: TextFormField(
- initialValue: widget.initialValue,
- decoration: widget.decoration,
- onChanged: (value) {
- _value = value;
- },
- onEditingComplete: () => widget.onEditingComplete!(_value),
- onTapOutside: (e) => widget.onEditingComplete!(_value),
- keyboardType: widget.keyboardType,
- inputFormatters: widget.inputFormatters,
- focusNode: focusNode,
- ),
- ),
- const SizedBox(
- width: 20,
+ return ListTile(
+ title: Text(label),
+ subtitle: Text(initialValue.toString()),
+ leading: leading,
+ trailing: const Icon(Icons.edit),
+ onTap: () {
+ showDialog(
+ context: context,
+ builder: (context) => NumberInputDialoge(
+ initialValue: initialValue?.toString(),
+ hintText: label,
+ onParsableSubmit: (value) {
+ Navigator.of(context).pop();
+ onParsableSubmit(value);
+ },
),
- ],
- ),
+ );
+ },
);
}
+
}
/// A ListTile that allows choosing from a dropdown.
lib/screens/subsettings/export_import_screen.dart
@@ -78,9 +78,9 @@ class ExportImportScreen extends StatelessWidget {
Consumer<CsvExportSettings>(builder: (context, csvExportSettings, child) =>
Column(
children: [
- InputSettingsTile(
- title: Text(localizations.fieldDelimiter),
- inputWidth: 40,
+ /* TODO
+ NumberInputSettingsTile(
+ label: localizations.fieldDelimiter,
initialValue: csvExportSettings.fieldDelimiter,
onEditingComplete: (value) {
if (value != null) {
@@ -88,8 +88,8 @@ class ExportImportScreen extends StatelessWidget {
}
},
),
- InputSettingsTile(
- title: Text(localizations.textDelimiter),
+ NumberInputSettingsTile(
+ label: Text(localizations.textDelimiter),
inputWidth: 40,
initialValue: csvExportSettings.textDelimiter,
onEditingComplete: (value) {
@@ -98,6 +98,7 @@ class ExportImportScreen extends StatelessWidget {
}
},
),
+ */
SwitchListTile(
title: Text(localizations.exportCsvHeadline),
subtitle: Text(localizations.exportCsvHeadlineDesc),
@@ -134,53 +135,41 @@ class ExportImportScreen extends StatelessWidget {
onChanged: (value) {
pdfExportSettings.exportData = value;
}),
- InputSettingsTile(
- initialValue: pdfExportSettings.headerHeight.toString(),
- title: Text(localizations.exportPdfHeaderHeight),
- onEditingComplete: (value) {
- final pV = double.tryParse(value ?? '');
- if (pV != null) pdfExportSettings.headerHeight = pV;
- },
- disabled: !(pdfExportSettings.exportData),
- keyboardType: TextInputType.number,
- inputWidth: 40,
- ),
- InputSettingsTile(
- initialValue: pdfExportSettings.cellHeight.toString(),
- title: Text(localizations.exportPdfCellHeight),
- onEditingComplete: (value) {
- final pV = double.tryParse(value ?? '');
- if (pV != null) pdfExportSettings.cellHeight = pV;
- },
- disabled: !pdfExportSettings.exportData,
- keyboardType: TextInputType.number,
- inputWidth: 40,
- ),
- InputSettingsTile(
- initialValue: pdfExportSettings.headerFontSize.toString(),
- title: Text(localizations.exportPdfHeaderFontSize),
- onEditingComplete: (value) {
- final pV = double.tryParse(value ?? '');
- if (pV != null) pdfExportSettings.headerFontSize = pV;
- },
- disabled: !pdfExportSettings.exportData,
- keyboardType: TextInputType.number,
- inputWidth: 40,
- ),
- InputSettingsTile(
- initialValue: pdfExportSettings.cellFontSize.toString(),
- title: Text(localizations.exportPdfCellFontSize),
- onEditingComplete: (value) {
- final pV = double.tryParse(value ?? '');
- if (pV != null) pdfExportSettings.cellFontSize = pV;
- },
- disabled: !pdfExportSettings.exportData,
- keyboardType: TextInputType.number,
- inputWidth: 40,
- ),
if (pdfExportSettings.exportData)
- ExportFieldCustomisationSetting(
- fieldsSettings: pdfExportSettings,
+ Column(
+ children: [
+ NumberInputListTile(
+ initialValue: pdfExportSettings.headerHeight,
+ label: localizations.exportPdfHeaderHeight,
+ onParsableSubmit: (value) {
+ pdfExportSettings.headerHeight = value;
+ },
+ ),
+ NumberInputListTile(
+ initialValue: pdfExportSettings.cellHeight,
+ label: localizations.exportPdfCellHeight,
+ onParsableSubmit: (value) {
+ pdfExportSettings.cellHeight = value;
+ },
+ ),
+ NumberInputListTile(
+ initialValue: pdfExportSettings.headerFontSize,
+ label: localizations.exportPdfHeaderFontSize,
+ onParsableSubmit: (value) {
+ pdfExportSettings.headerFontSize = value;
+ },
+ ),
+ NumberInputListTile(
+ initialValue: pdfExportSettings.cellFontSize,
+ label: localizations.exportPdfCellFontSize,
+ onParsableSubmit: (value) {
+ pdfExportSettings.cellFontSize = value;
+ },
+ ),
+ ExportFieldCustomisationSetting(
+ fieldsSettings: pdfExportSettings,
+ ),
+ ],
),
]
)
lib/screens/settings.dart
@@ -15,7 +15,6 @@ import 'package:blood_pressure_app/screens/subsettings/version.dart';
import 'package:blood_pressure_app/screens/subsettings/warn_about.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path/path.dart';
@@ -167,37 +166,23 @@ class SettingsPage extends StatelessWidget {
onChanged: (value) {
settings.confirmDeletion = value;
}),
- InputSettingsTile(
+ NumberInputListTile(
key: const Key('sysWarn'),
- title: Text(localizations.sysWarn),
+ label: localizations.sysWarn,
leading: const Icon(Icons.warning_amber_outlined),
- keyboardType: TextInputType.number,
- inputFormatters: [FilteringTextInputFormatter.digitsOnly],
- initialValue: settings.sysWarn.toInt().toString(),
- onEditingComplete: (String? value) {
- if (value == null || value.isEmpty || (int.tryParse(value) == null)) {
- return;
- }
- settings.sysWarn = int.parse(value);
+ initialValue: settings.sysWarn,
+ onParsableSubmit: (double value) {
+ settings.sysWarn = value.round();
},
- decoration: InputDecoration(hintText: localizations.sysWarn),
- inputWidth: 120,
),
- InputSettingsTile(
+ NumberInputListTile(
key: const Key('diaWarn'),
- title: Text(localizations.diaWarn),
+ label: localizations.diaWarn,
leading: const Icon(Icons.warning_amber_outlined),
- keyboardType: TextInputType.number,
- inputFormatters: [FilteringTextInputFormatter.digitsOnly],
- initialValue: settings.diaWarn.toInt().toString(),
- onEditingComplete: (String? value) {
- if (value == null || value.isEmpty || (int.tryParse(value) == null)) {
- return;
- }
- settings.diaWarn = int.parse(value);
+ initialValue: settings.diaWarn,
+ onParsableSubmit: (double value) {
+ settings.diaWarn = value.round();
},
- decoration: InputDecoration(hintText: localizations.diaWarn),
- inputWidth: 120,
),
ListTile(
key: const Key('determineWarnValues'),
@@ -208,7 +193,8 @@ class SettingsPage extends StatelessWidget {
context: context,
builder: (context) => NumberInputDialoge(
hintText: localizations.age,
- onParsableSubmit: (age) {
+ onParsableSubmit: (value) {
+ int age = value.round();
settings.sysWarn = BloodPressureWarnValues.getUpperSysWarnValue(age);
settings.diaWarn = BloodPressureWarnValues.getUpperDiaWarnValue(age);
Navigator.of(context).pop();