main
1import 'dart:convert';
2
3import 'package:blood_pressure_app/model/export_import/column.dart';
4import 'package:blood_pressure_app/model/storage/convert_util.dart';
5import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
6import 'package:collection/collection.dart';
7import 'package:flutter/widgets.dart';
8import 'package:blood_pressure_app/l10n/app_localizations.dart';
9
10/// Class for managing columns currently used for ex- and import.
11class ActiveExportColumnConfiguration extends ChangeNotifier {
12 /// Create a manager of the currently relevant [ExportColumn]s.
13 ///
14 /// The default configuration is guaranteed to be restoreable.
15 ActiveExportColumnConfiguration({
16 ExportImportPreset? activePreset,
17 List<String>? userSelectedColumnIds,
18 }) :
19 _activePreset = activePreset ?? ExportImportPreset.bloodPressureApp,
20 _userSelectedColumns = userSelectedColumnIds ?? [];
21
22 /// Create a instance from a [String] created by [toJson].
23 factory ActiveExportColumnConfiguration.fromJson(String jsonString) {
24 try {
25 final json = jsonDecode(jsonString);
26 return ActiveExportColumnConfiguration(
27 activePreset: ExportImportPreset.decode(json['preset']) ?? ExportImportPreset.bloodPressureApp,
28 userSelectedColumnIds: ConvertUtil.parseList<String>(json['columns']),
29 );
30 } on FormatException {
31 return ActiveExportColumnConfiguration();
32 }
33
34 }
35
36 /// Serialize the object to a restoreable string.
37 String toJson() => jsonEncode({
38 'columns': _userSelectedColumns,
39 'preset': _activePreset.encode(),
40 });
41
42 /// The [UserColumn.internalIdentifier] of columns currently selected by user.
43 ///
44 /// Note that this is persistent different from [getActiveColumns].
45 final List<String> _userSelectedColumns;
46
47 ExportImportPreset _activePreset;
48
49 /// The current selection on what set of values will be exported.
50 ExportImportPreset get activePreset => _activePreset;
51
52 set activePreset(ExportImportPreset value) {
53 _activePreset = value;
54 notifyListeners();
55 }
56
57 /// Put the user column at [oldIndex] to [newIndex].
58 void reorderUserColumns(int oldIndex, int newIndex) {
59 assert(_activePreset == ExportImportPreset.none, 'user columns are not modifiable while another configuration is active');
60 assert(oldIndex >= 0 && oldIndex < _userSelectedColumns.length);
61 assert(newIndex >= 0 && newIndex < _userSelectedColumns.length);
62 if (oldIndex < newIndex) {
63 newIndex -= 1;
64 }
65 final item = _userSelectedColumns.removeAt(oldIndex);
66 _userSelectedColumns.insert(newIndex, item);
67 notifyListeners();
68 }
69
70 /// Add a export column to the end of user columns.
71 void addUserColumn(ExportColumn column) {
72 assert(_activePreset == ExportImportPreset.none, 'user columns are not modifiable while another configuration is active');
73 _userSelectedColumns.add(column.internalIdentifier);
74 notifyListeners();
75 }
76
77 /// Removes the first export column from user columns where
78 /// [ExportColumn.internalIdentifier] matches [identifier].
79 void removeUserColumn(String identifier) {
80 assert(_activePreset == ExportImportPreset.none, 'user columns are not modifiable while another configuration is active');
81 _userSelectedColumns.removeWhere((c) => c == identifier);
82 notifyListeners();
83 }
84
85 /// Columns to respect for export.
86 UnmodifiableListView<ExportColumn> getActiveColumns(ExportColumnsManager availableColumns) => UnmodifiableListView(
87 switch (_activePreset) {
88 ExportImportPreset.none => _userSelectedColumns.map((e) => availableColumns.getColumn(e)).whereNotNull(),
89 ExportImportPreset.bloodPressureApp => [
90 NativeColumn.timestampUnixMs,
91 NativeColumn.systolic,
92 NativeColumn.diastolic,
93 NativeColumn.pulse,
94 NativeColumn.notes,
95 NativeColumn.color,
96 NativeColumn.intakes,
97 NativeColumn.bodyweight,
98 ],
99 ExportImportPreset.myHeart => [
100 BuildInColumn.mhDate,
101 BuildInColumn.mhSys,
102 BuildInColumn.mhDia,
103 BuildInColumn.mhPul,
104 BuildInColumn.mhDesc,
105 BuildInColumn.mhTags,
106 BuildInColumn.mhWeight,
107 BuildInColumn.mhOxygen,
108 ],
109 ExportImportPreset.bloodPressureAppPdf => [
110 BuildInColumn.formattedTime,
111 NativeColumn.systolic,
112 NativeColumn.diastolic,
113 NativeColumn.pulse,
114 ]
115 },);
116}
117
118
119/// Common export configurations that have specific associated columns.
120enum ExportImportPreset {
121 /// Custom export configuration.
122 none,
123
124 /// Default preset, that ensures working exports and restoration.
125 ///
126 /// All [NativeColumn]s.
127 bloodPressureApp,
128
129 /// Default preset for pdf exports.
130 ///
131 /// Includes formatted time, sys, dia and pulse.
132 bloodPressureAppPdf,
133
134 /// Preset for exporting data to the myHeart app.
135 myHeart;
136
137 /// Selection of a displayable string from [localizations].
138 String localize(AppLocalizations localizations) => switch (this) {
139 ExportImportPreset.none => localizations.custom,
140 ExportImportPreset.bloodPressureApp => localizations.default_,
141 ExportImportPreset.bloodPressureAppPdf => localizations.pdf,
142 ExportImportPreset.myHeart => '"My Heart" export'
143 };
144
145 /// Turn the value into a [decode]able integer for serialization purposes.
146 int encode() => switch (this) {
147 ExportImportPreset.none => 0,
148 ExportImportPreset.bloodPressureApp => 1,
149 ExportImportPreset.myHeart => 2,
150 ExportImportPreset.bloodPressureAppPdf => 3,
151 };
152
153 /// Create a enum value form a number returned by [encode].
154 static ExportImportPreset? decode(Object? e) => switch(e) {
155 0 => ExportImportPreset.none,
156 1 => ExportImportPreset.bloodPressureApp,
157 2 => ExportImportPreset.myHeart,
158 3 => ExportImportPreset.bloodPressureAppPdf,
159 _ => (){
160 assert(e is! int, 'non ints can happen through bad user values, other ints can happen as well, but should developers should be notified.');
161 return null;
162 }(),
163 };
164}