Commit 4f51e05
Changed files (8)
lib
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);