Commit c90387d

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2023-12-12 15:06:03
reimplement warn banner
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 6d3e7b6
Changed files (4)
lib/components/export_warn_banner.dart
@@ -0,0 +1,105 @@
+import 'package:blood_pressure_app/model/export_import/export_configuration.dart';
+import 'package:blood_pressure_app/model/export_import/legacy_column.dart';
+import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
+import 'package:blood_pressure_app/model/storage/export_csv_settings_store.dart';
+import 'package:blood_pressure_app/model/storage/export_settings_store.dart';
+import 'package:collection/collection.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+/// Banner that gives the user information on the importability of their export.
+class ExportWarnBanner extends StatefulWidget {
+  const ExportWarnBanner({super.key,
+    required this.exportSettings,
+    required this.csvExportSettings,
+    required this.availableColumns});
+
+  final ExportSettings exportSettings;
+  final CsvExportSettings csvExportSettings;
+  final ExportColumnsManager availableColumns;
+
+  @override
+  State<ExportWarnBanner> createState() => _ExportWarnBannerState();
+}
+
+class _ExportWarnBannerState extends State<ExportWarnBanner> {
+  /// Whether the banner was hidden by pressing a button.
+  bool _hidden = false;
+
+  @override
+  Widget build(BuildContext context) {
+    if (_hidden) return _buildOK();
+
+    switch (widget.exportSettings.exportFormat) {
+      case ExportFormat.db:
+        return _buildOK();
+      case ExportFormat.pdf:
+        return _buildNotExportable(context);
+      case ExportFormat.csv:
+        if (widget.csvExportSettings.exportHeadline == false) return _buildNotExportable(context);
+        if (widget.csvExportSettings.fieldDelimiter != ',' && widget.csvExportSettings.fieldDelimiter != '|') return _buildNotExportable(context);
+        if (widget.csvExportSettings.textDelimiter != '"' && widget.csvExportSettings.textDelimiter != "'") return _buildNotExportable(context);
+        if (widget.csvExportSettings.exportHeadline == false) return _buildNotExportable(context);
+        final preset = widget.csvExportSettings.exportFieldsConfiguration.activePreset;
+        switch (preset) {
+          case ExportImportPreset.bloodPressureApp:
+            return _buildOK();
+          case ExportImportPreset.myHeart:
+            return _buildNotExportable(context);
+          case ExportImportPreset.none:
+            final exportedTypes = widget.csvExportSettings.exportFieldsConfiguration
+                .getActiveColumns(widget.availableColumns)
+                .map((column) => column.restoreAbleType);
+
+            if (!exportedTypes.contains(RowDataFieldType.timestamp)) return _buildNotExportable(context);
+
+            final neededForFullExport = ActiveExportColumnConfiguration()
+                .getActiveColumns(widget.availableColumns)
+                .map((column) => column.restoreAbleType);
+            final missingTypes = neededForFullExport
+                .where((column) => !exportedTypes.contains(column));
+            if (missingTypes.isEmpty) return _buildOK();
+
+            return _buildIncompleteExport(context, missingTypes);
+        }
+    }
+  }
+
+  /// Exports made with this configuration are importable.
+  Widget _buildOK() => const SizedBox.shrink();
+
+  /// Exports made with this configuration are not importable for a variety of reasons.
+  Widget _buildNotExportable(BuildContext context) {
+    final localizations = AppLocalizations.of(context)!;
+    return _banner(localizations.exportWarnConfigNotImportable, localizations);
+  }
+
+  /// Exports made with this configuration are not fully importable.
+  Widget _buildIncompleteExport(BuildContext context, Iterable<RowDataFieldType?> missingTypes) {
+    final localizations = AppLocalizations.of(context)!;
+    return _banner(localizations.exportWarnNotEveryFieldExported(
+      missingTypes.length,
+      missingTypes
+          .whereNotNull()
+          .map((e) => e.localize(localizations))
+          .join(', ')
+    ), localizations);
+  }
+
+  Widget _banner(String text, AppLocalizations localizations) {
+    return MaterialBanner(
+        padding: const EdgeInsets.all(20),
+        content: Text(text),
+        actions: [
+          TextButton(
+            onPressed: () {
+              setState(() {
+                _hidden = true;
+              });
+            },
+            child: Text(localizations.btnConfirm)
+          )
+        ]
+      );
+  }
+}
\ No newline at end of file
lib/model/export_import/column.dart
@@ -117,7 +117,8 @@ class NativeColumn extends ExportColumn {
 /// Useful columns that are present by default and recreatable through a formatPattern.
 class BuildInColumn extends ExportColumn {
   /// Creates a build in column and adds it to allColumns.
-  BuildInColumn._create(this.internalIdentifier, this.csvTitle, String formatString, this._userTitle);
+  BuildInColumn._create(this.internalIdentifier, this.csvTitle, String formatString, this._userTitle)
+      : _formatter = ScriptedFormatter(formatString);
   
   static final List<BuildInColumn> allColumns = [
     pulsePressure,
@@ -199,7 +200,7 @@ class BuildInColumn extends ExportColumn {
   @override
   String userTitle(AppLocalizations localizations) => _userTitle(localizations);
 
-  late final Formatter _formatter;
+  final Formatter _formatter;
 
   @override
   (RowDataFieldType, dynamic)? decode(String pattern) => _formatter.decode(pattern);
@@ -223,9 +224,8 @@ class UserColumn extends ExportColumn {
   /// Create a object that handles export behavior for data in a column.
   ///
   /// [formatter] will be created according to [formatString].
-  UserColumn(this.internalIdentifier, this.csvTitle, String formatString) {
-    formatter = ScriptedFormatter(formatString);
-  }
+  UserColumn(this.internalIdentifier, this.csvTitle, String formatString):
+        formatter = ScriptedFormatter(formatString);
 
   @override
   final String internalIdentifier;
@@ -237,7 +237,7 @@ class UserColumn extends ExportColumn {
   String userTitle(AppLocalizations localizations) => csvTitle;
 
   /// Converter associated with this column.
-  late final Formatter formatter;
+  final Formatter formatter;
 
   @override
   (RowDataFieldType, dynamic)? decode(String pattern) => formatter.decode(pattern);
lib/model/export_import/export_configuration.dart
@@ -10,6 +10,8 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 /// Class for managing columns currently used for ex- and import.
 class ActiveExportColumnConfiguration extends ChangeNotifier {
   /// Create a manager of the currently relevant [ExportColumn]s.
+  ///
+  /// The default configuration is guaranteed to be restoreable.
   ActiveExportColumnConfiguration({
     ExportImportPreset? activePreset,
     List<String>? userSelectedColumnIds
lib/screens/subsettings/export_import_screen.dart
@@ -2,18 +2,16 @@ import 'dart:convert';
 import 'dart:io';
 import 'dart:typed_data';
 
-import 'package:blood_pressure_app/components/consistent_future_builder.dart';
 import 'package:blood_pressure_app/components/diabled.dart';
 import 'package:blood_pressure_app/components/display_interval_picker.dart';
+import 'package:blood_pressure_app/components/export_warn_banner.dart';
 import 'package:blood_pressure_app/components/settings/settings_widgets.dart';
 import 'package:blood_pressure_app/model/blood_pressure.dart';
 import 'package:blood_pressure_app/model/export_import/column.dart';
 import 'package:blood_pressure_app/model/export_import/csv_converter.dart';
 import 'package:blood_pressure_app/model/export_import/export_configuration.dart';
-import 'package:blood_pressure_app/model/export_import/legacy_column.dart';
 import 'package:blood_pressure_app/model/export_import/pdf_converter.dart';
 import 'package:blood_pressure_app/model/export_import/record_parsing_result.dart';
-import 'package:blood_pressure_app/model/export_options.dart';
 import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
 import 'package:blood_pressure_app/model/storage/storage.dart';
 import 'package:blood_pressure_app/platform_integration/platform_client.dart';
@@ -39,7 +37,15 @@ class ExportImportScreen extends StatelessWidget {
         return SingleChildScrollView(
           child: Column(
             children: [
-              const ExportWarnBanner(),
+              Consumer<CsvExportSettings>(builder: (context, csvExportSettings, child) =>
+                Consumer<ExportColumnsManager>(builder: (context, availableColumns, child) =>
+                  ExportWarnBanner(
+                    exportSettings: settings,
+                    csvExportSettings: csvExportSettings,
+                    availableColumns: availableColumns
+                  ),
+                ),
+              ),
               const SizedBox(
                 height: 15,
               ),
@@ -437,87 +443,3 @@ class ExportImportButtons extends StatelessWidget {
     }
   }
 }
-
-class ExportWarnBanner extends StatefulWidget {
-  const ExportWarnBanner({super.key});
-
-  @override
-  State<StatefulWidget> createState() => _ExportWarnBannerState();
-}
-
-class _ExportWarnBannerState extends State<ExportWarnBanner> {
-  bool _showWarnBanner = true;
-
-  @override
-  Widget build(BuildContext context) {
-    final localizations = AppLocalizations.of(context)!;
-    return Consumer<Settings>(builder: (context, settings, child) =>
-      Consumer<ExportSettings>(builder: (context, exportSettings, child) =>
-        Consumer<CsvExportSettings>(builder: (context, csvExportSettings, child) =>
-          Consumer<PdfExportSettings>(builder: (context, pdfExportSettings, child) =>
-            ConsistentFutureBuilder(
-              future: ExportConfigurationModel.get(localizations),
-              lastChildWhileWaiting: true,
-              onData: (context, configurationModel) {
-                String? message;
-                final CustomFieldsSettings fieldSettings = (exportSettings.exportFormat == ExportFormat.csv
-                    ? csvExportSettings : pdfExportSettings) as CustomFieldsSettings;
-
-                final missingAttributes = _getMissingAttributes(exportSettings, fieldSettings, configurationModel);
-                if (ExportFormat.db == exportSettings.exportFormat) {
-                  // When exporting as database no wrong configuration is possible
-                } else if (_showWarnBanner && _isExportable(exportSettings, csvExportSettings,
-                    fieldSettings.exportFieldsConfiguration, missingAttributes)) {
-                  message = localizations.exportWarnConfigNotImportable;
-                } else if (_showWarnBanner &&
-                    fieldSettings.exportFieldsConfiguration.activePreset != ExportImportPreset.bloodPressureApp && missingAttributes.isNotEmpty) {
-                  message = localizations.exportWarnNotEveryFieldExported(
-                      missingAttributes.length, missingAttributes.map((e) => e.localize(localizations)).join(', '));
-                }
-
-                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();
-              }))
-        )
-    ));
-  }
-}
-
-bool _isExportable(ExportSettings exportSettings, CsvExportSettings csvExportSettings, ActiveExportColumnConfiguration exportConfig, Set<RowDataFieldType> missingAttributes) {
-  return ((ExportFormat.pdf == exportSettings.exportFormat) ||
-      csvExportSettings.exportHeadline == false ||
-      // exportCustomEntries && TODO: replace or rewrite method?
-          missingAttributes.contains(RowDataFieldType.timestamp) ||
-      ![',', '|'].contains(csvExportSettings.fieldDelimiter) ||
-      !['"', '\''].contains(csvExportSettings.textDelimiter));
-}
-
-Set<RowDataFieldType> _getMissingAttributes(ExportSettings exportSettings, CustomFieldsSettings fieldSettings,
-    ExportConfigurationModel configurationModel) {
-  final exportFormats = configurationModel
-      .getActiveExportColumns(exportSettings.exportFormat, fieldSettings)
-      .map((e) => e.parsableFormat);
-  var missingAttributes = {
-    RowDataFieldType.timestamp,
-    RowDataFieldType.sys,
-    RowDataFieldType.dia,
-    RowDataFieldType.pul,
-    RowDataFieldType.notes,
-    RowDataFieldType.color
-  };
-  missingAttributes.removeWhere((e) => exportFormats.contains(e));
-  return missingAttributes;
-}