Commit 4f51e05

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2023-10-20 12:56:33
change dark mode booleans to ThemeMode enum
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 0a9323d
lib/model/storage/db/config_dao.dart
@@ -12,6 +12,8 @@ import 'package:sqflite/sqflite.dart';
 /// The user of this class needs to pay attention to dispose all old instances of objects created by the instance
 /// methods in order to ensure there are no concurrent writes to the database. Having multiple instances will cause data
 /// loss because states are not synced again after one changes.
+///
+/// The load... methods have to schedule a initial save to db in case an migration / update of fields occurred.
 class ConfigDao {
   ConfigDao(this._configDB);
   
@@ -43,6 +45,7 @@ class ConfigDao {
         settings = Settings.fromJson(settingsJson.toString());
       }
     }
+    _updateSettings(profileID, settings);
     settings.addListener(() {
       _updateSettings(profileID, settings);
     });
@@ -90,6 +93,7 @@ class ConfigDao {
         exportSettings = ExportSettings.fromJson(settingsJson.toString());
       }
     }
+    _updateExportSettings(profileID, exportSettings);
     exportSettings.addListener(() {
       _updateExportSettings(profileID, exportSettings);
     });
@@ -137,6 +141,7 @@ class ConfigDao {
         exportSettings = CsvExportSettings.fromJson(settingsJson.toString());
       }
     }
+    _updateCsvExportSettings(profileID, exportSettings);
     exportSettings.addListener(() {
       _updateCsvExportSettings(profileID, exportSettings);
     });
@@ -184,6 +189,7 @@ class ConfigDao {
         exportSettings = PdfExportSettings.fromJson(settingsJson.toString());
       }
     }
+    _updatePdfExportSettings(profileID, exportSettings);
     exportSettings.addListener(() {
       _updatePdfExportSettings(profileID, exportSettings);
     });
@@ -231,6 +237,7 @@ class ConfigDao {
       intervallStorage = IntervallStorage.fromMap(dbEntry.first);
     }
 
+    _updateIntervallStorage(profileID, storageID, intervallStorage);
     intervallStorage.addListener(() {
       _updateIntervallStorage(profileID, storageID, intervallStorage);
     });
@@ -254,7 +261,6 @@ class ConfigDao {
     );
   }
 
-  // TODO: test if custom export columns still work
   /// Loads the current export columns from the database.
   ///
   /// Changes will *not* be saved automatically, see [updateExportColumn].
lib/model/storage/convert_util.dart
@@ -88,4 +88,21 @@ class ConvertUtil {
     if (value is List && value.isEmpty) return [];
     return null;
   }
+
+  static ThemeMode? parseThemeMode(dynamic value) {
+    int? intValue = ConvertUtil.parseInt(value);
+    switch(intValue) {
+      case null:
+        return null;
+      case 0:
+        return ThemeMode.system;
+      case 1:
+        return ThemeMode.dark;
+      case 2:
+        return ThemeMode.light;
+      default:
+        assert(false);
+        return null;
+    }
+  }
 }
