Commit 756aef1

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2023-09-24 13:14:26
rework export warn banner conditions
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 04fe232
Changed files (2)
lib
lib/model/export_options.dart
@@ -61,7 +61,7 @@ class ExportConfigurationModel {
     return _instance!;
   }
 
-  List<ExportColumn> _getActiveExportColumns(ExportFormat format) {
+  List<ExportColumn> getActiveExportColumns(ExportFormat format) {
     switch (format) {
       case ExportFormat.csv:
         return availableFormats.where((e) =>
@@ -134,7 +134,7 @@ class ExportConfigurationModel {
       UnmodifiableMapView(Map.fromIterable(_availableFormats, key: (e) => e.internalName));
 
   List<List<String>> createTable(List<BloodPressureRecord> data, ExportFormat format, {bool createHeadline = true,}) {
-    final exportItems = _getActiveExportColumns(format);
+    final exportItems = getActiveExportColumns(format);
     List<List<String>> items = [];
     if (createHeadline) {
       items.add(exportItems.map((e) => e.internalName).toList());
@@ -261,8 +261,18 @@ class ExportColumn {
   /// Checks if the pattern can be used to parse records. This is the case when the pattern contains variables without
   /// containing curly brackets or commas.
   bool get isReversible {
-    return formatPattern == r'$TIMESTAMP' ||
-        formatPattern.contains(RegExp(r'\$(TIMESTAMP|SYS|DIA|PUL|NOTE)')) && !formatPattern.contains(RegExp(r'[{},]'));
+    return (formatPattern == r'$TIMESTAMP') ||
+        formatPattern.contains(RegExp(r'\$(SYS|DIA|PUL|NOTE)')) && !formatPattern.contains(RegExp(r'[{},]'));
+  }
+
+  RowDataFieldType? get parsableFormat {
+    if (formatPattern.contains(RegExp(r'[{},]'))) return null;
+    if (formatPattern == r'$TIMESTAMP') return RowDataFieldType.timestamp;
+    if (formatPattern.contains(RegExp(r'\$(SYS)'))) return RowDataFieldType.sys;
+    if (formatPattern.contains(RegExp(r'\$(DIA)'))) return RowDataFieldType.dia;
+    if (formatPattern.contains(RegExp(r'\$(PUL)'))) return RowDataFieldType.pul;
+    if (formatPattern.contains(RegExp(r'\$(NOTE)'))) return RowDataFieldType.notes;
+    return null;
   }
 
   @override
lib/screens/subsettings/export_import_screen.dart
@@ -27,35 +27,41 @@ class ExportImportScreen extends StatelessWidget {
           child: Column(
             children: [
               const ExportWarnBanner(),
-              const SizedBox(height: 15,),
+              const SizedBox(
+                height: 15,
+              ),
               Opacity(
                 opacity: (settings.exportFormat == ExportFormat.db) ? 0.7 : 1,
-                child: IgnorePointer(ignoring: (settings.exportFormat == ExportFormat.db), child: const IntervalPicker()),
+                child: IgnorePointer(
+                    ignoring: (settings.exportFormat == ExportFormat.db),
+                    child: const IntervalPicker()),
               ),
               SettingsTile(
-                title: Text(localizations.exportDir),
-                description: Text(settings.defaultExportDir),
-                onPressed: (context) async {
-                  final appDir = await JSaver.instance.setDefaultSavingDirectory();
-                  settings.defaultExportDir = appDir.value;
-                }
-              ),
+                  title: Text(localizations.exportDir),
+                  description: Text(settings.defaultExportDir),
+                  onPressed: (context) async {
+                    final appDir =
+                        await JSaver.instance.setDefaultSavingDirectory();
+                    settings.defaultExportDir = appDir.value;
+                  }),
               SwitchSettingsTile(
                   title: Text(localizations.exportAfterEveryInput),
                   description: Text(localizations.exportAfterEveryInputDesc),
                   initialValue: settings.exportAfterEveryEntry,
                   onToggle: (value) {
                     settings.exportAfterEveryEntry = value;
-                  }
-              ),
+                  }),
               DropDownSettingsTile<ExportFormat>(
                 key: const Key('exportFormat'),
                 title: Text(localizations.exportFormat),
                 value: settings.exportFormat,
                 items: [
-                  DropdownMenuItem(value: ExportFormat.csv, child: Text(localizations.csv)),
-                  DropdownMenuItem(value: ExportFormat.pdf, child: Text(localizations.pdf)),
-                  DropdownMenuItem(value: ExportFormat.db, child: Text(localizations.db)),
+                  DropdownMenuItem(
+                      value: ExportFormat.csv, child: Text(localizations.csv)),
+                  DropdownMenuItem(
+                      value: ExportFormat.pdf, child: Text(localizations.pdf)),
+                  DropdownMenuItem(
+                      value: ExportFormat.db, child: Text(localizations.db)),
                 ],
                 onChanged: (ExportFormat? value) {
                   if (value != null) {
@@ -86,46 +92,43 @@ class ExportImportScreen extends StatelessWidget {
                 },
               ),
               SwitchSettingsTile(
-                title: Text(localizations.exportCsvHeadline),
-                description: Text(localizations.exportCsvHeadlineDesc),
-                initialValue: settings.exportCsvHeadline,
-                disabled: settings.exportFormat != ExportFormat.csv,
-                onToggle: (value) {
-                  settings.exportCsvHeadline = value;
-                }
-              ),
+                  title: Text(localizations.exportCsvHeadline),
+                  description: Text(localizations.exportCsvHeadlineDesc),
+                  initialValue: settings.exportCsvHeadline,
+                  disabled: settings.exportFormat != ExportFormat.csv,
+                  onToggle: (value) {
+                    settings.exportCsvHeadline = value;
+                  }),
               SwitchSettingsTile(
-                title: Text(localizations.exportPdfExportTitle),
-                initialValue: settings.exportPdfExportTitle,
-                disabled: settings.exportFormat != ExportFormat.pdf,
-                onToggle: (value) {
-                  settings.exportPdfExportTitle = value;
-                }
-              ),
+                  title: Text(localizations.exportPdfExportTitle),
+                  initialValue: settings.exportPdfExportTitle,
+                  disabled: settings.exportFormat != ExportFormat.pdf,
+                  onToggle: (value) {
+                    settings.exportPdfExportTitle = value;
+                  }),
               SwitchSettingsTile(
-                title: Text(localizations.exportPdfExportStatistics),
-                initialValue: settings.exportPdfExportStatistics,
-                disabled: settings.exportFormat != ExportFormat.pdf,
-                onToggle: (value) {
-                  settings.exportPdfExportStatistics = value;
-                }
-              ),
+                  title: Text(localizations.exportPdfExportStatistics),
+                  initialValue: settings.exportPdfExportStatistics,
+                  disabled: settings.exportFormat != ExportFormat.pdf,
+                  onToggle: (value) {
+                    settings.exportPdfExportStatistics = value;
+                  }),
               SwitchSettingsTile(
-                title: Text(localizations.exportPdfExportData),
-                initialValue: settings.exportPdfExportData,
-                disabled: settings.exportFormat != ExportFormat.pdf,
-                onToggle: (value) {
-                  settings.exportPdfExportData = value;
-                }
-              ),
+                  title: Text(localizations.exportPdfExportData),
+                  initialValue: settings.exportPdfExportData,
+                  disabled: settings.exportFormat != ExportFormat.pdf,
+                  onToggle: (value) {
+                    settings.exportPdfExportData = value;
+                  }),
               InputSettingsTile(
                 initialValue: settings.exportPdfHeaderHeight.toString(),
                 title: Text(localizations.exportPdfHeaderHeight),
                 onEditingComplete: (value) {
-                  final pV = double.tryParse(value??'');
+                  final pV = double.tryParse(value ?? '');
                   if (pV != null) settings.exportPdfHeaderHeight = pV;
                 },
-                disabled: !(settings.exportFormat == ExportFormat.pdf && settings.exportPdfExportData),
+                disabled: !(settings.exportFormat == ExportFormat.pdf &&
+                    settings.exportPdfExportData),
                 keyboardType: TextInputType.number,
                 inputWidth: 40,
               ),
@@ -133,10 +136,11 @@ class ExportImportScreen extends StatelessWidget {
                 initialValue: settings.exportPdfCellHeight.toString(),
                 title: Text(localizations.exportPdfCellHeight),
                 onEditingComplete: (value) {
-                  final pV = double.tryParse(value??'');
+                  final pV = double.tryParse(value ?? '');
                   if (pV != null) settings.exportPdfCellHeight = pV;
                 },
-                disabled: !(settings.exportFormat == ExportFormat.pdf && settings.exportPdfExportData),
+                disabled: !(settings.exportFormat == ExportFormat.pdf &&
+                    settings.exportPdfExportData),
                 keyboardType: TextInputType.number,
                 inputWidth: 40,
               ),
@@ -144,10 +148,11 @@ class ExportImportScreen extends StatelessWidget {
                 initialValue: settings.exportPdfHeaderFontSize.toString(),
                 title: Text(localizations.exportPdfHeaderFontSize),
                 onEditingComplete: (value) {
-                  final pV = double.tryParse(value??'');
+                  final pV = double.tryParse(value ?? '');
                   if (pV != null) settings.exportPdfHeaderFontSize = pV;
                 },
-                disabled: !(settings.exportFormat == ExportFormat.pdf && settings.exportPdfExportData),
+                disabled: !(settings.exportFormat == ExportFormat.pdf &&
+                    settings.exportPdfExportData),
                 keyboardType: TextInputType.number,
                 inputWidth: 40,
               ),
@@ -155,10 +160,11 @@ class ExportImportScreen extends StatelessWidget {
                 initialValue: settings.exportPdfCellFontSize.toString(),
                 title: Text(localizations.exportPdfCellFontSize),
                 onEditingComplete: (value) {
-                  final pV = double.tryParse(value??'');
+                  final pV = double.tryParse(value ?? '');
                   if (pV != null) settings.exportPdfCellFontSize = pV;
                 },
-                disabled: !(settings.exportFormat == ExportFormat.pdf && settings.exportPdfExportData),
+                disabled: !(settings.exportFormat == ExportFormat.pdf &&
+                    settings.exportPdfExportData),
                 keyboardType: TextInputType.number,
                 inputWidth: 40,
               ),
@@ -176,73 +182,79 @@ class ExportFieldCustomisationSetting extends StatefulWidget {
   const ExportFieldCustomisationSetting({super.key});
 
   @override
-  State<ExportFieldCustomisationSetting> createState() => _ExportFieldCustomisationSettingState();
+  State<ExportFieldCustomisationSetting> createState() =>
+      _ExportFieldCustomisationSettingState();
 }
 
-class _ExportFieldCustomisationSettingState extends State<ExportFieldCustomisationSetting> {
+class _ExportFieldCustomisationSettingState
+    extends State<ExportFieldCustomisationSetting> {
   // hack so that FutureBuilder doesn't always rebuild
   Future<ExportConfigurationModel>? _future;
-  
+
   @override
   Widget build(BuildContext context) {
     final localizations = AppLocalizations.of(context)!;
-    _future ??= ExportConfigurationModel.get(Provider.of<Settings>(context, listen: false), localizations);
+    _future ??= ExportConfigurationModel.get(
+        Provider.of<Settings>(context, listen: false), localizations);
 
     return ConsistentFutureBuilder(
-      future: _future!,
-      onData: (context, result) {
-        return Consumer<Settings>(builder: (context, settings, child) {
-          /// whether or not the currently selected export format supports field customization
-          final isApplicable = (settings.exportFormat == ExportFormat.csv || settings.exportFormat == ExportFormat.pdf &&
-              settings.exportPdfExportData);
-          final exportCustomEntries = (settings.exportFormat == ExportFormat.csv) ?
-              settings.exportCustomEntriesCsv : settings.exportCustomEntriesPdf;
-          final exportItems = (settings.exportFormat == ExportFormat.csv) ? settings.exportItemsCsv : settings.exportItemsPdf;
+        future: _future!,
+        onData: (context, configurationModel) {
+          return Consumer<Settings>(builder: (context, settings, child) {
+            /// whether or not the currently selected export format supports field customization
+            final isApplicable = (settings.exportFormat == ExportFormat.csv ||
+                settings.exportFormat == ExportFormat.pdf &&
+                    settings.exportPdfExportData);
+            final exportCustomEntries =
+                (settings.exportFormat == ExportFormat.csv)
+                    ? settings.exportCustomEntriesCsv
+                    : settings.exportCustomEntriesPdf;
+            final exportItems = (settings.exportFormat == ExportFormat.csv)
+                ? settings.exportItemsCsv
+                : settings.exportItemsPdf;
 
-          final formats = result.availableFormats.toSet();
-          List<ExportColumn> activeFields = [];
-          List<ExportColumn> hiddenFields = [];
-          for (final internalName in exportItems) {
-            activeFields.add(formats.singleWhere((e) => e.internalName == internalName));
-            formats.removeWhere((e) => e.internalName == internalName);
-          }
-          hiddenFields = formats.toList();
-          
-          return Column(
-            children: [
-              SwitchSettingsTile(
-                  title: Text(localizations.exportCustomEntries),
-                  initialValue: exportCustomEntries,
-                  disabled: !isApplicable,
-                  onToggle: (value) {
-                    if (settings.exportFormat == ExportFormat.csv) {
-                      settings.exportCustomEntriesCsv = value;
-                    } else {
-                      assert(settings.exportFormat == ExportFormat.pdf);
-                      settings.exportCustomEntriesPdf = value;
-                    }
-
-                  }
-              ),
-              (exportCustomEntries && isApplicable) ?
-                ExportItemsCustomizer(
-                  shownItems: activeFields,
-                  disabledItems: hiddenFields,
-                  onReorder: (exportItems, exportAddableItems) {
-                    if (settings.exportFormat == ExportFormat.csv) {
-                      settings.exportItemsCsv = exportItems.map((e) => e.internalName).toList();
-                    } else {
-                      assert(settings.exportFormat == ExportFormat.pdf);
-                      settings.exportItemsPdf = exportItems.map((e) => e.internalName).toList();
-                    }
+            final formats = configurationModel.availableFormats.toSet();
+            List<ExportColumn> activeFields = configurationModel.getActiveExportColumns(settings.exportFormat);
+            List<ExportColumn> hiddenFields = [];
+            for (final internalName in exportItems) {
+              formats.removeWhere((e) => e.internalName == internalName);
+            }
+            hiddenFields = formats.toList();
 
-                  },
-                ) : const SizedBox.shrink()
-            ],
-          );
+            return Column(
+              children: [
+                SwitchSettingsTile(
+                    title: Text(localizations.exportCustomEntries),
+                    initialValue: exportCustomEntries,
+                    disabled: !isApplicable,
+                    onToggle: (value) {
+                      if (settings.exportFormat == ExportFormat.csv) {
+                        settings.exportCustomEntriesCsv = value;
+                      } else {
+                        assert(settings.exportFormat == ExportFormat.pdf);
+                        settings.exportCustomEntriesPdf = value;
+                      }
+                    }),
+                (exportCustomEntries && isApplicable)
+                    ? ExportItemsCustomizer(
+                        shownItems: activeFields,
+                        disabledItems: hiddenFields,
+                        onReorder: (exportItems, exportAddableItems) {
+                          if (settings.exportFormat == ExportFormat.csv) {
+                            settings.exportItemsCsv =
+                                exportItems.map((e) => e.internalName).toList();
+                          } else {
+                            assert(settings.exportFormat == ExportFormat.pdf);
+                            settings.exportItemsPdf =
+                                exportItems.map((e) => e.internalName).toList();
+                          }
+                        },
+                      )
+                    : const SizedBox.shrink()
+              ],
+            );
+          });
         });
-      }
-    );
   }
 }
 
@@ -267,19 +279,33 @@ class ExportImportButtons extends StatelessWidget {
                 flex: 50,
                 child: MaterialButton(
                   height: 60,
-                  child:  Text(localizations.export),
-                  onPressed: () async => Exporter(settings, model, messenger, localizations, theme, await ExportConfigurationModel.get(settings, localizations)).export(),
-                )
-            ),
+                  child: Text(localizations.export),
+                  onPressed: () async => Exporter(
+                          settings,
+                          model,
+                          messenger,
+                          localizations,
+                          theme,
+                          await ExportConfigurationModel.get(
+                              settings, localizations))
+                      .export(),
+                )),
             const VerticalDivider(),
             Expanded(
                 flex: 50,
                 child: MaterialButton(
                   height: 60,
                   child: Text(localizations.import),
-                  onPressed: () async => Exporter(settings, model, messenger, localizations, theme, await ExportConfigurationModel.get(settings, localizations)).import(),
-                )
-            ),
+                  onPressed: () async => Exporter(
+                          settings,
+                          model,
+                          messenger,
+                          localizations,
+                          theme,
+                          await ExportConfigurationModel.get(
+                              settings, localizations))
+                      .import(),
+                )),
           ],
         ),
       ),
@@ -296,47 +322,68 @@ class ExportWarnBanner extends StatefulWidget {
 
 class _ExportWarnBannerState extends State<ExportWarnBanner> {
   bool _showWarnBanner = true;
+  late Future<ExportConfigurationModel> _future;
+
   @override
   Widget build(BuildContext context) {
     final localizations = AppLocalizations.of(context)!;
-    String? message;
+    _future = ExportConfigurationModel.get(Provider.of<Settings>(context, listen: false), localizations);
     return Consumer<Settings>(builder: (context, settings, child) {
-      final exportItems = (settings.exportFormat == ExportFormat.csv) ? settings.exportItemsCsv : settings.exportItemsPdf;
-      final exportCustomEntries = (settings.exportFormat == ExportFormat.csv) ?
-      settings.exportCustomEntriesCsv : settings.exportCustomEntriesPdf;
+      return ConsistentFutureBuilder(
+          future: _future,
+          onData: (context, configurationModel) {
+            String? message;
+            final exportItems = (settings.exportFormat == ExportFormat.csv)
+                ? settings.exportItemsCsv
+                : settings.exportItemsPdf;
+            final exportCustomEntries =
+                (settings.exportFormat == ExportFormat.csv)
+                    ? settings.exportCustomEntriesCsv
+                    : settings.exportCustomEntriesPdf;
+            final exportFormats = configurationModel.getActiveExportColumns(settings.exportFormat)
+                .map((e) => e.parsableFormat);
 
-      if (_showWarnBanner && ![ExportFormat.csv, ExportFormat.db].contains(settings.exportFormat) ||
-          settings.exportCsvHeadline == false ||
-          exportCustomEntries && !(['timestampUnixMs'].any((i) => exportItems.contains(i))) ||
-          ![',', '|'].contains(settings.csvFieldDelimiter) ||
-          !['"', '\''].contains(settings.csvTextDelimiter)
-      ) {
-        message = localizations.exportWarnConfigNotImportable;
-      } else if (_showWarnBanner && exportCustomEntries &&
-          !(['systolic','diastolic', 'pulse', 'notes'].every((i) => exportItems.contains(i)))) {
-        var missingAttributes = {'systolic','diastolic', 'pulse', 'notes'};
-        missingAttributes.removeWhere((e) => exportItems.contains(e));
+            if (_showWarnBanner &&
+                    ![ExportFormat.csv, ExportFormat.db]
+                        .contains(settings.exportFormat) ||
+                settings.exportCsvHeadline == false ||
+                exportCustomEntries && exportFormats.where((e) => e == RowDataFieldType.timestamp).isEmpty ||
+                ![',', '|'].contains(settings.csvFieldDelimiter) ||
+                !['"', '\''].contains(settings.csvTextDelimiter)) {
+              print(exportFormats.join(','));
+              message = localizations.exportWarnConfigNotImportable;
+            } else if (_showWarnBanner &&
+                exportCustomEntries &&
+                !([RowDataFieldType.sys, RowDataFieldType.dia, RowDataFieldType.pul, RowDataFieldType.notes]
+                    .every((i) => exportFormats.contains(i)))) {
+              var missingAttributes = {
+                'systolic',
+                'diastolic',
+                'pulse',
+                'notes'
+              };
+              missingAttributes.removeWhere((e) => exportItems.contains(e));
 
-        message = localizations.exportWarnNotEveryFieldExported(missingAttributes.length, missingAttributes.toString());
-      }
+              message = localizations.exportWarnNotEveryFieldExported(
+                  missingAttributes.length, missingAttributes.toString());
+            }
 
-      if (message != null) {
-        return MaterialBanner(
-            padding: const EdgeInsets.all(20),
-            content: Text(message!),
-            actions: [
-              TextButton(
-                  onPressed: () {
-                    setState(() {
-                      _showWarnBanner = false;
-                    });
-                  },
-                  child: Text(localizations.btnConfirm))
-            ]
-        );
-      }
-      return const SizedBox.shrink();
+            if (message != null) {
+              return MaterialBanner(
+                  padding: const EdgeInsets.all(20),
+                  content: Text(message!),
+                  actions: [
+                    TextButton(
+                        onPressed: () {
+                          setState(() {
+                            _showWarnBanner = false;
+                          });
+                        },
+                        child: Text(localizations.btnConfirm))
+                  ]);
+            }
+            return const SizedBox.shrink();
+          });
     });
-    }
   }
-
+}