main
1import 'dart:convert';
2import 'dart:io';
3
4import 'package:archive/archive_io.dart';
5import 'package:blood_pressure_app/model/storage/db/settings_loader.dart';
6import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
7import 'package:blood_pressure_app/model/storage/export_csv_settings_store.dart';
8import 'package:blood_pressure_app/model/storage/export_pdf_settings_store.dart';
9import 'package:blood_pressure_app/model/storage/export_settings_store.dart';
10import 'package:blood_pressure_app/model/storage/export_xsl_settings_store.dart';
11import 'package:blood_pressure_app/model/storage/interval_store.dart';
12import 'package:blood_pressure_app/model/storage/settings_store.dart';
13import 'package:flutter/widgets.dart';
14import 'package:path/path.dart';
15import 'package:sqflite/sqflite.dart';
16
17/// Store settings in a directory format on disk.
18class FileSettingsLoader implements SettingsLoader {
19 FileSettingsLoader._create(this._path);
20
21 /// Creates setting loader from relative directory [path] or the default
22 /// settings path.
23 static Future<FileSettingsLoader> load([String? path]) async {
24 path ??= join(await getDatabasesPath(), 'settings');
25 Directory(path).createSync(recursive: true);
26 return FileSettingsLoader._create(path);
27 }
28
29 final String _path;
30
31 /// Instantiates a settings file relative to [_path] and writes changes.
32 ///
33 /// If the is read successfully [build] is called else [createNew] is called.
34 T _loadFile<T extends ChangeNotifier>(
35 String fileName,
36 T Function(String) build,
37 T Function() createNew,
38 String Function(T) serialize,
39 ) {
40 final f = File(join(_path, fileName));
41 T? obj;
42 try {
43 obj = build(f.readAsStringSync());
44 } on FileSystemException {}
45 obj ??= createNew();
46
47 obj.addListener(() => f.writeAsStringSync(serialize(obj!)));
48 f.writeAsStringSync(serialize(obj));
49 return obj;
50 }
51
52 @override
53 Future<CsvExportSettings> loadCsvExportSettings() async => _loadFile(
54 'csv-export',
55 CsvExportSettings.fromJson,
56 CsvExportSettings.new,
57 (e) => e.toJson(),
58 );
59
60 @override
61 Future<ExportColumnsManager> loadExportColumnsManager() async => _loadFile(
62 'export-columns',
63 ExportColumnsManager.fromJson,
64 ExportColumnsManager.new,
65 (e) => e.toJson(),
66 );
67
68 @override
69 Future<ExportSettings> loadExportSettings() async => _loadFile(
70 'export',
71 ExportSettings.fromJson,
72 ExportSettings.new,
73 (e) => e.toJson(),
74 );
75
76 @override
77 Future<IntervalStoreManager> loadIntervalStorageManager() async => _loadFile(
78 'intervall-store',
79 (String jsonStr) {
80 final json = jsonDecode(jsonStr);
81 if (json is Map<String, dynamic>) {
82 return IntervalStoreManager(
83 json['main'] is! String ? IntervalStorage() : IntervalStorage.fromJson(json['main']!),
84 json['export'] is! String ? IntervalStorage() : IntervalStorage.fromJson(json['export']!),
85 json['stats'] is! String ? IntervalStorage() : IntervalStorage.fromJson(json['stats']!),
86 );
87 }
88 return IntervalStoreManager(IntervalStorage(), IntervalStorage(), IntervalStorage());
89 },
90 () => IntervalStoreManager(IntervalStorage(), IntervalStorage(), IntervalStorage()),
91 (e) => jsonEncode({
92 'main': e.mainPage.toJson(),
93 'export': e.exportPage.toJson(),
94 'stats': e.statsPage.toJson(),
95 }),
96 );
97
98 @override
99 Future<PdfExportSettings> loadPdfExportSettings() async => _loadFile(
100 'pdf-export',
101 PdfExportSettings.fromJson,
102 PdfExportSettings.new,
103 (e) => e.toJson(),
104 );
105
106 @override
107 Future<ExcelExportSettings> loadXslExportSettings() async => _loadFile(
108 'xsl-export',
109 ExcelExportSettings.fromJson,
110 ExcelExportSettings.new,
111 (e) => e.toJson(),
112 );
113
114 @override
115 Future<Settings> loadSettings() async => _loadFile(
116 'general',
117 Settings.fromJson,
118 Settings.new,
119 (e) => e.toJson(),
120 );
121
122 /// Attempt to backup all stored data to archive.
123 Archive? createArchive() {
124 try {
125 final archive = Archive();
126 _backupFile(archive, 'general');
127 _backupFile(archive, 'export');
128 _backupFile(archive, 'csv-export');
129 _backupFile(archive, 'pdf-export');
130 _backupFile(archive, 'export-columns');
131 _backupFile(archive, 'intervall-store');
132 return archive;
133 } on FileSystemException {
134 return null;
135 }
136 }
137
138 void _backupFile(Archive archive, String fileName) {
139 final data = File(join(_path, fileName)).readAsStringSync();
140 archive.addFile(ArchiveFile.string(fileName, data));
141 }
142}