Commit a7e1470

derdilla <82763757+derdilla@users.noreply.github.com>
2025-05-01 17:18:46
Remove old data migration code (#555)
* delete old medicince intake and related update code * delete old blood pressure db * delete code to update deprecated setting
1 parent 40771c0
app/lib/features/export_import/import_button.dart
@@ -1,8 +1,7 @@
 import 'dart:convert';
 
 import 'package:blood_pressure_app/features/export_import/import_preview_dialoge.dart';
-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/l10n/app_localizations.dart';
 import 'package:blood_pressure_app/model/export_import/csv_converter.dart';
 import 'package:blood_pressure_app/model/export_import/csv_record_parsing_actor.dart';
 import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
@@ -10,7 +9,6 @@ import 'package:blood_pressure_app/model/storage/storage.dart';
 import 'package:file_picker/file_picker.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:blood_pressure_app/l10n/app_localizations.dart';
 import 'package:health_data_store/health_data_store.dart';
 import 'package:provider/provider.dart';
 import 'package:sqflite/sqflite.dart';
@@ -98,31 +96,6 @@ class ImportButton extends StatelessWidget {
             // DB doesn't conform new format
           }
 
-          try { // Update legacy format
-            final model = (records.isNotEmpty || notes.isNotEmpty || intakes.isNotEmpty)
-                ? null
-                : await BloodPressureModel.create(dbPath: file.path!, isFullPath: true);
-            for (final OldBloodPressureRecord oldR in (await model?.all) ?? []) {
-              if (oldR.systolic != null || oldR.diastolic != null || oldR.pulse != null) {
-                records.add(BloodPressureRecord(
-                  time: oldR.creationTime,
-                  sys: oldR.systolic == null ? null :Pressure.mmHg(oldR.systolic!),
-                  dia: oldR.diastolic == null ? null :Pressure.mmHg(oldR.diastolic!),
-                  pul: oldR.pulse,
-                ));
-              }
-              if (oldR.notes.isNotEmpty || oldR.needlePin != null) {
-                notes.add(Note(
-                  time: oldR.creationTime,
-                  note: oldR.notes.isEmpty ? null : oldR.notes,
-                  color: oldR.needlePin?.color.toARGB32(),
-                ));
-              }
-            }
-            await model?.close();
-          } catch (e) {
-            // DB not importable
-          }
 
           await Future.forEach(records, bpRepo.add);
           await Future.forEach(notes, noteRepo.add);
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