Commit a0817ed

derdilla <derdilla06@gmail.com>
2023-07-30 13:15:15
don't store context across async gaps as Export attribute anymore
1 parent be09b59
Changed files (4)
lib/l10n/app_en.arb
@@ -347,5 +347,16 @@
   "drawRegressionLinesDesc": "Draws regression lines in graph. Only useful for large intervalls.",
   "@drawRegressionLinesDesc": {},
   "exportHiddenFields": "hidden fields",
-  "@exportHiddenFields": {}
+  "@exportHiddenFields": {},
+  "pdfDocumentTitle": "Blood pressure values from {start} until {end}",
+  "@pdfDocumentTitle": {
+    "placeholders": {
+      "start": {
+        "type": "string"
+      },
+      "end": {
+        "type": "string"
+      }
+    }
+  }
 }
lib/model/export_import.dart
@@ -3,26 +3,28 @@ import 'dart:convert';
 import 'dart:io';
 import 'dart:typed_data';
 
+import 'package:blood_pressure_app/model/blood_pressure_analyzer.dart';
 import 'package:blood_pressure_app/model/settings_store.dart';
 import 'package:csv/csv.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';
+import 'package:intl/intl.dart';
 import 'package:jsaver/jSaver.dart';
 import 'package:path/path.dart';
 import 'package:pdf/pdf.dart';
 import 'package:pdf/widgets.dart' as pw;
