Commit c5c3421

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2023-10-02 16:57:25
access ExportColumns through config_dao.dart
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 551aca4
Changed files (4)
lib/model/storage/db/config_dao.dart
@@ -1,3 +1,4 @@
+import 'package:blood_pressure_app/model/export_options.dart';
 import 'package:blood_pressure_app/model/storage/db/config_db.dart';
 import 'package:blood_pressure_app/model/storage/settings_store.dart';
 import 'package:sqflite/sqflite.dart';
@@ -50,4 +51,39 @@ class ConfigDao {
       conflictAlgorithm: ConflictAlgorithm.replace
     );
   }
+
+  // TODO: test if custom export columns still work
+  Future<List<ExportColumn>> loadExportColumns() async {
+    final existingDbEntries = await _configDB.database.query(
+      ConfigDB.exportStringsTable,
+      columns: ['internalColumnName', 'columnTitle', 'formatPattern']
+    );
+    return [
+      for (final e in existingDbEntries)
+        ExportColumn(
+            internalName: e['internalColumnName'].toString(),
+            columnTitle: e['columnTitle'].toString(),
+            formatPattern: e['formatPattern'].toString()
+        ),
+    ];
+  }
+
+  Future<void> updateExportColumn(ExportColumn exportColumn) async {
+    await _configDB.database.insert(
+        ConfigDB.exportStringsTable,
+        {
+          'internalColumnName': exportColumn.internalName,
+          'columnTitle': exportColumn.columnTitle,
+          'formatPattern': exportColumn.formatPattern
+        },
+        conflictAlgorithm: ConflictAlgorithm.replace
+    );
+  }
+
+  Future<void> deleteExportColumn(String internalName) async {
+    await _configDB.database.delete('exportStrings', where: 'internalColumnName = ?', whereArgs: [internalName]);
+  }
+
+
+  // TODO: ExportConfigurationModel
 }
