Commit ff5cd32
Changed files (9)
lib
components
model
screens
test
model
export_import
lib/components/export_item_order.dart
@@ -3,7 +3,7 @@ import 'dart:async';
import 'package:badges/badges.dart' as badges;
import 'package:blood_pressure_app/components/consistent_future_builder.dart';
-import 'package:blood_pressure_app/model/export-import/export_column.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/export_options.dart';
import 'package:blood_pressure_app/model/storage/storage.dart';
import 'package:blood_pressure_app/screens/subsettings/export_column_data.dart';
lib/model/export-import/export_column.dart → lib/model/export_import/column.dart
@@ -20,7 +20,7 @@ class ExportColumn {
late final String columnTitle;
/// Pattern to create the field contents from:
- /// It supports inserting values for $TIMESTAMP, $SYS $DIA $PUL and $NOTE. Where $TIMESTAMP is the time since unix epoch in milliseconds.
+ /// It supports inserting values for $TIMESTAMP, $SYS $DIA $PUL, $COLOR and $NOTE. Where $TIMESTAMP is the time since unix epoch in milliseconds.
/// To format a timestamp in the same format as the $TIMESTAMP variable, $FORMAT(<timestamp>, <formatString>).
/// It is supported to use basic mathematics inside of double brackets ("{{}}"). In case one of them is not present in the record, -1 is provided.
/// The following math is supported:
@@ -41,13 +41,14 @@ class ExportColumn {
/// doesn't show up as unused / hidden field in list
final bool hidden;
- ExportColumn.fromJson(Map<String, dynamic> json, [this.editable = true, this.hidden = false]) {
+ factory ExportColumn.fromJson(Map<String, dynamic> json, [editable = true, hidden = false]) =>
ExportColumn(
internalName: json['internalColumnName'],
columnTitle: json['columnTitle'],
formatPattern: json['formatPattern'],
+ editable: editable,
+ hidden: hidden
);
- }
Map<String, dynamic> toJson() => {
'internalColumnName': internalName,
@@ -131,8 +132,8 @@ class ExportColumn {
/// Checks if the pattern can be used to parse records. This is the case when the pattern contains variables without
/// containing curly brackets or commas.
bool get isReversible {
- return (formatPattern == r'$TIMESTAMP') || (formatPattern == r'$COLOR') ||
- formatPattern.contains(RegExp(r'\$(SYS|DIA|PUL|NOTE)')) && !formatPattern.contains(RegExp(r'[{},]'));
+ final match = RegExp(r'([^{},$]*(\$SYS|\$DIA|\$PUL|\$NOTE)[^{},$]*)|\$TIMESTAMP|\$COLOR').firstMatch(formatPattern);
+ return (match != null) && (match.start == 0) && (match.end == formatPattern.length);
}
RowDataFieldType? get parsableFormat {
lib/model/storage/db/config_dao.dart
@@ -1,4 +1,4 @@
-import 'package:blood_pressure_app/model/export-import/export_column.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/storage/db/config_db.dart';
import 'package:blood_pressure_app/model/storage/export_csv_settings_store.dart';
import 'package:blood_pressure_app/model/storage/export_pdf_settings_store.dart';
lib/model/export_import.dart
@@ -5,7 +5,7 @@ import 'dart:typed_data';
import 'package:blood_pressure_app/model/blood_pressure.dart';
import 'package:blood_pressure_app/model/blood_pressure_analyzer.dart';
-import 'package:blood_pressure_app/model/export-import/export_column.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/export_options.dart';
import 'package:blood_pressure_app/model/storage/export_csv_settings_store.dart';
import 'package:blood_pressure_app/model/storage/export_pdf_settings_store.dart';
lib/model/export_options.dart
@@ -2,7 +2,7 @@ import 'dart:collection';
import 'package:blood_pressure_app/main.dart';
import 'package:blood_pressure_app/model/blood_pressure.dart';
-import 'package:blood_pressure_app/model/export-import/export_column.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/storage/common_settings_interfaces.dart';
import 'package:blood_pressure_app/model/storage/db/config_dao.dart';
import 'package:blood_pressure_app/model/storage/export_settings_store.dart';
lib/screens/subsettings/export_column_data.dart
@@ -1,6 +1,6 @@
import 'package:blood_pressure_app/components/consistent_future_builder.dart';
import 'package:blood_pressure_app/model/blood_pressure.dart';
-import 'package:blood_pressure_app/model/export-import/export_column.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/export_options.dart';
import 'package:blood_pressure_app/screens/subsettings/export_field_format_documentation.dart';
import 'package:flutter/material.dart';
lib/screens/subsettings/export_import_screen.dart
@@ -4,8 +4,8 @@ import 'package:blood_pressure_app/components/display_interval_picker.dart';
import 'package:blood_pressure_app/components/export_item_order.dart';
import 'package:blood_pressure_app/components/settings/settings_widgets.dart';
import 'package:blood_pressure_app/model/blood_pressure.dart';
-import 'package:blood_pressure_app/model/export-import/export_column.dart';
import 'package:blood_pressure_app/model/export_import.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/export_options.dart';
import 'package:blood_pressure_app/model/storage/storage.dart';
import 'package:flutter/material.dart';
test/model/export_import/column_test.dart
@@ -0,0 +1,79 @@
+
+import 'package:blood_pressure_app/model/blood_pressure.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:intl/intl.dart';
+
+void main() {
+ group('ExportColumn', () {
+ test('should not throw errors', () async {
+ final c = ExportColumn(
+ internalName: 'testColumn',
+ columnTitle: 'Test',
+ formatPattern: r'$SYS'
+ );
+
+ expect(c.internalName, 'testColumn');
+ expect(c.columnTitle, 'Test');
+ expect(c.formatPattern, r'$SYS');
+ c.formatRecord(BloodPressureRecord(DateTime.now(), 123, 45, 67, 'notes'));
+ c.formatRecord(BloodPressureRecord(DateTime.now(), null, null, null, ''));
+ c.parseRecord('122');
+ });
+ test('should not change during json conversion', () {
+ final original = ExportColumn(
+ internalName: 'testColumn',
+ columnTitle: 'Test',
+ formatPattern: r'{{$SYS-$DIA}}',
+ );
+ final fromJson = ExportColumn.fromJson(original.toJson());
+ expect(original.internalName, fromJson.internalName);
+ expect(original.columnTitle, fromJson.columnTitle);
+ expect(original.formatPattern, fromJson.formatPattern);
+ expect(original.isReversible, fromJson.isReversible);
+ expect(original.formatPattern, fromJson.formatPattern);
+ expect(original.toJson(), fromJson.toJson());
+ });
+ test('should create correct strings', () {
+ final testRecord = BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(31415926), 123, 45, 67, 'Test',
+ needlePin: const MeasurementNeedlePin(Colors.red));
+
+ expect(_testColumn(r'$SYS',).formatRecord(testRecord), testRecord.systolic.toString());
+ expect(_testColumn(r'$DIA',).formatRecord(testRecord), testRecord.diastolic.toString());
+ expect(_testColumn(r'$PUL',).formatRecord(testRecord), testRecord.pulse.toString());
+ expect(_testColumn(r'$COLOR',).formatRecord(testRecord), testRecord.needlePin!.color.value.toString());
+ expect(_testColumn(r'$NOTE',).formatRecord(testRecord), testRecord.notes);
+ expect(_testColumn(r'$TIMESTAMP',).formatRecord(testRecord), testRecord.creationTime.millisecondsSinceEpoch.toString());
+ expect(_testColumn(r'{{$SYS-$DIA}}',).formatRecord(testRecord),
+ (testRecord.systolic! - testRecord.diastolic!).toDouble().toString());
+ expect(_testColumn(r'{{$SYS*$DIA-$PUL}}',).formatRecord(testRecord),
+ (testRecord.systolic! * testRecord.diastolic! - testRecord.pulse!).toDouble().toString());
+ expect(_testColumn(r'$SYS-$DIA',).formatRecord(testRecord), ('${testRecord.systolic}-${testRecord.diastolic}'));
+
+ final formatter = DateFormat.yMMMMEEEEd();
+ expect(_testColumn('\$FORMAT{\$TIMESTAMP,${formatter.pattern}}',).formatRecord(testRecord),
+ formatter.format(testRecord.creationTime));
+ });
+ test('should report correct reversibility', () {
+ expect(_testColumn(r'$SYS',).isReversible, true);
+ expect(_testColumn(r'$DIA',).isReversible, true);
+ expect(_testColumn(r'$PUL',).isReversible, true);
+ expect(_testColumn(r'$TIMESTAMP',).isReversible, true);
+ expect(_testColumn(r'$NOTE',).isReversible, true);
+ expect(_testColumn(r'$COLOR',).isReversible, true);
+ expect(_testColumn(r'test$NOTE',).isReversible, true);
+ expect(_testColumn(r'test$NOTE123',).isReversible, true);
+ expect(_testColumn(r'test$SYS123',).isReversible, true);
+ expect(_testColumn(r'test$DIA123',).isReversible, true);
+ expect(_testColumn(r'test$PUL123',).isReversible, true);
+
+ expect(_testColumn(r'$PUL$SYS',).isReversible, false);
+ expect(_testColumn(r'{{$PUL-$SYS}}',).isReversible, false);
+ });
+ // TODO: test parsing
+ });
+}
+
+ExportColumn _testColumn(String formatPattern) =>
+ ExportColumn(internalName: '', columnTitle: '', formatPattern: formatPattern,);
\ No newline at end of file