Commit e8d3a52

derdilla <derdilla06@gmail.com>
2023-06-20 16:15:06
rewrite function to parse csv files
1 parent 02709cc
Changed files (4)
lib/l10n/app_de.arb
@@ -37,6 +37,9 @@
   "errNoData": "Keine Daten",
   "errNoRangeForExport": "Sie müssen angeben, welche daten sie exportieren wollen.",
   "errPleaseSelect": "Bitte auswählen",
+  "errNotCsvFormat": "Es können nur Dateien im csv Format importiert werden.",
+  "errNeedHeadline": "Es können nur Dateien mit einer Überschrift importiert werden.",
+
 
   "btnCancel": "ABBRUCH",
   "btnSave": "OK",
lib/l10n/app_en.arb
@@ -37,6 +37,9 @@
   "errNoData": "no data",
   "errNoRangeForExport": "You need to specify a range in which data is exported.",
   "errPleaseSelect": "please select",
+  "errNotCsvFormat": "You can only import files in csv format.",
+  "errNeedHeadline": "You can only import files with a headline.",
+  "errCantReadFile": "The file contents can not be read",
 
   "btnCancel": "CANCEL",
   "btnSave": "SAVE",
lib/model/export_import.dart
@@ -29,7 +29,7 @@ class DataExporter {
             csvHead += settings.csvFieldDelimiter;
           }
         }
-        csvHead += '\n';
+        csvHead += '\r\n';
       }
 
       List<List<dynamic>> items = [];
@@ -64,6 +64,66 @@ class DataExporter {
     }
     return Uint8List(0);
   }
+
+  List<BloodPressureRecord> parseCSVFile(Uint8List data) {
+    assert(settings.exportFormat == ExportFormat.csv);
+    assert(settings.exportCsvHeadline);
+
+    List<BloodPressureRecord> records = [];
+
+    String fileContents = utf8.decode(data.toList());
+    final converter = CsvToListConverter(fieldDelimiter: settings.csvFieldDelimiter, textDelimiter: settings.csvTextDelimiter);
+    final csvLines = converter.convert(fileContents);
+    if (csvLines.length <= 1) {
+      throw const FormatException('empty file');
+    }
+    final attributes = csvLines.removeAt(0);
+    var creationTimePos = -1;
+    var sysPos = -1;
+    var diaPos = -1;
+    var pulPos = -1;
+    var notePos = -1;
+    for (var i = 0; i<attributes.length; i++) {
+      switch (attributes[i]) {
+        case 'timestampUnixMs':
+          creationTimePos = i;
+          break;
+        case 'systolic':
+          sysPos = i;
+          break;
+        case 'diastolic':
+          diaPos = i;
+          break;
+        case 'pulse':
+          pulPos = i;
+          break;
+        case 'notes':
+          notePos = i;
+          break;
+      }
+    }
+    assert(creationTimePos >= 0);
+    assert(sysPos >= 0);
+    assert(diaPos >= 0);
+    assert(pulPos >= 0);
+    assert(notePos >= 0);
+
+    for (final line in csvLines) {
+      records.add(
+          BloodPressureRecord(
+              DateTime.fromMillisecondsSinceEpoch(line[creationTimePos]),
+              line[sysPos],
+              line[diaPos],
+              line[pulPos],
+              line[notePos]
+          )
+      );
+    }
+    // TODO: maybe use customized fields if no header is present?
+    // requires changes in screen class
+
+    return records;
+  }
 }
 
 class ExportFormat {
lib/screens/subsettings/export_import_screen.dart
@@ -6,6 +6,7 @@ import 'package:blood_pressure_app/components/settings_widgets.dart';
 import 'package:blood_pressure_app/model/blood_pressure.dart';
 import 'package:blood_pressure_app/model/export_import.dart';
 import 'package:blood_pressure_app/model/settings_store.dart';
+import 'package:file_picker/file_picker.dart';
 import 'package:file_saver/file_saver.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -194,23 +195,36 @@ class ExportImportScreen extends StatelessWidget {
                 child: MaterialButton(
                   height: 60,
                   child: Text(AppLocalizations.of(context)!.import),
-                  onPressed: () {
-                    try {
-                      Provider.of<BloodPressureModel>(context, listen: false).import((res) {
-                        if (res) {
-                          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
-                              content:
-                              Text(AppLocalizations.of(context)!.success(AppLocalizations.of(context)!.import))));
-                        } else {
-                          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
-                              content: Text(AppLocalizations.of(context)!
-                                  .error(AppLocalizations.of(context)!.errNoFileOpened))));
-                        }
-                      });
-                    } on Exception catch (e) {
-                      ScaffoldMessenger.of(context)
-                          .showSnackBar(SnackBar(content: Text(AppLocalizations.of(context)!.error(e.toString()))));
+                  onPressed: () async {
+                    final settings = Provider.of<Settings>(context, listen: false);
+                    if (!(settings.exportFormat == ExportFormat.csv)) {
+                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+                          content: Text(AppLocalizations.of(context)!.errNotCsvFormat)));
+                    }
+                    if (!settings.exportCsvHeadline) {
+                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+                          content: Text(AppLocalizations.of(context)!.errNeedHeadline)));
+                    }
+
+                    // TODO: import from here
+
+
+                    var result = await FilePicker.platform.pickFiles(
+                      allowMultiple: false,
+                      withData: true,
+                    );
+                    if (result == null) {
+                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+                          content: Text(AppLocalizations.of(context)!.errNoFileOpened)));
+                      return;
+                    }
+                    var binaryContent = result.files.single.bytes;
+                    if (binaryContent == null) {
+                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+                          content: Text(AppLocalizations.of(context)!.errCantReadFile)));
+                      return;
                     }
+                    DataExporter(settings).parseCSVFile(binaryContent);
                   },
                 )
               ),