-import 'package:provider/provider.dart';
 import 'package:share_plus/share_plus.dart';
 import 'package:sqflite/sqflite.dart';
 
 import 'blood_pressure.dart';
 
 class ExportFileCreator {
-  Settings settings;
+  final Settings settings;
+  final AppLocalizations localizations;
 
-  ExportFileCreator(this.settings);
+  ExportFileCreator(this.settings, this.localizations);
 
   Future<Uint8List> createFile(List<BloodPressureRecord> records) async {
     switch (settings.exportFormat) {
@@ -165,13 +167,19 @@ class ExportFileCreator {
   }
 
   Future<Uint8List> createPdfFile(List<BloodPressureRecord> data) async {
+    final analyzer = BloodPressureAnalyser(data);
+    final dateFormatter = DateFormat(settings.dateFormatString);
+
     pw.Document pdf = pw.Document();
 
     pdf.addPage(pw.Page(
         pageFormat: PdfPageFormat.a4,
         build: (pw.Context context) {
-          return pw.Center(
-            child: pw.Table(
+          return pw.Column(
+            children: [
+              pw.Text(localizations.pdfDocumentTitle(dateFormatter.format(analyzer.firstDay!),
+                  dateFormatter.format(analyzer.lastDay!))),
+              pw.Table(
                 children: [
                   pw.TableRow(
                       children: [
@@ -193,7 +201,8 @@ class ExportFileCreator {
                         ]
                     )
                 ]
-            ),
+              )
+            ],
           );
         }));
     return await pdf.save();
@@ -215,18 +224,15 @@ class ExportFileCreator {
 }
 
 class Exporter {
-  BuildContext context;
-  Exporter(this.context);
+  final Settings settings;
+  final BloodPressureModel model;
+  final ScaffoldMessengerState messenger;
+  final AppLocalizations localizations;
+  Exporter(this.settings, this.model, this.messenger, this.localizations);
 
   Future<void> export() async {
-    var settings = Provider.of<Settings>(context, listen: false);
-    final messenger = ScaffoldMessenger.of(context);
-    final localizations = AppLocalizations.of(context);
-
-    final entries = await Provider.of<BloodPressureModel>(context, listen: false)
-        .getInTimeRange(settings.displayDataStart, settings.displayDataEnd);
-    var fileContents = await ExportFileCreator(settings).createFile(entries);
-
+    final entries = await model.getInTimeRange(settings.displayDataStart, settings.displayDataEnd);
+    var fileContents = await ExportFileCreator(settings, localizations).createFile(entries);
     String filename = 'blood_press_${DateTime.now().toIso8601String()}';
     String ext;
     switch(settings.exportFormat) {
@@ -243,14 +249,14 @@ class Exporter {
     String path = await FileSaver.instance.saveFile(name: filename, ext: ext, bytes: fileContents);
 
     if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) {
-      messenger.showSnackBar(SnackBar(content: Text(localizations!.success(path))));
+      messenger.showSnackBar(SnackBar(content: Text(localizations.success(path))));
     } else if (Platform.isAndroid || Platform.isIOS) {
       if (settings.defaultExportDir.isNotEmpty) {
         JSaver.instance.save(
             fromPath: path,
             androidPathOptions: AndroidPathOptions(toDefaultDirectory: true)
         );
-        messenger.showSnackBar(SnackBar(content: Text(localizations!.success(settings.defaultExportDir))));
+        messenger.showSnackBar(SnackBar(content: Text(localizations.success(settings.defaultExportDir))));
       } else {
         Share.shareXFiles([
           XFile(
@@ -266,14 +272,8 @@ class Exporter {
 
 
   Future<void> import() async {
-    final messenger = ScaffoldMessenger.of(context);
-    final localizations = AppLocalizations.of(context);
-
-    final settings = Provider.of<Settings>(context, listen: false);
-    final model = Provider.of<BloodPressureModel>(context, listen: false);
-
     if (!([ExportFormat.csv, ExportFormat.db].contains(settings.exportFormat))) {
-      messenger.showSnackBar(SnackBar(content: Text(localizations!.errWrongImportFormat)));
+      messenger.showSnackBar(SnackBar(content: Text(localizations.errWrongImportFormat)));
       return;
     }
 
@@ -282,23 +282,23 @@ class Exporter {
       withData: true,
     );
     if (result == null) {
-      messenger.showSnackBar(SnackBar(content: Text(localizations!.errNoFileOpened)));
+      messenger.showSnackBar(SnackBar(content: Text(localizations.errNoFileOpened)));
       return;
     }
     var binaryContent = result.files.single.bytes;
     if (binaryContent == null) {
-      messenger.showSnackBar(SnackBar(content: Text(localizations!.errCantReadFile)));
+      messenger.showSnackBar(SnackBar(content: Text(localizations.errCantReadFile)));
       return;
     }
     var path = result.files.single.path;
     assert(path != null); // null state directly linked to binary content
 
-    var fileContents = await ExportFileCreator(settings).parseFile(path! ,binaryContent);
+    var fileContents = await ExportFileCreator(settings, localizations).parseFile(path! ,binaryContent);
     if (fileContents == null) {
-      messenger.showSnackBar(SnackBar(content: Text(localizations!.errNotImportable)));
+      messenger.showSnackBar(SnackBar(content: Text(localizations.errNotImportable)));
       return;
     }
-    messenger.showSnackBar(SnackBar(content: Text(localizations!.importSuccess(fileContents.length))));
+    messenger.showSnackBar(SnackBar(content: Text(localizations.importSuccess(fileContents.length))));
     for (final e in fileContents) {
       model.add(e);
     }
lib/screens/subsettings/export_import_screen.dart
@@ -1,5 +1,6 @@
 import 'package:blood_pressure_app/components/display_interval_picker.dart';
 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:flutter/material.dart';
@@ -7,7 +8,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 import 'package:jsaver/jSaver.dart';
 import 'package:provider/provider.dart';
 
-// TODO: control if warn messages work
 class ExportImportScreen extends StatelessWidget {
   const ExportImportScreen({super.key});
 
@@ -25,7 +25,7 @@ class ExportImportScreen extends StatelessWidget {
               const ExportWarnBanner(),
               const SizedBox(height: 15,),
               Opacity(
-                opacity: (settings.exportFormat == ExportFormat.db) ? 0.5 : 1, // TODO: centralize when restyle
+                opacity: (settings.exportFormat == ExportFormat.db) ? 0.5 : 1, // TODO: centralize opacity when restyle
                 child: const IntervalPicker(),
               ),
               SettingsTile(
@@ -286,6 +286,11 @@ class ExportImportButtons extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
+    final settings = Provider.of<Settings>(context, listen: false);
+    final model = Provider.of<BloodPressureModel>(context, listen: false);
+    final messenger = ScaffoldMessenger.of(context);
+    final localizations = AppLocalizations.of(context)!;
+
     return Container(
       height: 60,
       color: Theme.of(context).colorScheme.onInverseSurface,
@@ -297,7 +302,7 @@ class ExportImportButtons extends StatelessWidget {
                 child: MaterialButton(
                   height: 60,
                   child:  Text(AppLocalizations.of(context)!.export),
-                  onPressed: () => Exporter(context).export(),
+                  onPressed: () => Exporter(settings, model, messenger, localizations).export(),
                 )
             ),
             const VerticalDivider(),
@@ -306,7 +311,7 @@ class ExportImportButtons extends StatelessWidget {
                 child: MaterialButton(
                   height: 60,
                   child: Text(AppLocalizations.of(context)!.import),
-                  onPressed: () => Exporter(context).import(),
+                  onPressed: () => Exporter(settings, model, messenger, localizations).import(),
                 )
             ),
           ],
lib/screens/add_measurement.dart
@@ -188,7 +188,7 @@ class _AddMeasurementPageState extends State<AddMeasurementPage> {
 
                                 await model.add(BloodPressureRecord(_time, _systolic, _diastolic, _pulse, _note));
                                 if (settings.exportAfterEveryEntry && context.mounted) {
-                                  final exporter = Exporter(context);
+                                  final exporter = Exporter(settings, model, ScaffoldMessenger.of(context), AppLocalizations.of(context)!);
                                   exporter.export();
                                 }
                                 navigator.pop();