Commit a7e1470
Changed files (19)
app
lib
features
export_import
model
screens
test
app/lib/model/blood_pressure/medicine/intake_history.dart
@@ -1,117 +0,0 @@
-import 'package:blood_pressure_app/logging.dart';
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine.dart';
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine_intake.dart';
-import 'package:collection/collection.dart';
-import 'package:flutter/material.dart';
-
-/// Model of all medicine intakes that allows fast access of data.
-///
-/// Internally maintains a sorted list of intakes to allow for binary search.
-///
-/// Intake history does not implement database support, as operations performed
-/// are
-@Deprecated('use health_data_store')
-class IntakeHistory extends ChangeNotifier {
- /// Create a intake history from an unsorted list of intakes.
- IntakeHistory(List<OldMedicineIntake> medicineIntakes):
- _medicineIntakes = medicineIntakes.sorted((p0, p1) => p0.compareTo(p1));
-
- /// Creates a intake history from a sorted list of intakes.
- IntakeHistory._sorted(this._medicineIntakes);
-
- /// Restores a intake history from a [serialize] generated string.
- factory IntakeHistory.deserialize(String serialized, List<Medicine> availableMedicines) =>
- IntakeHistory._sorted(
- serialized
- .split('\n')
- .map((e) {
- try {
- return OldMedicineIntake.deserialize(e, availableMedicines);
- } on FormatException {
- log.severe('OldMedicineIntake deserialization problem: "$e"');
- return null;
- }
- })
- .whereNotNull()
- .toList(),
- );
-
- /// List of all medicine intakes sorted in ascending order.
- ///
- /// Can contain multiple medicine intakes at the same time.
- final List<OldMedicineIntake> _medicineIntakes;
-
- /// Returns all intakes in a given range in ascending order.
- ///
- /// Binary searches the lower and the upper bound of stored intakes to create
- /// the list view.
- UnmodifiableListView<OldMedicineIntake> getIntakes(DateTimeRange range) {
- if (_medicineIntakes.isEmpty) return UnmodifiableListView([]);
- int start = _findLowerBound(_medicineIntakes, range.start);
- int end = _findUpperBound(_medicineIntakes, range.end);
-
- if (start < 0) start = 0;
- assert(end < _medicineIntakes.length);
- if (end < 0) end = _medicineIntakes.length;
-
- return UnmodifiableListView(_medicineIntakes.getRange(start, end));
- }
-
- /// Use binary search to determine the first index in [list] before which all
- /// values that are before or at the same time as [t].
- int _findUpperBound(List<OldMedicineIntake> list, DateTime t) {
- int low = 0;
- int high = list.length - 1;
-
- int idx = -1;
- while (low <= high) {
- final int mid = low + ((high - low) >> 1);
- assert (mid == (low + (high - low) / 2).toInt());
-
- if (list[mid].timestamp.isBefore(t) || list[mid].timestamp.isAtSameMomentAs(t)) {
- low = mid + 1;
- } else {
- idx = mid;
- high = mid - 1;
- }
- }
-
- return idx;
- }
-
- /// Use binary search to determine the last index in [list] after which before
- /// all values that are after or at the same time as [t].
- int _findLowerBound(List<OldMedicineIntake> list, DateTime t) {
- int low = 0;
- int high = list.length - 1;
-
- int idx = -1;
- while (low <= high) {
- final int mid = low + ((high - low) >> 1);
- assert (mid == (low + (high - low) / 2).toInt());
-
- if (list[mid].timestamp.isAfter(t) || list[mid].timestamp.isAtSameMomentAs(t) ){
- high = mid - 1;
- } else {
- idx = mid;
- low = mid + 1;
- }
- }
-
- return idx + 1;
- }
-
- @override
- bool operator ==(Object other) =>
- identical(this, other) ||
- other is IntakeHistory && runtimeType == other.runtimeType &&
- (){
- for (final e in _medicineIntakes) {
- if (!other._medicineIntakes.contains(e)) return false;
- }
- return true;
- }();
-
- @override
- int get hashCode => _medicineIntakes.hashCode;
-}
app/lib/model/blood_pressure/medicine/medicine.dart
@@ -1,66 +0,0 @@
-import 'dart:convert';
-import 'dart:ui';
-
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine_intake.dart';
-import 'package:flutter/material.dart';
-
-/// Description of a specific medicine.
-@Deprecated('use health_data_store')
-class Medicine {
- /// Create a instance from a map created by [toMap].
- factory Medicine.fromMap(Map<String, dynamic> map) => Medicine(
- map['id'],
- designation: map['designation'],
- color: Color(map['color']),
- defaultDosis: map['defaultDosis'],
- hidden: map.containsKey('hidden') ? map['hidden'] : false,
- );
-
- /// Create a instance from a [String] created by [toJson].
- factory Medicine.fromJson(String json) => Medicine.fromMap(jsonDecode(json));
-
- /// Create a new medicine.
- Medicine(this.id, {
- required this.designation,
- required this.color,
- required this.defaultDosis,
- this.hidden = false,
- });
-
- /// Unique id used to store the medicine in serialized objects.
- final int id;
-
- /// Name of the medicine.
- final String designation;
-
- /// Color used to display medicine intake
- final Color color;
-
- /// Default dosis used to autofill [OldMedicineIntake].
- final double? defaultDosis;
-
- /// Indicates that this medicine should not be shown in selection menus.
- ///
- /// This is usually set when the user deletes the medicine in order to avoid
- /// data inconsistencies with existing intakes that use this medicine.
- bool hidden;
-
- @override
- bool operator ==(Object other) =>
- identical(this, other) ||
- other is Medicine &&
- runtimeType == other.runtimeType &&
- id == other.id &&
- designation == other.designation &&
- color.toARGB32() == other.color.toARGB32() &&
- defaultDosis == other.defaultDosis &&
- hidden == other.hidden;
-
- @override
- int get hashCode => id.hashCode ^ designation.hashCode ^ color.hashCode
- ^ defaultDosis.hashCode ^ hidden.hashCode;
-
- @override
- String toString() => 'Medicine{id: $id, designation: $designation, '
- 'color: $color, defaultDosis: $defaultDosis, hidden: $hidden}';
-}
app/lib/model/blood_pressure/medicine/medicine_intake.dart
@@ -1,82 +0,0 @@
-
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine.dart';
-import 'package:flutter/foundation.dart';
-import 'package:flutter/material.dart';
-
-/// Instance of a medicine intake.
-@Deprecated('use health_data_store')
-class OldMedicineIntake implements Comparable<Object> {
- /// Create a intake from a String created by [serialize].
- ///
- /// [availableMeds] must contain the
- factory OldMedicineIntake.deserialize(
- String string,
- List<Medicine> availableMeds,
- ) {
- final elements = string.split('\x00');
- final storedMedicine = availableMeds
- .where((e) => e.id == int.parse(elements[0]));
- if (kDebugMode && storedMedicine.isEmpty) {
- throw ArgumentError('Medicine of intake $string not found.');
- }
- return OldMedicineIntake(
- medicine: storedMedicine.firstOrNull ?? Medicine(
- int.parse(elements[0]),
- designation: 'DELETED MEDICINE',
- color: Colors.red,
- defaultDosis: null,
- ),
- timestamp: DateTime.fromMillisecondsSinceEpoch(int.parse(elements[1])),
- dosis: double.parse(elements[2]),
- );
- }
-
- /// Create a instance of a medicine intake.
- const OldMedicineIntake({
- required this.medicine,
- required this.dosis,
- required this.timestamp,
- });
-
- /// Serialize the object to a deserializable string.
- ///
- /// The string consists of the id of the medicine, the unix timestamp and the
- /// dosis. These values are seperated by a null byte
- /*String serialize() =>
- '${medicine.id}\x00${timestamp.millisecondsSinceEpoch}\x00$dosis';*/
-
- /// Kind of medicine taken.
- final Medicine medicine;
-
- /// Amount in mg of medicine taken.
- final double dosis;
-
- /// Time when the medicine was taken.
- final DateTime timestamp;
-
- @override
- bool operator ==(Object other) =>
- identical(this, other) ||
- other is OldMedicineIntake &&
- runtimeType == other.runtimeType &&
- medicine == other.medicine &&
- dosis == other.dosis &&
- timestamp == other.timestamp;
-
- @override
- int get hashCode => medicine.hashCode ^ dosis.hashCode ^ timestamp.hashCode;
-
- @override
- int compareTo(Object other) {
- assert(other is OldMedicineIntake);
- if (other is! OldMedicineIntake) return 0;
-
- final timeCompare = timestamp.compareTo(other.timestamp);
- if (timeCompare != 0) return timeCompare;
-
- return dosis.compareTo(other.dosis);
- }
-
- @override
- String toString() => 'MedicineIntake{medicine: $medicine, dosis: $dosis, timestamp: $timestamp}';
-}
app/lib/model/blood_pressure/model.dart
@@ -1,89 +0,0 @@
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-
-import 'package:blood_pressure_app/model/blood_pressure/needle_pin.dart';
-import 'package:blood_pressure_app/model/blood_pressure/record.dart';
-import 'package:blood_pressure_app/screens/error_reporting_screen.dart';
-import 'package:collection/collection.dart';
-import 'package:flutter/material.dart';
-import 'package:path/path.dart';
-import 'package:sqflite/sqflite.dart';
-
-/// Model to access values in the measurement database.
-@Deprecated('use health_data_store')
-class BloodPressureModel extends ChangeNotifier {
-
- BloodPressureModel._create();
-
- late final Database _database;
-
- FutureOr<void> _onDBUpgrade(Database db, int oldVersion, int newVersion) async {
- // When adding more versions the upgrade procedure proposed in https://stackoverflow.com/a/75153875/21489239
- // might be useful, to avoid duplicated code. Currently this would only lead to complexity, without benefits.
- if (oldVersion == 1 && newVersion == 2) {
- await db.execute('ALTER TABLE bloodPressureModel ADD COLUMN needlePin STRING;');
- await db.database.setVersion(2);
- } else {
- await ErrorReporting.reportCriticalError('Unsupported database upgrade', 'Attempted to upgrade the measurement database from version $oldVersion to version $newVersion, which is not supported. This action failed to avoid data loss. Please contact the app developer by opening an issue with the link below or writing an email to contact@derdilla.com.');
- }
- }
-
- /// Construct a instance of [BloodPressureModel] if a db file still exists.
- static Future<BloodPressureModel?> create({String? dbPath, bool isFullPath = false}) async {
- final component = BloodPressureModel._create();
- dbPath ??= await getDatabasesPath();
-
- if (dbPath != inMemoryDatabasePath && !isFullPath) {
- dbPath = join(dbPath, 'blood_pressure.db');
- }
- if (!File(dbPath).existsSync()) return null;
- component._database = await openDatabase(
- dbPath,
- onUpgrade: component._onDBUpgrade,
- // In integration tests the file may be deleted which causes deadlocks.
- singleInstance: false,
- version: 2,
- );
- return component;
- }
-
- /// Returns all recordings in saved in a range in ascending order
- Future<UnmodifiableListView<OldBloodPressureRecord>> getInTimeRange(DateTime from, DateTime to) async {
- if (!_database.isOpen) return UnmodifiableListView([]);
- final dbEntries = await _database.query('bloodPressureModel',
- orderBy: 'timestamp DESC',
- where: 'timestamp BETWEEN ? AND ?',
- whereArgs: [from.millisecondsSinceEpoch, to.millisecondsSinceEpoch],); // descending
- final List<OldBloodPressureRecord> recordsInRange = _convert(dbEntries);
- return UnmodifiableListView(recordsInRange);
- }
-
- /// Querries all measurements saved in the database.
- Future<UnmodifiableListView<OldBloodPressureRecord>> get all async {
- if (!_database.isOpen) return UnmodifiableListView([]);
- return UnmodifiableListView(_convert(await _database.query('bloodPressureModel', columns: ['*'])));
- }
-
- /// Close the database.
- ///
- /// Cannot be accessed anymore.
- Future<void> close() => _database.close();
-
- List<OldBloodPressureRecord> _convert(List<Map<String, Object?>> dbResult) {
- final List<OldBloodPressureRecord> records = [];
- for (final e in dbResult) {
- final needlePinJson = e['needlePin'] as String?;
- final needlePin = (needlePinJson != null) ? jsonDecode(needlePinJson) : null;
- records.add(OldBloodPressureRecord(
- DateTime.fromMillisecondsSinceEpoch(e['timestamp'] as int),
- e['systolic'] as int?,
- e['diastolic'] as int?,
- e['pulse'] as int?,
- e['notes'].toString(),
- needlePin: (needlePin != null) ? MeasurementNeedlePin.fromMap(needlePin) : null,
- ),);
- }
- return records;
- }
-}
app/lib/model/blood_pressure/needle_pin.dart
@@ -1,16 +0,0 @@
-import 'package:blood_pressure_app/model/blood_pressure/record.dart';
-import 'package:flutter/material.dart';
-
-@immutable
-@Deprecated('only maintained for imports, use health_data_store')
-/// Metadata and secondary information for a [OldBloodPressureRecord].
-class MeasurementNeedlePin {
- /// Create a instance from a map created in older versions.
- MeasurementNeedlePin.fromMap(Map<String, dynamic> json)
- : color = Color(json['color']);
- // When updating this, remember to be backwards compatible.
- // (or reimplement the system)
-
- /// The color associated with the measurement.
- final Color color;
-}
app/lib/model/blood_pressure/record.dart
@@ -1,57 +0,0 @@
-import 'package:blood_pressure_app/model/blood_pressure/needle_pin.dart';
-import 'package:flutter/material.dart';
-
-/// Immutable data representation of a saved measurement.
-@immutable
-@Deprecated('use health data store')
-class OldBloodPressureRecord {
- /// Create a measurement.
- OldBloodPressureRecord(DateTime creationTime, this.systolic, this.diastolic, this.pulse, this.notes, {
- this.needlePin,
- }) {
- if (creationTime.millisecondsSinceEpoch > 0) {
- this.creationTime = creationTime;
- } else {
- assert(false, 'Tried to create BloodPressureRecord at or before epoch');
- this.creationTime = DateTime.fromMillisecondsSinceEpoch(1);
- }
- }
-
- /// The time the measurement was created.
- late final DateTime creationTime;
-
- /// The stored sys value.
- final int? systolic;
-
- /// The stored dia value.
- final int? diastolic;
-
- /// The stored pul value.
- final int? pulse;
-
- /// Notes stored about this measurement.
- final String notes;
-
- /// Secondary information about the measurement.
- final MeasurementNeedlePin? needlePin;
-
- /// Creates a new record from this one by updating individual properties.
- OldBloodPressureRecord copyWith({
- DateTime? creationTime,
- int? systolic,
- int? diastolic,
- int? pulse,
- String? notes,
- MeasurementNeedlePin? needlePin,
- }) => OldBloodPressureRecord(
- creationTime ?? this.creationTime,
- systolic ?? this.systolic,
- diastolic ?? this.diastolic,
- pulse ?? this.pulse,
- notes ?? this.notes,
- needlePin: needlePin ?? this.needlePin,
- );
-
- @override
- String toString() => 'BloodPressureRecord($creationTime, $systolic, $diastolic, $pulse, $notes, $needlePin)';
-}
app/lib/model/blood_pressure/update_legacy_entries.dart
@@ -1,89 +0,0 @@
-import 'dart:io';
-
-import 'package:blood_pressure_app/model/blood_pressure/model.dart';
-import 'package:blood_pressure_app/model/blood_pressure/record.dart';
-import 'package:blood_pressure_app/model/storage/settings_store.dart';
-import 'package:flutter/material.dart';
-import 'package:health_data_store/health_data_store.dart' as hds;
-import 'package:path/path.dart';
-import 'package:sqflite/sqflite.dart';
-
-import '../../screens/error_reporting_screen.dart';
-import 'medicine/intake_history.dart';
-import 'medicine/medicine.dart';
-
-/// Loads data from old storage locations, adds them to new repos and deletes old storage location on success.
-@Deprecated('Only use to migrate legacy data')
-Future<void> updateLegacyEntries(
- Settings settings,
- hds.BloodPressureRepository bpRepo,
- hds.NoteRepository noteRepo,
- hds.MedicineRepository medRepo,
- hds.MedicineIntakeRepository intakeRepo,
-) async {
- // Migrate old meds still in use and old intakes
- try {
- if (settings.medications.isNotEmpty) {
- final intakeString = File(join(await getDatabasesPath(), 'medicine.intakes')).readAsStringSync();
- final intakeHistory = IntakeHistory.deserialize(intakeString, settings.medications);
- final addedMeds = <Medicine, hds.Medicine>{};
- for (final i in intakeHistory.getIntakes(DateTimeRange(
- start: DateTime.fromMillisecondsSinceEpoch(0),
- end: DateTime.now(),
- ))) {
- hds.Medicine? med = addedMeds[i.medicine];
- if (med == null) {
- med = hds.Medicine(
- designation: i.medicine.designation,
- color: i.medicine.color.toARGB32(),
- dosis: i.medicine.defaultDosis == null ? null : hds.Weight.mg(i.medicine.defaultDosis!),
- );
- addedMeds[i.medicine] = med;
- await medRepo.add(med);
- }
- final newI = hds.MedicineIntake(
- time: i.timestamp,
- medicine: med,
- dosis: hds.Weight.mg(i.dosis),
- );
- await intakeRepo.add(newI);
- }
- }
-
- File(join(await getDatabasesPath(), 'medicine.intakes')).deleteSync();
- } on PathNotFoundException {
- // pass
- } catch (e, stack) {
- await ErrorReporting.reportCriticalError('Error while migrating intakes to '
- 'new format', '$e\n$stack',);
- }
-
- // Migrating records and notes
- try {
- final oldBpModel = await BloodPressureModel.create();
- for (final OldBloodPressureRecord r in await oldBpModel?.all ?? []) {
- if (r.diastolic != null || r.systolic != null || r.pulse != null) {
- await bpRepo.add(hds.BloodPressureRecord(
- time: r.creationTime,
- sys: r.systolic == null ? null : hds.Pressure.mmHg(r.systolic!),
- dia: r.diastolic == null ? null : hds.Pressure.mmHg(r.diastolic!),
- pul: r.pulse,
- ));
- }
- if (r.notes.isNotEmpty || r.needlePin != null) {
- await noteRepo.add(hds.Note(
- time: r.creationTime,
- note: r.notes.isEmpty ? null : r.notes,
- color: r.needlePin?.color.toARGB32(),
- ));
- }
- }
- await oldBpModel?.close();
- File(join(await getDatabasesPath(), 'blood_pressure.db')).deleteSync();
- } on PathNotFoundException {
- // pass
- } catch (e, stack) {
- await ErrorReporting.reportCriticalError('Error while migrating records to '
- 'new format', '$e\n$stack',);
- }
-}
app/lib/model/export_import/import_field_type.dart
@@ -1,6 +1,5 @@
-import 'package:blood_pressure_app/model/blood_pressure/needle_pin.dart';
-import 'package:blood_pressure_app/model/export_import/record_formatter.dart';
import 'package:blood_pressure_app/l10n/app_localizations.dart';
+import 'package:blood_pressure_app/model/export_import/record_formatter.dart';
/// Type a [Formatter] can uses to indicate the kind of data returned.
enum RowDataFieldType {
@@ -15,8 +14,6 @@ enum RowDataFieldType {
/// Guarantees [String] is returned.
notes,
/// Guarantees that a [int] containing a [Color.toARGB32()] is returned.
- ///
- /// Backwards compatability with [MeasurementNeedlePin] json is maintained.
color,
/// Guarantees [List<(String medicineDesignation, double dosisMg)>] is returned.
intakes,
app/lib/model/export_import/record_formatter.dart
@@ -1,6 +1,3 @@
-import 'dart:convert';
-
-import 'package:blood_pressure_app/model/blood_pressure/needle_pin.dart';
import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/export_import/import_field_type.dart';
import 'package:function_tree/function_tree.dart';
@@ -51,11 +48,7 @@ class ScriptedFormatter implements Formatter {
}(),
RowDataFieldType.sys || RowDataFieldType.dia || RowDataFieldType.pul => int.tryParse(text),
RowDataFieldType.notes => text,
- RowDataFieldType.color => (){
- try {
- return int.tryParse(text) ?? MeasurementNeedlePin.fromMap(jsonDecode(text)).color.toARGB32();
- } on FormatException { return null; } on TypeError { return null; }
- }(),
+ RowDataFieldType.color => int.tryParse(text),
RowDataFieldType.intakes => NativeColumn.intakes.decode(text),
RowDataFieldType.weightKg => double.tryParse(text),
};
app/lib/model/storage/settings_store.dart
@@ -3,7 +3,6 @@ import 'dart:convert';
import 'package:blood_pressure_app/config.dart';
import 'package:blood_pressure_app/features/bluetooth/logic/device_scan_cubit.dart';
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine.dart';
import 'package:blood_pressure_app/model/blood_pressure/pressure_unit.dart';
import 'package:blood_pressure_app/model/horizontal_graph_line.dart';
import 'package:blood_pressure_app/model/storage/bluetooth_input_mode.dart';
@@ -46,7 +45,6 @@ class Settings extends ChangeNotifier {
bool? startWithAddMeasurementPage,
bool? useLegacyList,
bool? bottomAppBars,
- List<Medicine>? medications,
PressureUnit? preferredPressureUnit,
List<String>? knownBleDev,
int? highestMedIndex,
@@ -75,7 +73,6 @@ class Settings extends ChangeNotifier {
if (horizontalGraphLines != null) _horizontalGraphLines = horizontalGraphLines;
if (lastVersion != null) _lastVersion = lastVersion;
if (bottomAppBars != null) _bottomAppBars = bottomAppBars;
- if (medications != null) _medications.addAll(medications);
if (preferredPressureUnit != null) _preferredPressureUnit = preferredPressureUnit;
if (highestMedIndex != null) _highestMedIndex = highestMedIndex;
if (knownBleDev != null) _knownBleDev = knownBleDev;
@@ -111,8 +108,6 @@ class Settings extends ChangeNotifier {
needlePinBarWidth: ConvertUtil.parseDouble(map['needlePinBarWidth']),
lastVersion: ConvertUtil.parseInt(map['lastVersion']),
bottomAppBars: ConvertUtil.parseBool(map['bottomAppBars']),
- medications: ConvertUtil.parseList<String>(map['medications'])?.map((e) =>
- Medicine.fromJson(jsonDecode(e)),).toList(),
highestMedIndex: ConvertUtil.parseInt(map['highestMedIndex']),
knownBleDev: ConvertUtil.parseList<String>(map['knownBleDev']),
bleInput: BluetoothInputMode.deserialize(ConvertUtil.parseInt(map['bleInput'])),
@@ -161,7 +156,6 @@ class Settings extends ChangeNotifier {
'needlePinBarWidth': _needlePinBarWidth,
'lastVersion': lastVersion,
'bottomAppBars': bottomAppBars,
- 'medications': medications.map(jsonEncode).toList(),
'highestMedIndex': highestMedIndex,
'preferredPressureUnit': preferredPressureUnit.encode(),
'knownBleDev': knownBleDev,
@@ -200,8 +194,6 @@ class Settings extends ChangeNotifier {
_preferredPressureUnit = other._preferredPressureUnit;
_knownBleDev = other._knownBleDev;
_bleInput = other._bleInput;
- _medications.clear();
- _medications.addAll(other._medications);
_highestMedIndex = other._highestMedIndex;
_weightInput = other._weightInput;
_weightUnit = other._weightUnit;
@@ -438,15 +430,6 @@ class Settings extends ChangeNotifier {
notifyListeners();
}
- final List<Medicine> _medications = [];
- /// All medications ever added.
- ///
- /// This includes medications that got hidden. To obtain medications for a
- /// selection, do `settings.medications.where((e) => !e.hidden)`.
- @Deprecated('use health_data_store')
- UnmodifiableListView<Medicine> get medications =>
- UnmodifiableListView(_medications);
-
int _highestMedIndex = 0;
/// Total amount of medicines created.
int get highestMedIndex => _highestMedIndex;
app/lib/model/storage/update_legacy_settings.dart
@@ -1,7 +1,6 @@
import 'dart:convert';
import 'package:blood_pressure_app/model/blood_pressure/warn_values.dart';
-import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/export_import/export_configuration.dart';
import 'package:blood_pressure_app/model/horizontal_graph_line.dart';
import 'package:blood_pressure_app/model/storage/convert_util.dart';
@@ -13,10 +12,8 @@ import 'package:blood_pressure_app/model/storage/export_settings_store.dart';
import 'package:blood_pressure_app/model/storage/interval_store.dart';
import 'package:blood_pressure_app/model/storage/settings_store.dart';
import 'package:flutter/material.dart';
-import 'package:fluttertoast/fluttertoast.dart';
import 'package:health_data_store/health_data_store.dart';
import 'package:shared_preferences/shared_preferences.dart';
-import 'package:sqflite/sqflite.dart';
import 'db/config_dao.dart';
@@ -199,36 +196,6 @@ Future<void> migrateSharedPreferences(Settings settings, ExportSettings exportSe
}
}
-/// Function for upgrading pre 1.5.8 columns and settings to new structures.
-///
-/// - Adds columns from old db table to [manager].
-Future<void> _updateLegacyExport(ConfigDB database, ExportColumnsManager manager) async {
- if (await _tableExists(database.database, ConfigDB.exportStringsTable)) {
- final existingDbEntries = await database.database.query(
- ConfigDB.exportStringsTable,
- columns: ['internalColumnName', 'columnTitle', 'formatPattern'],
- );
- for (final e in existingDbEntries) {
- final column = UserColumn(
- e['internalColumnName'].toString(),
- e['columnTitle'].toString(),
- e['formatPattern'].toString(),
- );
- if (column.formatPattern?.contains(r'$FORMAT') ?? false) {
- await Fluttertoast.showToast(
- msg: r'The export $FORMAT pattern got replaced. Your export columns broke.',
- );
- }
- manager.addOrUpdate(column);
- }
-
- await database.database.execute('DROP TABLE IF EXISTS ${ConfigDB.exportStringsTable};');
- }
-}
-
-Future<bool> _tableExists(Database database, String tableName) async => (await database.rawQuery(
- "SELECT name FROM sqlite_master WHERE type='table' AND name='$tableName';",)).isNotEmpty;
-
/// Migrate to file based settings format from db in pre 1.7.4 (Jul 24).
Future<void> migrateDatabaseSettings(
Settings settings,
@@ -242,18 +209,9 @@ Future<void> migrateDatabaseSettings(
final configDB = await ConfigDB.open();
if(configDB == null) return; // not upgradable
- await _updateLegacyExport(configDB, manager); // TODO: test these older migrations
final configDao = ConfigDao(configDB);
- final oldSettings = await configDao.loadSettings();
- settings.copyFrom(oldSettings);
- final oldMeds = settings.medications.map((e) => Medicine(
- designation: e.designation,
- color: e.color.toARGB32(),
- dosis: e.defaultDosis == null ? null : Weight.mg(e.defaultDosis!),
- ));
- await Future.forEach(oldMeds, medRepo.add);
-
+ settings.copyFrom(await configDao.loadSettings());
exportSettings.copyFrom(await configDao.loadExportSettings());
csvExportSettings.copyFrom(await configDao.loadCsvExportSettings());
pdfExportSettings.copyFrom(await configDao.loadPdfExportSettings());
app/lib/screens/error_reporting_screen.dart
@@ -107,25 +107,6 @@ class ErrorScreen extends StatelessWidget {
try {
String dbPath = await getDatabasesPath();
- assert(dbPath != inMemoryDatabasePath);
- dbPath = join(dbPath, 'blood_pressure.db');
- await FilePicker.platform.saveFile(
- fileName: 'blood_pressure.db',
- bytes: File(dbPath).readAsBytesSync(),
- type: FileType.any, // application/vnd.sqlite3
- );
- } catch(e) {
- scaffoldMessenger.showSnackBar(SnackBar(
- content: Text('ERR: $e'),),);
- }
- },
- child: const Text('rescue legacy blood_pressure.db'),
- ),
- TextButton(
- onPressed: () async {
- try {
- String dbPath = await getDatabasesPath();
-
assert(dbPath != inMemoryDatabasePath);
dbPath = join(dbPath, 'config.db');
@@ -146,25 +127,6 @@ class ErrorScreen extends StatelessWidget {
try {
String dbPath = await getDatabasesPath();
- assert(dbPath != inMemoryDatabasePath);
- dbPath = join(dbPath, 'medicine.intakes');
- await FilePicker.platform.saveFile(
- fileName: 'medicine.intakes',
- bytes: File(dbPath).readAsBytesSync(),
- type: FileType.any, // application/octet-stream
- );
- } catch(e) {
- scaffoldMessenger.showSnackBar(SnackBar(
- content: Text('ERR: $e'),),);
- }
- },
- child: const Text('rescue old medicine intakes'),
- ),
- TextButton(
- onPressed: () async {
- try {
- String dbPath = await getDatabasesPath();
-
assert(dbPath != inMemoryDatabasePath);
dbPath = join(dbPath, 'bp.db');
await FilePicker.platform.saveFile(
app/lib/app.dart
@@ -1,8 +1,7 @@
import 'dart:io';
import 'package:blood_pressure_app/data_util/consistent_future_builder.dart';
-import 'package:blood_pressure_app/model/blood_pressure/update_legacy_entries.dart';
-import 'package:blood_pressure_app/model/export_import/export_configuration.dart';
+import 'package:blood_pressure_app/l10n/app_localizations.dart';
import 'package:blood_pressure_app/model/storage/db/file_settings_loader.dart';
import 'package:blood_pressure_app/model/storage/db/settings_loader.dart';
import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
@@ -13,8 +12,6 @@ import 'package:blood_pressure_app/screens/loading_screen.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:blood_pressure_app/l10n/app_localizations.dart';
-import 'package:fluttertoast/fluttertoast.dart';
import 'package:health_data_store/health_data_store.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path/path.dart';
@@ -77,10 +74,14 @@ class _AppState extends State<App> {
try {
File(join(dbPath, 'config.db')).deleteSync();
File(join(dbPath, 'config.db-journal')).deleteSync();
- } on FileSystemException { }
+ } on FileSystemException {
+ // No file to delete
+ }
try {
File(join(dbPath, 'medicine.intakes')).deleteSync();
- } on FileSystemException { }
+ } on FileSystemException {
+ // No file to delete
+ }
}
try {
@@ -116,31 +117,7 @@ class _AppState extends State<App> {
}
try {
- await updateLegacyEntries(
- _settings!,
- bpRepo,
- noteRepo,
- medRepo,
- intakeRepo,
- );
-
// update logic
- if (_settings!.lastVersion == 0) {
- await migrateSharedPreferences(_settings!, _exportSettings!, _csvExportSettings!, _pdfExportSettings!, _intervalStorageManager!);
-
- _settings!.lastVersion = 30;
- if (_exportSettings!.exportAfterEveryEntry) {
- await Fluttertoast.showToast(
- msg: r'Please review your export settings to ensure everything works as expected.',
- );
- }
- }
- if (_settings!.lastVersion == 30) {
- if (_pdfExportSettings!.exportFieldsConfiguration.activePreset == ExportImportPreset.bloodPressureApp) {
- _pdfExportSettings!.exportFieldsConfiguration.activePreset = ExportImportPreset.bloodPressureAppPdf;
- }
- _settings!.lastVersion = 31;
- }
if (_settings!.allowMissingValues && _settings!.validateInputs){
_settings!.validateInputs = false;
}
app/test/model/medicine/medicine_intake_test.dart
@@ -1,24 +0,0 @@
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine.dart';
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine_intake.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-void main() {
- test('should determine equality', () {
- final med = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 123);
- final int1 = OldMedicineIntake(medicine: med, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
- final int2 = OldMedicineIntake(medicine: med, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
- expect(int1, int2);
- });
- test('should determine inequality', () {
- final med1 = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 123);
- final med2 = Medicine(2, designation: 'designation', color: Colors.red, defaultDosis: 123);
- final int1 = OldMedicineIntake(medicine: med1, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
- final int2 = OldMedicineIntake(medicine: med2, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
- expect(int1, isNot(int2));
- final int3 = OldMedicineIntake(medicine: med1, dosis: 11, timestamp: DateTime.fromMillisecondsSinceEpoch(123));
- expect(int1, isNot(int3));
- final int4 = OldMedicineIntake(medicine: med1, dosis: 10, timestamp: DateTime.fromMillisecondsSinceEpoch(124));
- expect(int1, isNot(int4));
- });
-}
app/test/model/medicine/medicine_test.dart
@@ -1,20 +0,0 @@
-import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-void main() {
- test('should determine equality', () {
- final med1 = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 10);
- final med2 = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 10);
- expect(med1, med2);
- });
- test('should determine inequality', () {
- final med1 = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 10);
- final med2 = Medicine(1, designation: 'designatio', color: Colors.red, defaultDosis: 10);
- expect(med1, isNot(med2));
- final med3 = Medicine(1, designation: 'designation', color: Colors.blue, defaultDosis: 10);
- expect(med1, isNot(med3));
- final med4 = Medicine(1, designation: 'designation', color: Colors.red, defaultDosis: 11);
- expect(med1, isNot(med4));
- });
-}
app/test/model/bood_pressure_test.dart
@@ -1,68 +0,0 @@
-import 'package:blood_pressure_app/model/blood_pressure/model.dart';
-import 'package:blood_pressure_app/model/blood_pressure/record.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:path/path.dart';
-import 'package:sqflite_common_ffi/sqflite_ffi.dart';
-
-
-void main() {
- group('BloodPressureRecord', () {
- test('should initialize with all values supported by dart', () {
- final OldBloodPressureRecord record = OldBloodPressureRecord(DateTime.fromMicrosecondsSinceEpoch(1582991592), 0, -50, 1000,
- '((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა',);
-
- expect(record.creationTime, DateTime.fromMicrosecondsSinceEpoch(1582991592));
- expect(record.systolic, 0);
- expect(record.diastolic, -50);
- expect(record.pulse, 1000);
- expect(record.notes,
- '((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა',);
- });
- test('should not save times at or before epoch', () {
- expect(() => OldBloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(0), 0, 0, 0, ''), throwsAssertionError);
- });
- });
-
- group('BloodPressureModel', () {
- setUpAll(() {
- sqfliteFfiInit();
- databaseFactory = databaseFactoryFfi;
- });
-
- test("Doesn't create new models", () async {
- final model = await BloodPressureModel
- .create(dbPath: join(inMemoryDatabasePath, 'BPMShouldInit.db'));
- expect(model, isNull);
- });
- /* TODO: make reliable and reduce test data size
- test('correctly loads db from v1.6.4 and prior', () async {
-
- final model = await BloodPressureModel.create(dbPath: 'test/model/export_import/exported_formats/v1.6.4.db', isFullPath: true);
- expect(model, isNotNull);
-
- final all = await model!.all;
- expect(all, hasLength(27620));
- expect(all, contains(isA<OldBloodPressureRecord>()
- .having((r) => r.creationTime.millisecondsSinceEpoch, 'time', 1077625200000)
- .having((r) => r.systolic, 'sys', 100)
- .having((r) => r.diastolic, 'dia', 82)
- .having((r) => r.pulse, 'pul', 63),
- ));
- }, timeout: Timeout(Duration(minutes: 3)));
- test('correctly loads db from v1.7.0 and later', () async {
- sqfliteFfiInit();
- final db = await databaseFactoryFfi.openDatabase('test/model/export_import/exported_formats/v1.7.0.db');
- final hDataStore = await HealthDataStore.load(db);
- final bpRepo = hDataStore.bpRepo;
-
- final all = await bpRepo.get(DateRange.all());
- expect(all, hasLength(27620));
- expect(all, contains(isA<FullEntry>()
- .having((r) => r.time.millisecondsSinceEpoch, 'time', 1077625200000)
- .having((r) => r.sys, 'sys', 100)
- .having((r) => r.dia, 'dia', 82)
- .having((r) => r.pul, 'pul', 63),
- ));
- }, timeout: Timeout(Duration(minutes: 3)));*/
- });
-}
app/pubspec.lock
@@ -458,14 +458,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
- fluttertoast:
- dependency: "direct main"
- description:
- name: fluttertoast
- sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1"
- url: "https://pub.dev"
- source: hosted
- version: "8.2.12"
freezed_annotation:
dependency: transitive
description:
app/pubspec.yaml
@@ -35,7 +35,6 @@ dependencies:
flutter_blue_plus: ^1.35.3
archive: ^4.0.5
file_picker: ^10.0.0
- fluttertoast: ^8.2.12
app_settings: ^5.2.0
logging: ^1.3.0
persistent_user_dir_access_android: ^0.0.1