\ No newline at end of file
lib/model/storage/db/config_db.dart
@@ -15,7 +15,10 @@ class ConfigDB {
   
   /// Name of the settings table.
   ///
-  /// It is used to store json representations of [Settings] objects.
+  /// It is used to store json representations of [Settings] objects. Settings are saved as json, as there is no use
+  /// case where accessing individual fields for SQLs logic and matching is needed and the complexity of maintaining
+  /// different settings formats (export) is not worth it. Disk space doesn't play a role, as in most cases there will
+  /// be only one entry in the table.
   ///
   /// Format:
   /// `CREATE TABLE settings(profile_id: INTEGER PRIMARY KEY, settings_json: STRING)`
@@ -25,7 +28,10 @@ class ConfigDB {
       'CREATE TABLE settings(profile_id: INTEGER PRIMARY KEY, settings_json: STRING)';
 
   /// Name of the exportStrings table. It is used to store formats used in the [ExportConfigurationModel].
-  static const String exportStrings = 'exportStrings';
+  ///
+  /// Format:
+  /// `CREATE TABLE exportStrings(internalColumnName STRING PRIMARY KEY, columnTitle STRING, formatPattern STRING)`
+  static const String exportStringsTable = 'exportStrings';
   // instead of just changing this string when changing the format, _onDBUpgrade should be used.
   static const String _exportStringsTableCreationString =
       'CREATE TABLE exportStrings(internalColumnName STRING PRIMARY KEY, columnTitle STRING, formatPattern STRING)';
@@ -68,7 +74,7 @@ class ConfigDB {
   ///
   /// [dbPath] is the path to the folder the database is in. When [dbPath] is left empty the default database file is
   /// used. The [isFullPath] option tells the constructor not to add the default filename at the end of [dbPath].
-  Future<ConfigDB> open({String? dbPath, bool isFullPath = false}) async {
+  static Future<ConfigDB> open({String? dbPath, bool isFullPath = false}) async {
     final instance = ConfigDB._create();
     await instance._asyncInit(dbPath, isFullPath);
     return instance;
lib/model/export_options.dart
@@ -4,12 +4,11 @@ import 'package:blood_pressure_app/main.dart';
 import 'package:blood_pressure_app/model/blood_pressure.dart';
 import 'package:blood_pressure_app/model/export_import.dart';
 import 'package:blood_pressure_app/model/settings_store.dart';
+import 'package:blood_pressure_app/model/storage/db/config_dao.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 import 'package:function_tree/function_tree.dart';
 import 'package:intl/intl.dart';
-import 'package:path/path.dart';
-import 'package:sqflite/sqflite.dart';
 
 class ExportFields {
   static const defaultCsv = ['timestampUnixMs', 'systolic', 'diastolic', 'pulse', 'notes', 'color'];
@@ -23,7 +22,7 @@ class ExportConfigurationModel {
 
   final Settings settings;
   final AppLocalizations localizations;
-  late final Database _database;
+  final ConfigDao _configDao; // TODO: remove after #181 is complete
   
   final List<ExportColumn> _availableFormats = [];
 
@@ -35,33 +34,16 @@ class ExportConfigurationModel {
     ('"My Heart" export', ['DATUM', 'SYSTOLE', 'DIASTOLE', 'PULS', 'Beschreibung', 'Tags', 'Gewicht', 'Sauerstoffsättigung']),
   ];
 
-  ExportConfigurationModel._create(this.settings, this.localizations);
-  Future<void> _asyncInit(String? dbPath, bool isFullPath) async {
-    dbPath ??= await getDatabasesPath();
-    if (dbPath != inMemoryDatabasePath && !isFullPath) {
-      dbPath = join(dbPath, 'config.db');
-    }
-
-    _database = await openDatabase(
-      dbPath,
-      onCreate: (db, version) {
-        return db.execute(
-            'CREATE TABLE exportStrings(internalColumnName STRING PRIMARY KEY, columnTitle STRING, formatPattern STRING)');
-      },
-      version: 1,
-    );
+  ExportConfigurationModel._create(this.settings, this.localizations, this._configDao);
+  Future<void> _asyncInit() async {
 
-    final existingDbEntries = await _database.rawQuery('SELECT * FROM exportStrings');
-    for (final e in existingDbEntries) {
-      _availableFormats.add(ExportColumn(internalName: e['internalColumnName'].toString(),
-          columnTitle: e['columnTitle'].toString(), formatPattern: e['formatPattern'].toString()));
-    }
     _availableFormats.addAll(getDefaultFormates());
+    _availableFormats.addAll(await _configDao.loadExportColumns());
   }
   static Future<ExportConfigurationModel> get(Settings settings, AppLocalizations localizations, {String? dbPath, bool isFullPath = false}) async {
     if (_instance == null) {
-      _instance = ExportConfigurationModel._create(settings, localizations);
-      await _instance!._asyncInit(dbPath, isFullPath);
+      _instance = ExportConfigurationModel._create(settings, localizations, globalConfigDao);
+      await _instance!._asyncInit();
     }
     return _instance!;
   }
@@ -102,37 +84,16 @@ class ExportConfigurationModel {
     ExportColumn(internalName: 'Sauerstoffsättigung', columnTitle: '"My Heart" export oxygen', formatPattern: r'0', editable: false, hidden: true),
   ];
 
-  // TODO: testing
   void addOrUpdate(ExportColumn format) {
-    final existingEntries = _availableFormats.where((element) => element.internalName == format.internalName);
-    if (existingEntries.isNotEmpty) {
-      assert(existingEntries.length == 1);
-      if (!existingEntries.first.editable) {
-        assert(false, 'Attempted to update non editable field. While this doesn\'t cause any direct issues, it should not be made possible through the UI.');
-        return;
-      }
-      _availableFormats.remove(existingEntries.first);
-      _availableFormats.add(format);
-      _database.update('exportStrings', {
-        'columnTitle': format.columnTitle,
-        'formatPattern': format.formatPattern
-      }, where: 'internalColumnName = ?', whereArgs: [format.internalName]);
-    } else {
-      _availableFormats.add(format);
-      _database.insert('exportStrings', {
-        'internalColumnName': format.internalName,
-        'columnTitle': format.columnTitle,
-        'formatPattern': format.formatPattern
-      },);
-    }
-
+    _availableFormats.add(format);
+    _configDao.updateExportColumn(format);
   }
 
   void delete(ExportColumn format) {
     final existingEntries = _availableFormats.where((element) => (element.internalName == format.internalName) && element.editable);
     assert(existingEntries.isNotEmpty, r"Tried to delete entry that doesn't exist or is not editable.");
     _availableFormats.removeWhere((element) => element.internalName == format.internalName);
-    _database.delete('exportStrings', where: 'internalColumnName = ?', whereArgs: [format.internalName]);
+    _configDao.deleteExportColumn(format.internalName);
   }
 
   UnmodifiableListView<ExportColumn> get availableFormats => UnmodifiableListView(_availableFormats);
lib/main.dart
@@ -1,12 +1,17 @@
 import 'package:blood_pressure_app/model/blood_pressure.dart';
 import 'package:blood_pressure_app/model/settings_store.dart';
+import 'package:blood_pressure_app/model/storage/db/config_dao.dart';
+import 'package:blood_pressure_app/model/storage/db/config_db.dart';
 import 'package:blood_pressure_app/screens/home.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 import 'package:flutter_localizations/flutter_localizations.dart';
 import 'package:provider/provider.dart';
 
+@Deprecated('see #182')
 late AppLocalizations gLocalizations;
+@Deprecated('This should not be used for new code, but rather for migrating existing code.')
+late final ConfigDao globalConfigDao;
 
 void main() async {
   WidgetsFlutterBinding.ensureInitialized();
@@ -14,6 +19,9 @@ void main() async {
   final dataModel = await BloodPressureModel.create();
   final settingsModel = await Settings.create();
 
+  // TODO:
+  globalConfigDao = ConfigDao(await ConfigDB.open());
+
   // Reset the step size intervall to current on startup
   settingsModel.changeStepSize(settingsModel.graphStepSize);