\ No newline at end of file
lib/model/storage/settings_store.dart
@@ -36,8 +36,7 @@ class Settings extends ChangeNotifier {
     int? diaWarn,
     bool? allowManualTimeInput,
     bool? confirmDeletion,
-    bool? darkMode,
-    bool? followSystemDarkMode,
+    ThemeMode? themeMode,
     bool? validateInputs,
     bool? allowMissingValues,
     bool? drawRegressionLines,
@@ -50,13 +49,12 @@ class Settings extends ChangeNotifier {
     if (pulColor != null) _pulColor = pulColor;
     if (allowManualTimeInput != null) _allowManualTimeInput = allowManualTimeInput;
     if (confirmDeletion != null) _confirmDeletion = confirmDeletion;
-    if (darkMode != null) _darkMode = darkMode;
+    if (themeMode != null) _themeMode = themeMode;
     if (dateFormatString != null) _dateFormatString = dateFormatString;
     if (animationSpeed != null) _animationSpeed = animationSpeed;
     if (sysWarn != null) _sysWarn = sysWarn;
     if (diaWarn != null) _diaWarn = diaWarn;
     if (graphLineThickness != null) _graphLineThickness = graphLineThickness;
-    if (followSystemDarkMode != null) _followSystemDarkMode = followSystemDarkMode;
     if (validateInputs != null) _validateInputs = validateInputs;
     if (allowMissingValues != null) _allowMissingValues = allowMissingValues;
     if (drawRegressionLines != null) _drawRegressionLines = drawRegressionLines;
@@ -66,29 +64,36 @@ class Settings extends ChangeNotifier {
     _language = language; // No check here, as null is the default as well.
   }
 
-  factory Settings.fromMap(Map<String, dynamic> map) => Settings(
-    accentColor: ConvertUtil.parseColor(map['accentColor']),
-    sysColor: ConvertUtil.parseColor(map['sysColor']),
-    diaColor: ConvertUtil.parseColor(map['diaColor']),
-    pulColor: ConvertUtil.parseColor(map['pulColor']),
-    allowManualTimeInput: ConvertUtil.parseBool(map['allowManualTimeInput']),
-    confirmDeletion: ConvertUtil.parseBool(map['confirmDeletion']),
-    darkMode: ConvertUtil.parseBool(map['darkMode']),
-    dateFormatString: ConvertUtil.parseString(map['dateFormatString']),
-    animationSpeed: ConvertUtil.parseInt(map['animationSpeed']),
-    sysWarn: ConvertUtil.parseInt(map['sysWarn']),
-    diaWarn: ConvertUtil.parseInt(map['diaWarn']),
-    graphLineThickness: ConvertUtil.parseDouble(map['graphLineThickness']),
-    followSystemDarkMode: ConvertUtil.parseBool(map['followSystemDarkMode']),
-    validateInputs: ConvertUtil.parseBool(map['validateInputs']),
-    allowMissingValues: ConvertUtil.parseBool(map['allowMissingValues']),
-    drawRegressionLines: ConvertUtil.parseBool(map['drawRegressionLines']),
-    startWithAddMeasurementPage: ConvertUtil.parseBool(map['startWithAddMeasurementPage']),
-    useLegacyList: ConvertUtil.parseBool(map['useLegacyList']),
-    language: ConvertUtil.parseLocale(map['language']),
-    horizontalGraphLines: ConvertUtil.parseList<String>(map['horizontalGraphLines'])?.map((e) =>
-        HorizontalGraphLine.fromJson(jsonDecode(e))).toList(),
-  );
+  factory Settings.fromMap(Map<String, dynamic> map) {
+    var settingsObject = Settings(
+      accentColor: ConvertUtil.parseColor(map['accentColor']),
+      sysColor: ConvertUtil.parseColor(map['sysColor']),
+      diaColor: ConvertUtil.parseColor(map['diaColor']),
+      pulColor: ConvertUtil.parseColor(map['pulColor']),
+      allowManualTimeInput: ConvertUtil.parseBool(map['allowManualTimeInput']),
+      confirmDeletion: ConvertUtil.parseBool(map['confirmDeletion']),
+      themeMode: ConvertUtil.parseThemeMode(map['themeMode']),
+      dateFormatString: ConvertUtil.parseString(map['dateFormatString']),
+      animationSpeed: ConvertUtil.parseInt(map['animationSpeed']),
+      sysWarn: ConvertUtil.parseInt(map['sysWarn']),
+      diaWarn: ConvertUtil.parseInt(map['diaWarn']),
+      graphLineThickness: ConvertUtil.parseDouble(map['graphLineThickness']),
+      validateInputs: ConvertUtil.parseBool(map['validateInputs']),
+      allowMissingValues: ConvertUtil.parseBool(map['allowMissingValues']),
+      drawRegressionLines: ConvertUtil.parseBool(map['drawRegressionLines']),
+      startWithAddMeasurementPage: ConvertUtil.parseBool(map['startWithAddMeasurementPage']),
+      useLegacyList: ConvertUtil.parseBool(map['useLegacyList']),
+      language: ConvertUtil.parseLocale(map['language']),
+      horizontalGraphLines: ConvertUtil.parseList<String>(map['horizontalGraphLines'])?.map((e) =>
+          HorizontalGraphLine.fromJson(jsonDecode(e))).toList(),
+    );
+
+    // update
+    if (ConvertUtil.parseBool(map['followSystemThemeMode']) == false) { // when this is true the default is the same
+      settingsObject.themeMode = (ConvertUtil.parseBool(map['themeMode']) ?? true) ? ThemeMode.dark : ThemeMode.light;
+    }
+    return settingsObject;
+  }
 
   factory Settings.fromJson(String json) {
     try {
@@ -110,8 +115,7 @@ class Settings extends ChangeNotifier {
       'diaWarn': diaWarn,
       'allowManualTimeInput': allowManualTimeInput,
       'confirmDeletion': confirmDeletion,
-      'darkMode': darkMode,
-      'followSystemDarkMode': followSystemDarkMode,
+      'themeMode': themeMode.serialize(),
       'validateInputs': validateInputs,
       'allowMissingValues': allowMissingValues,
       'drawRegressionLines': drawRegressionLines,
@@ -217,21 +221,14 @@ class Settings extends ChangeNotifier {
     notifyListeners();
   }
 
-  bool _darkMode = true;
-  bool get darkMode => _darkMode;
-  set darkMode(bool value) {
-    _darkMode = value;
+  ThemeMode _themeMode = ThemeMode.system;
+  ThemeMode get themeMode => _themeMode;
+  set themeMode(ThemeMode value) {
+    _themeMode = value;
     notifyListeners();
   }
 
 
-  bool _followSystemDarkMode = true;
-  bool get followSystemDarkMode => _followSystemDarkMode;
-  set followSystemDarkMode(bool value) {
-    _followSystemDarkMode = value;
-    notifyListeners();
-  }
-
   bool _validateInputs = true;
   bool get validateInputs => _validateInputs;
   set validateInputs(bool value) {
@@ -270,4 +267,16 @@ class Settings extends ChangeNotifier {
 // When adding fields notice the checklist at the top.
 }
 
+extension on ThemeMode {
+  int serialize() {
+    switch(this) {
+      case ThemeMode.system:
+        return 0;
+      case ThemeMode.dark:
+        return 1;
+      case ThemeMode.light:
+        return 2;
+    }
+  }
+}
 
lib/model/storage/update_legacy_settings.dart
@@ -43,6 +43,10 @@ Future<void> updateLegacySettings(Settings settings, ExportSettings exportSettin
         csvExportSettings.customFields = sharedPreferences.getStringList(key)!;
         await sharedPreferences.remove(key);
         break;
+      case 'darkMode':
+        settings.themeMode = sharedPreferences.getBool(key)! ? ThemeMode.dark : ThemeMode.light;
+        await sharedPreferences.remove(key);
+        break;
     }
   }
   for (final key in keys) {
@@ -53,10 +57,7 @@ Future<void> updateLegacySettings(Settings settings, ExportSettings exportSettin
         intervallStoreManager.exportPage.changeStepSize(TimeStep.deserialize(sharedPreferences.getInt(key)!));
         break;
       case 'followSystemDarkMode':
-        settings.followSystemDarkMode = sharedPreferences.getBool(key)!;
-        break;
-      case 'darkMode':
-        settings.darkMode = sharedPreferences.getBool(key)!;
+        if (sharedPreferences.getBool(key)!) settings.themeMode = ThemeMode.system;
         break;
       case 'accentColor':
         settings.accentColor = ConvertUtil.parseColor(sharedPreferences.getInt(key)!)!;
lib/screens/settings.dart
@@ -52,32 +52,18 @@ class SettingsPage extends StatelessWidget {
                   );
                 },
               ),
-              DropDownSettingsTile<int>(
-                key: const Key('thema'),
+              DropDownSettingsTile<ThemeMode>(
+                key: const Key('theme'),
                 leading: const Icon(Icons.brightness_4),
                 title: Text(localizations.theme),
-                value: settings.followSystemDarkMode ? 0 : (settings.darkMode ? 1 : 2),
+                value: settings.themeMode,
                 items: [
-                  DropdownMenuItem(value: 0, child: Text(localizations.system)),
-                  DropdownMenuItem(value: 1, child: Text(localizations.dark)),
-                  DropdownMenuItem(value: 2, child: Text(localizations.light))
+                  DropdownMenuItem(value: ThemeMode.system, child: Text(localizations.system)),
+                  DropdownMenuItem(value: ThemeMode.dark, child: Text(localizations.dark)),
+                  DropdownMenuItem(value: ThemeMode.light, child: Text(localizations.light))
                 ],
-                onChanged: (int? value) {
-                  switch (value) {
-                    case 0:
-                      settings.followSystemDarkMode = true;
-                      break;
-                    case 1:
-                      settings.followSystemDarkMode = false;
-                      settings.darkMode = true;
-                      break;
-                    case 2:
-                      settings.followSystemDarkMode = false;
-                      settings.darkMode = false;
-                      break;
-                    default:
-                      assert(false);
-                  }
+                onChanged: (ThemeMode? value) {
+                  if (value != null) settings.themeMode = value;
                 },
               ),
               ColorSelectionSettingsTile(
lib/main.dart
@@ -54,8 +54,6 @@ class AppRoot extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return Consumer<Settings>(builder: (context, settings, child) {
-      final mode = getMode(settings);
-
       return MaterialApp(
         title: 'Blood Pressure App',
         onGenerateTitle: (context) {
@@ -76,7 +74,7 @@ class AppRoot extends StatelessWidget {
           ),
           useMaterial3: true
         ),
-        themeMode: mode,
+        themeMode: settings.themeMode,
         localizationsDelegates: const [
           AppLocalizations.delegate,
           GlobalMaterialLocalizations.delegate,
@@ -88,16 +86,6 @@ class AppRoot extends StatelessWidget {
       );
     });
   }
-
-  ThemeMode getMode(Settings settings) {
-    if (settings.followSystemDarkMode) {
-      return ThemeMode.system;
-    } else if (settings.darkMode) {
-      return ThemeMode.dark;
-    } else {
-      return ThemeMode.light;
-    }
-  }
 }
 
 bool _isDatabaseClosed = false;
test/model/convert_util_test.dart
@@ -113,5 +113,12 @@ void main() {
       expect(ConvertUtil.parseList<String>([1234,567,89,0]), null);
       expect(ConvertUtil.parseList<String>('tests'), null);
     });
+
+    test('parseThemeMode should convert valid values correctly', () {
+      expect(ConvertUtil.parseThemeMode(0), ThemeMode.system);
+      expect(ConvertUtil.parseThemeMode(1), ThemeMode.dark);
+      expect(ConvertUtil.parseThemeMode(2), ThemeMode.light);
+      expect(ConvertUtil.parseThemeMode(null), ThemeMode.light);
+    });
   });
 }
\ No newline at end of file
test/model/json_serialization_test.dart
@@ -81,8 +81,7 @@ void main() {
         diaWarn: 78,
         allowManualTimeInput: false,
         confirmDeletion: false,
-        darkMode: false,
-        followSystemDarkMode: false,
+        themeMode: ThemeMode.light,
         validateInputs: false,
         allowMissingValues: false,
         drawRegressionLines: false,
@@ -104,8 +103,7 @@ void main() {
       expect(initial.diaWarn, fromJson.diaWarn);
       expect(initial.allowManualTimeInput, fromJson.allowManualTimeInput);
       expect(initial.confirmDeletion, fromJson.confirmDeletion);
-      expect(initial.darkMode, fromJson.darkMode);
-      expect(initial.followSystemDarkMode, fromJson.followSystemDarkMode);
+      expect(initial.themeMode, fromJson.themeMode);
       expect(initial.validateInputs, fromJson.validateInputs);
       expect(initial.allowMissingValues, fromJson.allowMissingValues);
       expect(initial.drawRegressionLines, fromJson.drawRegressionLines);