Commit 80ecab9

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2023-11-05 13:13:52
update InputSettingsTile
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 16a33f4
Changed files (4)
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();