From 384c4ec92ef5228d50f1f688f777658bfcc0c937 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 14 Jun 2026 12:19:35 +0300 Subject: [PATCH 1/2] feat(theme): persist selected registry theme in AppSettings Store theme_selected_id/source/path for registry-backed selection without changing existing preset or legacy import settings. --- lib/core/storage/app_settings.dart | 68 ++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/lib/core/storage/app_settings.dart b/lib/core/storage/app_settings.dart index 9530b38d..b62c1d74 100644 --- a/lib/core/storage/app_settings.dart +++ b/lib/core/storage/app_settings.dart @@ -106,6 +106,9 @@ abstract final class AppSettingsKeys { static const themeImportPath = 'theme_import_path'; static const themeImportName = 'theme_import_name'; static const themeImportedColorsJson = 'theme_imported_colors_json'; + static const themeSelectedId = 'theme_selected_id'; + static const themeSelectedSource = 'theme_selected_source'; + static const themeSelectedPath = 'theme_selected_path'; static const themeAnimationEnabled = 'theme_animation_enabled'; static const uiScale = 'ui_scale'; } @@ -327,6 +330,68 @@ class AppSettings { AppSettingsRevision.bump(); } + Future getSelectedThemeId() async { + final v = await LocalDb.instance.getAppSetting(AppSettingsKeys.themeSelectedId); + if (v == null || v.isEmpty) return null; + return v; + } + + Future setSelectedThemeId(String? id) async { + if (id == null || id.isEmpty) { + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedId); + } else { + await LocalDb.instance.setAppSetting(AppSettingsKeys.themeSelectedId, id); + } + AppSettingsRevision.bump(); + } + + Future getSelectedThemeSource() async { + final v = + await LocalDb.instance.getAppSetting(AppSettingsKeys.themeSelectedSource); + if (v == null || v.isEmpty) return null; + return v; + } + + Future setSelectedThemeSource(String? source) async { + if (source == null || source.isEmpty) { + await LocalDb.instance.deleteAppSetting( + AppSettingsKeys.themeSelectedSource, + ); + } else { + await LocalDb.instance.setAppSetting( + AppSettingsKeys.themeSelectedSource, + source, + ); + } + AppSettingsRevision.bump(); + } + + Future getSelectedThemePath() async { + final v = + await LocalDb.instance.getAppSetting(AppSettingsKeys.themeSelectedPath); + if (v == null || v.isEmpty) return null; + return v; + } + + Future setSelectedThemePath(String? path) async { + if (path == null || path.isEmpty) { + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedPath); + } else { + await LocalDb.instance.setAppSetting( + AppSettingsKeys.themeSelectedPath, + path, + ); + } + AppSettingsRevision.bump(); + } + + Future clearSelectedThemeRegistry() async { + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedId); + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedSource); + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedPath); + AppSettingsRevision.bump(); + } + Future> getThemeImportedColors() async { final v = await LocalDb.instance.getAppSetting( AppSettingsKeys.themeImportedColorsJson, @@ -453,6 +518,9 @@ class AppSettings { await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themePreset); await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeOverridesJson); await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeAnimationEnabled); + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedId); + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedSource); + await LocalDb.instance.deleteAppSetting(AppSettingsKeys.themeSelectedPath); await deleteThemeImportKeys(); AppSettingsRevision.bump(); } From e7182012415835683800438e8c1b05a45551a83e Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 14 Jun 2026 12:19:35 +0300 Subject: [PATCH 2/2] test(storage): cover selected theme registry AppSettings roundtrip Closes #110. --- test/core/storage/app_settings_test.dart | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/core/storage/app_settings_test.dart b/test/core/storage/app_settings_test.dart index 62e6b05d..9f4fa6e1 100644 --- a/test/core/storage/app_settings_test.dart +++ b/test/core/storage/app_settings_test.dart @@ -227,6 +227,55 @@ void main() { await AppSettings.instance.clearThemeColorOverrides(); expect(await AppSettings.instance.getThemeColorOverrides(), isEmpty); }); + + test('selected theme registry id/source/path roundtrip', () async { + expect(await AppSettings.instance.getSelectedThemeId(), isNull); + expect(await AppSettings.instance.getSelectedThemeSource(), isNull); + expect(await AppSettings.instance.getSelectedThemePath(), isNull); + + await AppSettings.instance.setSelectedThemeId('fixture-custom-dark'); + await AppSettings.instance.setSelectedThemeSource('filesystem'); + await AppSettings.instance.setSelectedThemePath( + '/data/themes/fixture-custom-dark.json', + ); + + expect( + await AppSettings.instance.getSelectedThemeId(), + 'fixture-custom-dark', + ); + expect( + await AppSettings.instance.getSelectedThemeSource(), + 'filesystem', + ); + expect( + await AppSettings.instance.getSelectedThemePath(), + '/data/themes/fixture-custom-dark.json', + ); + }); + + test('clearSelectedThemeRegistry clears registry selection', () async { + await AppSettings.instance.setSelectedThemeId('fixture-custom-dark'); + await AppSettings.instance.setSelectedThemeSource('imported'); + await AppSettings.instance.setSelectedThemePath('/tmp/theme.json'); + + await AppSettings.instance.clearSelectedThemeRegistry(); + + expect(await AppSettings.instance.getSelectedThemeId(), isNull); + expect(await AppSettings.instance.getSelectedThemeSource(), isNull); + expect(await AppSettings.instance.getSelectedThemePath(), isNull); + }); + + test('clearThemeSettings clears selected registry theme', () async { + await AppSettings.instance.setSelectedThemeId('fixture-custom-light'); + await AppSettings.instance.setSelectedThemeSource('filesystem'); + await AppSettings.instance.setSelectedThemePath('/tmp/light.json'); + + await AppSettings.instance.clearThemeSettings(); + + expect(await AppSettings.instance.getSelectedThemeId(), isNull); + expect(await AppSettings.instance.getSelectedThemeSource(), isNull); + expect(await AppSettings.instance.getSelectedThemePath(), isNull); + }); }); group('ui scale', () {