main
1import 'dart:convert';
2
3import 'package:blood_pressure_app/features/export_import/import_preview_dialoge.dart';
4import 'package:blood_pressure_app/l10n/app_localizations.dart';
5import 'package:blood_pressure_app/model/export_import/csv_converter.dart';
6import 'package:blood_pressure_app/model/export_import/csv_record_parsing_actor.dart';
7import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
8import 'package:blood_pressure_app/model/storage/storage.dart';
9import 'package:file_picker/file_picker.dart';
10import 'package:flutter/material.dart';
11import 'package:flutter_bloc/flutter_bloc.dart';
12import 'package:health_data_store/health_data_store.dart';
13import 'package:provider/provider.dart';
14import 'package:sqflite/sqflite.dart';
15
16/// Text button to import entries like configured in the context.
17class ImportButton extends StatelessWidget {
18 /// Create text button to import entries like configured in the context.
19 const ImportButton({super.key});
20
21 @override
22 Widget build(BuildContext context) => TextButton.icon(
23 label: Text(AppLocalizations.of(context)!.import),
24 icon: Icon(Icons.file_upload_outlined),
25 onPressed: () async {
26 final localizations = AppLocalizations.of(context)!;
27 final messenger = ScaffoldMessenger.of(context);
28
29 final file = (await FilePicker.platform.pickFiles(
30 withData: true,
31 ))?.files.firstOrNull;
32 if (file == null) {
33 messenger.showSnackBar(SnackBar(content: Text(localizations.errNoFileOpened)));
34 return;
35 }
36 if (!context.mounted) return;
37 switch(file.extension?.toLowerCase()) {
38 case 'csv':
39 final binaryContent = file.bytes;
40 if (binaryContent == null) {
41 messenger.showSnackBar(SnackBar(content: Text(localizations.errCantReadFile)));
42 return;
43 }
44 if (!context.mounted) return;
45 final csvSettings = Provider.of<CsvExportSettings>(context, listen: false);
46 final exportColumnsManager = Provider.of<ExportColumnsManager>(context, listen: false);
47 final converter = CsvConverter(
48 csvSettings,
49 exportColumnsManager,
50 await RepositoryProvider.of<MedicineRepository>(context).getAll(),
51 );
52 if (!context.mounted) return;
53 final importedRecords = await showImportPreview(
54 context,
55 CsvRecordParsingActor(
56 converter,
57 utf8.decode(binaryContent),
58 ),
59 exportColumnsManager,
60 Provider.of<Settings>(context, listen: false).bottomAppBars,
61 );
62 if (importedRecords == null || !context.mounted) return;
63 final bpRepo = RepositoryProvider.of<BloodPressureRepository>(context);
64 final noteRepo = RepositoryProvider.of<NoteRepository>(context);
65 final intakeRepo = RepositoryProvider.of<MedicineIntakeRepository>(context);
66 await Future.forEach<FullEntry>(importedRecords, (e) async {
67 if (e.sys != null || e.dia != null || e.pul != null) {
68 await bpRepo.add(e.$1);
69 }
70 if (e.note != null || e.color != null) {
71 await noteRepo.add(e.$2);
72 }
73 if (e.$3.isNotEmpty) {
74 await Future.forEach(e.$3, intakeRepo.add);
75 }
76 });
77 messenger.showSnackBar(SnackBar(content: Text(localizations.importSuccess(importedRecords.length))));
78 break;
79 case 'db':
80 if (file.path == null) return;
81 final bpRepo = RepositoryProvider.of<BloodPressureRepository>(context);
82 final noteRepo = RepositoryProvider.of<NoteRepository>(context);
83 final intakeRepo = RepositoryProvider.of<MedicineIntakeRepository>(context);
84
85 final List<BloodPressureRecord> records = [];
86 final List<Note> notes = [];
87 final List<MedicineIntake> intakes = [];
88 try {
89 final db = await openReadOnlyDatabase(file.path!);
90 final importedDB = await HealthDataStore.load(db, true);
91 records.addAll(await importedDB.bpRepo.get(DateRange.all()));
92 notes.addAll(await importedDB.noteRepo.get(DateRange.all()));
93 intakes.addAll(await importedDB.intakeRepo.get(DateRange.all()));
94 await db.close();
95 } catch (e) {
96 // DB doesn't conform new format
97 }
98
99
100 await Future.forEach(records, bpRepo.add);
101 await Future.forEach(notes, noteRepo.add);
102 await Future.forEach(intakes, intakeRepo.add);
103
104 messenger.showSnackBar(SnackBar(content: Text(localizations.importSuccess(records.length))));
105 break;
106 default:
107 messenger.showSnackBar(SnackBar(content: Text(localizations.errWrongImportFormat)));
108 }
109 },
110 );
111}