Источник: theme-parser-implementation-tasks.md.
Формат ниже рассчитан на перенос в GitHub Issues: каждый блок можно заводить как отдельный issue.
Рекомендуемые labels:
themefrontendperformanceparsersettingsdocstestsgood first issue— только для изолированных docs/fixtures/test задач
- Epic A — Custom theme parser core
- Epic B — Theme registry and caching
- Epic C — Preferences theme picker for 50+ themes
- Epic D — Built-in themes, filesystem loading, docs
- Epic E — Window chrome theme sync
- TP-01 → TP-07: parser core.
- TP-08 → TP-14: registry, persistence, cache.
- TP-15 → TP-20: Preferences UI and import flow.
- TP-21 → TP-24: built-in assets, filesystem folder, docs.
- TP-25 → TP-27: window chrome sync and final hardening.
- TP-28 → TP-30: QA, regression tests, release checklist.
Labels: theme, docs, good first issue
Epic: A
Depends on: none
Create public documentation for the new Querya custom theme JSON format (querya.theme.v1) before implementing the parser.
Current docs/theme-import.md describes VS Code theme import. The new format must be documented separately so parser behavior is clear and testable.
Create docs/theme-custom-json.md with:
- purpose of the Querya custom format;
- required root fields:
schemaidnametypeshadcn_colorseditor_colors
- optional root fields:
tokenColorsdescriptionauthorversion
- accepted
typevalues:dark,light; - accepted color formats:
#RRGGBBRRGGBB#AARRGGBBAARRGGBB- optionally
#RGB/#RGBAif supported by existing parser;
- fallback rules:
- missing optional colors fallback to
QueryaTheme.darkDefault/QueryaTheme.lightDefault; - invalid optional color is ignored;
- missing required root field fails parsing;
- broken selected theme falls back to Querya Dark on startup;
- missing optional colors fallback to
- difference between VS Code JSON/JSONC and Querya custom JSON;
- one minimal working example and one full example.
Update docs/theme-import.md with a short link to docs/theme-custom-json.md.
docs/theme-custom-json.mdexists.- It includes a valid copy-pastable JSON example.
- It explicitly says VS Code import remains supported.
- It documents fallback/error behavior.
Docs only. No automated tests required.
Labels: theme, tests, good first issue
Epic: A
Depends on: TP-01
Add stable fixtures for parser and factory tests.
test/fixtures/themes/querya_custom_dark.jsontest/fixtures/themes/querya_custom_light.jsontest/fixtures/themes/querya_custom_minimal.jsontest/fixtures/themes/querya_custom_invalid_missing_id.jsontest/fixtures/themes/querya_custom_invalid_color.jsontest/fixtures/themes/querya_custom_jsonc.jsonc
Add fixtures:
querya_custom_dark.json- full dark theme with
shadcn_colors,editor_colors, and sampletokenColors;
- full dark theme with
querya_custom_light.json- full light theme;
querya_custom_minimal.json- only required root fields and a small set of colors;
querya_custom_invalid_missing_id.json- no
id;
- no
querya_custom_invalid_color.json- one optional invalid color and enough valid fields to test skip/failure policy;
querya_custom_jsonc.jsonc- comments and trailing commas.
- Fixtures are small enough to read in tests.
- Dark/light/minimal fixtures use distinct values so tests can assert mapping.
- Invalid fixtures target one failure mode each.
No parser tests in this issue. Fixtures are consumed by later issues.
Labels: theme, parser
Epic: A
Depends on: TP-02
Create an immutable model for Querya custom theme manifests without converting colors to Flutter Color yet.
lib/core/theme/parser/querya_theme_manifest.darttest/core/theme/parser/querya_theme_manifest_test.dart
Add:
enum QueryaThemeType { dark, light }
class QueryaThemeManifest {
const QueryaThemeManifest({
required this.schema,
required this.id,
required this.name,
required this.type,
required this.shadcnColors,
required this.editorColors,
this.tokenColors = const [],
this.description,
this.author,
this.version,
});
}
class QueryaThemeManifestParseException implements Exception {
const QueryaThemeManifestParseException(this.message);
final String message;
}Fields:
schema: Stringid: Stringname: Stringtype: QueryaThemeTypeshadcnColors: Map<String, String>editorColors: Map<String, String>tokenColors: List<TokenColorRule>- optional metadata fields.
Add QueryaThemeManifest.fromJsonString(String raw).
Use existing:
stripJsoncTokenColorRule/ existing token color parser path where possible.
- Do not create
Color,QueryaTheme, orThemeDatahere. - Keep maps unmodifiable.
- Parsing should be pure and synchronous for a single file; async belongs in services.
- Valid dark/light fixtures parse.
- JSONC fixture parses.
- Missing required fields throw
QueryaThemeManifestParseException. - Unknown fields are ignored.
- Returned maps are immutable or safely copied.
Cover:
- valid full dark;
- valid full light;
- minimal manifest;
- JSONC comments/trailing commas;
- missing
id; - invalid
type; - empty
shadcn_colors/editor_colorsbehavior according to docs.
Labels: theme, parser, tests
Epic: A
Depends on: TP-03
Support Querya custom HEX formats without duplicating incompatible color parsing logic.
lib/core/theme/parser/color_parser.darttest/core/theme/parser/color_parser_test.dart
Add:
Color parseQueryaThemeColor(String raw)Behavior:
- trim whitespace;
- accept
#RRGGBB; - accept
RRGGBB; - accept
#AARRGGBB; - accept
AARRGGBB; - delegate to
parseVsCodeColorwhere possible; - throw
FormatExceptionfor invalid input.
If current parseVsCodeColor already supports all formats, implement this wrapper as normalization + delegate.
- Wrapper exists and is used by custom theme factory.
- No second unrelated parser implementation.
- Error messages mention the invalid value.
Cases:
#1E1E1E1E1E1E#FF1E1E1EFF1E1E1E- lowercase hex
- invalid length
- invalid characters
- empty string
Labels: theme, parser
Epic: A
Depends on: TP-04
Convert custom shadcn_colors into shadcn_flutter.ColorScheme with fallback values.
lib/core/theme/parser/querya_theme_color_scheme.darttest/core/theme/parser/querya_theme_color_scheme_test.dart
Add pure function:
ColorScheme colorSchemeFromQueryaThemeColors({
required Map<String, String> colors,
required QueryaTheme fallback,
});Map these keys:
backgroundforegroundcardcardForegroundpopoverpopoverForegroundprimaryprimaryForegroundsecondarysecondaryForegroundmutedmutedForegroundaccentaccentForegrounddestructivedestructiveForegroundborderinputringchart1chart2chart3chart4chart5
Fallback:
- missing key -> fallback
colorSchemevalue; - invalid optional color -> fallback value;
- debug log invalid optional key if useful.
- Function is pure.
- Missing optional keys preserve fallback.
- Full fixture maps distinct expected values.
- Brightness comes from fallback theme, not from colors map.
- full map uses custom values;
- missing keys use fallback;
- invalid optional color uses fallback;
- chart colors fallback correctly.
Labels: theme, parser
Epic: A
Depends on: TP-04
Convert custom editor color tokens into QueryaEditorTheme.
lib/core/theme/parser/querya_editor_theme_from_manifest.darttest/core/theme/parser/querya_editor_theme_from_manifest_test.dart
Add:
QueryaEditorTheme editorThemeFromQueryaColors({
required Map<String, String> colors,
required QueryaEditorTheme fallback,
});Support keys matching current QueryaEditorTheme fields. At minimum:
backgroundforegroundselectionlineNumberbracketMatchwidgetBorder
If QueryaEditorTheme has additional fields, include them explicitly.
Fallback:
- missing/invalid key -> fallback field.
- Full fixture changes editor background/foreground/selection.
- Minimal fixture falls back for missing fields.
- Invalid optional color does not crash.
- full custom values;
- fallback behavior;
- invalid optional value.
Labels: theme, parser
Epic: A
Depends on: TP-04
Convert workbench-related custom tokens into QueryaWorkbenchTheme.
lib/core/theme/parser/querya_workbench_theme_from_manifest.darttest/core/theme/parser/querya_workbench_theme_from_manifest_test.dart
Add:
QueryaWorkbenchTheme workbenchThemeFromQueryaColors({
required Map<String, String> colors,
required QueryaWorkbenchTheme fallback,
});Support keys:
sidebarBackgroundcanvassurfaceeditorBackgroundmutedForegroundaccentonAccentborderSubtledestructivegitModifiedgitUntracked
If the docs use background, map it deliberately:
background->canvasand/oreditorBackgroundonly if explicit in docs.
- Mapping is documented in code comments or docs table.
- Missing keys use fallback.
- Invalid optional colors use fallback.
- full custom workbench mapping;
- minimal fallback;
- invalid optional value.
Labels: theme, parser
Epic: A
Depends on: TP-05, TP-06, TP-07
Provide one factory that converts QueryaThemeManifest into the existing app-level QueryaTheme.
lib/core/theme/parser/querya_theme_from_manifest.darttest/core/theme/parser/querya_theme_from_manifest_test.dart
Add:
QueryaTheme queryaThemeFromManifest(QueryaThemeManifest manifest)Algorithm:
- Pick fallback:
- dark ->
QueryaTheme.darkDefault - light ->
QueryaTheme.lightDefault
- dark ->
- Build
ColorSchemefromshadcn_colors. - Build
QueryaEditorThemefromeditor_colors. - Build
QueryaWorkbenchThemefromeditor_colors. - Return
fallback.copyWith(...). - Preserve
tokenColors.
- Full dark fixture creates dark
QueryaTheme. - Full light fixture creates light
QueryaTheme. tokenColorsare preserved.- No
ThemeDatais created.
- dark brightness;
- light brightness;
- shadcn color mapping;
- editor/workbench mapping;
- token colors preserved;
- minimal fixture fallback.
Labels: theme, parser, error-handling
Epic: A
Depends on: TP-08
Introduce result types for loading/parsing themes so UI and startup can handle failures without exceptions leaking.
lib/core/theme/theme_load_result.dart
Add sealed result:
sealed class ThemeLoadResult {
const ThemeLoadResult();
}
class ThemeLoadSuccess extends ThemeLoadResult {
const ThemeLoadSuccess({
required this.definition,
required this.theme,
});
}
class ThemeLoadFailure extends ThemeLoadResult {
const ThemeLoadFailure({
required this.definition,
required this.message,
this.error,
});
}Use this result in later registry APIs.
- Result can represent success/failure without throwing.
- Failure keeps enough data to show user-facing error and debug logs.
No direct tests required unless lint coverage demands it. Later registry tests will cover usage.
Labels: theme, registry
Epic: B
Depends on: TP-03
Represent lightweight theme metadata for lists/pickers without full parsing.
lib/core/theme/theme_definition.darttest/core/theme/theme_definition_test.dart
Add:
enum ThemeSource { builtin, imported, filesystem, legacyImported }
enum ThemeFormat { queryaCustom, vscode }
class ThemeDefinition {
const ThemeDefinition({
required this.id,
required this.name,
required this.source,
required this.format,
required this.isDark,
this.path,
this.lastModified,
this.contentHash,
});
}Add helpers:
bool get isFileBackedString get stableCacheKey
ThemeDefinitionis immutable.stableCacheKeychanges whencontentHashchanges.- Does not depend on Flutter widgets.
- file-backed vs builtin;
- cache key includes id/hash/source;
- equality if implemented.
Labels: theme, filesystem
Epic: B
Depends on: TP-10
Centralize app theme directories and avoid path logic scattered across services.
lib/core/theme/theme_paths.darttest/core/theme/theme_paths_test.dartif path provider can be faked easily.
Add:
abstract final class ThemePaths {
static Future<Directory> userThemesDirectory();
static Future<Directory> importedThemesDirectory();
}Rules:
- Primary user dir: app support directory +
themes. - Imported dir: app support directory +
themes/imported. - Optionally expose
legacyDotQueryaThemesDirectory()for later~/.querya/themes.
- Directories are not created by path getter unless method name says
ensure. - Separate
ensureUserThemesDirectory()can create it.
- If existing test support fakes path provider, assert paths.
- Otherwise cover through registry tests.
Labels: theme, filesystem, performance
Epic: B
Depends on: TP-10, TP-11
Scan app support theme folder and return lightweight ThemeDefinition objects.
lib/core/theme/theme_registry_service.darttest/core/theme/theme_registry_service_test.dart
Add:
class ThemeRegistryService {
Future<List<ThemeDefinition>> loadThemeDefinitions();
}For .json and .jsonc files:
- Read file async.
- Detect format:
- if root
schema == querya.theme.v1-> custom; - otherwise try VS Code manifest.
- if root
- Extract only metadata:
- id
- name
- type/isDark
- format
- path
- lastModified
- contentHash
- Skip broken files from list or return a disabled/error definition. Prefer disabled/error definition if UI should show it later.
- Do not construct
QueryaTheme. - Do not construct
ThemeData. - Hash file content once during scan.
- Async file IO only.
- Valid custom files appear.
- Valid VS Code files appear.
- Broken file does not crash scan.
- Only
.json/.jsoncare considered.
- temp dir with 2 valid themes and 1 broken;
- stable ordering by name;
- content hash changes when file changes.
Labels: theme, registry
Epic: B
Depends on: TP-12, TP-09
Given a ThemeDefinition, parse the full theme and return ThemeLoadResult.
lib/core/theme/theme_registry_service.darttest/core/theme/theme_registry_service_test.dart
Add:
Future<ThemeLoadResult> loadTheme(ThemeDefinition definition)Behavior:
ThemeFormat.queryaCustom->QueryaThemeManifest.fromJsonString->queryaThemeFromManifest.ThemeFormat.vscode-> existingVsCodeThemeManifest-> existingqueryaThemeFromVsCode.- failure ->
ThemeLoadFailure. - missing file ->
ThemeLoadFailure.
- Custom definition loads to
QueryaTheme. - VS Code definition still loads.
- Missing/deleted file returns failure.
- No app crash on parse failure.
- custom success;
- VS Code success using existing fixture;
- deleted file failure;
- invalid file failure.
Labels: theme, performance, registry
Epic: B
Depends on: TP-13
Avoid repeated file reads and parsing when switching between themes.
lib/core/theme/theme_registry_service.darttest/core/theme/theme_registry_cache_test.dart
Inside ThemeRegistryService:
- cache
QueryaThemebydefinition.stableCacheKey; - max entries: 12 or 20;
- on cache hit, return cached theme;
- on content hash change, key changes naturally;
- expose
clearCache()for tests/reset.
If current project has no LRU helper, implement tiny private LRU using LinkedHashMap.
- Loading same definition twice parses once.
- Loading changed file parses again.
- Cache evicts oldest entry after limit.
- fake parser counter or temp file mutation;
- cache hit;
- cache invalidation by hash;
- eviction.
Labels: theme, storage
Epic: B
Depends on: TP-10
Persist selected registry theme across restarts without storing heavy objects.
lib/core/storage/app_settings.darttest/core/storage/app_settings_test.dart
Add keys:
theme_selected_idtheme_selected_sourcetheme_selected_path
Add methods:
Future<String?> getSelectedThemeId();
Future<void> setSelectedThemeId(String? id);
Future<String?> getSelectedThemeSource();
Future<void> setSelectedThemeSource(String? source);
Future<String?> getSelectedThemePath();
Future<void> setSelectedThemePath(String? path);Keep existing preset/imported settings unchanged.
- Settings roundtrip.
- Clearing selected theme works.
- No SQL workspace revision bump unless existing theme settings already do that intentionally.
- id/source/path roundtrip;
- clear values;
- existing theme preset tests still pass.
Labels: theme, migration, compatibility
Epic: B
Depends on: TP-12, TP-15
Users with existing imported VS Code themes should keep them after registry lands.
lib/core/theme/theme_registry_service.dartlib/core/theme/theme_import_service.dartlib/core/theme/theme_controller.dart- tests as needed.
During registry load:
- check existing persisted import path/name/colors;
- if found, add a
ThemeDefinition:id: legacy-importedorimported;source: legacyImported;format: vscode;path: stored import file;name: importedThemeName ?? "Imported theme".
Do not delete old settings.
- Existing
QueryaThemePreset.importedstill applies. - Legacy imported theme appears in new picker.
- Missing legacy file falls back gracefully.
- fake old imported path -> registry definition exists;
- selected legacy imported theme loads;
- missing old file does not crash.
Labels: theme, controller
Epic: B
Depends on: TP-13, TP-15, TP-16
Make ThemeController aware of registry themes while preserving existing presets.
lib/core/theme/theme_controller.dartlib/core/theme/querya_theme_preset.dart- tests for theme controller.
Add state:
_availableThemes: List<ThemeDefinition>_selectedThemeId: String?_selectedThemePath: String?_selectedThemeLoadError: String?
Add getters:
availableThemesselectedThemeIdselectedThemeLoadError
Add methods:
Future<void> loadAvailableThemes();
Future<void> setThemeById(String id);
Future<ThemeLoadResult> previewThemeById(String id);Behavior:
load()first loads existing mode/preset.- Then load registry definitions async.
- If stored selected id exists, try load it.
- On failure, apply Querya Dark fallback but keep error visible.
- Do not call
notifyListeners()for every discovered file. - Batch registry load and notify once.
previewThemeByIdmust not mutate active app theme.
- Existing
setPreset()behavior still works. - New
setThemeById()applies registry theme. - Broken selected theme falls back to Querya Dark.
previewThemeById()returns theme/result without notifying app listeners.
- old presets still pass;
- select by id persists setting;
- preview does not change
activeTheme; - broken selected id fallback.
Labels: theme, settings, frontend
Epic: C
Depends on: TP-10
Introduce a dedicated picker UI for many themes instead of overloading a small dropdown.
lib/features/settings/theme_picker_button.darttest/features/settings/theme_picker_button_test.dart
Create widget:
class ThemePickerButton extends StatelessWidget {
const ThemePickerButton({
required this.themes,
required this.selectedThemeId,
required this.onSelected,
this.isLoading = false,
});
}Use:
MenuAnchor;- fixed/max popup height 300-360px;
Scrollbar;ListView.builder;- row shows:
- name;
- source badge;
- dark/light icon or label.
- Opens menu with 50+ fake themes without overflow.
- Uses builder list, not
Column(children: themes.map(...)). - Does not parse or apply theme during build.
- pump with 60 definitions;
- open menu;
- visible rows render;
- no exception/overflow in test logs if test harness supports it;
- tap row triggers
onSelected(id).
Labels: theme, settings, frontend
Epic: C
Depends on: TP-18
Make 50+ themes easy to navigate.
lib/features/settings/theme_picker_button.darttest/features/settings/theme_picker_button_test.dart
Inside popup:
- small search input at top;
- local
TextEditingController; - filter by lowercase
name,id,source; - debounce not strictly required for 50 items, but avoid parsing/building themes;
- dispose controller.
- Typing filters list.
- Empty result shows small message.
- Search does not call
ThemeController.setThemeById.
- filter by theme name;
- filter no results;
- clear input restores list.
Labels: theme, settings, performance
Epic: C
Depends on: TP-18, TP-17
Optional visual preview for hovered/selected theme without rebuilding the whole app.
lib/features/settings/theme_preview_card.dartlib/features/settings/theme_picker_button.dart- tests as needed.
Add ThemePreviewCard:
- accepts
QueryaThemeor lightweight preview colors; - displays:
- background;
- surface;
- primary/accent;
- sample text;
- editor background strip.
In picker:
- hover selects preview target id locally;
- debounce 100-150ms before calling
previewThemeById; - preview result stored in local state only;
- never call
setThemeByIdon hover.
- Hovering row does not change app theme.
- Preview card updates after debounce.
- Broken preview shows non-blocking error in card.
- hover/callback does not call
onSelected; - preview future resolves and card updates;
- broken preview shows fallback/error.
Labels: theme, settings, frontend
Epic: C
Depends on: TP-17, TP-18
Replace or extend current Color preset dropdown with registry-backed theme selection.
lib/features/settings/preferences_appearance_section.dartlib/features/settings/theme_picker_button.dart
In Appearance:
- keep
Theme mode; - replace
Color presetrow withThemerow usingThemePickerButton; - include existing Querya Dark/Light as built-in definitions;
- show current imported/registry selected theme;
- call
ThemeController.setThemeById(id)on select; - keep old
Import theme…andReset appearancebuttons.
- If registry unavailable/empty, fallback to current preset dropdown behavior or show Querya Dark/Light only.
- Querya Dark/Light selectable.
- Legacy imported theme selectable if present.
- Selecting registry theme applies immediately.
- Existing reset returns to Querya Dark.
- widget shows built-in themes;
- selecting theme calls controller hook or fake callback;
- reset remains visible;
- import button remains visible.
Labels: theme, settings, filesystem
Epic: C
Depends on: TP-17, TP-21
Let users refresh filesystem themes without restarting the app.
lib/features/settings/preferences_appearance_section.dartlib/core/theme/theme_controller.dart
Add button near import/reset:
Refresh themes- calls
ThemeController.loadAvailableThemes(); - shows small loading state;
- preserves active theme if still available;
- if active theme changed on disk, optionally reload when selected again, not immediately.
- Refresh updates list.
- Broken files do not break Preferences.
- Loading state does not block whole dialog.
- fake controller list changes after refresh;
- button disabled while refreshing.
Labels: theme, filesystem, settings
Epic: D
Depends on: TP-12, TP-21
Make Import theme… add themes to registry instead of only overwriting one imported.json.
lib/core/theme/theme_registry_service.dartlib/core/theme/theme_import_service.dartlib/features/settings/preferences_appearance_section.dart
Add:
Future<ThemeDefinitionImportResult> importThemeFile(String sourcePath)Behavior:
- detect Querya custom vs VS Code;
- validate;
- copy into app support themes directory;
- filename should be stable and safe:
${id}.jsonfor custom;- slugified name for VS Code;
- avoid overwrite:
- if same id/hash exists, reuse;
- if same id different hash, append suffix or replace only after explicit policy;
- return new
ThemeDefinition.
- Importing custom theme adds it to picker.
- Importing VS Code theme still works.
- Multiple imported themes can coexist.
- Old single imported flow still works until fully migrated.
- import custom;
- import VS Code;
- duplicate import same hash;
- duplicate id different content.
Labels: theme, assets, docs
Epic: D
Depends on: TP-12
Ship built-in sample themes in release builds, not only as repository files.
assets/themes/pubspec.yamllib/core/theme/theme_registry_service.dart- tests as feasible.
Move/copy curated themes to:
assets/themes/cyberpunk-neon.json- any other approved built-in themes.
Update pubspec.yaml:
flutter:
assets:
- assets/themes/Registry:
- load built-in asset manifest;
- create
ThemeDefinition(source: ThemeSource.builtin); - load full theme from asset when selected.
- Built-in themes show in picker in release/profile builds.
- App does not depend on repo
themes/samples/path at runtime. - Existing
themes/samples/can remain for docs/manual testing.
- Asset loading if test environment supports bundle.
- Otherwise unit-test parsing with same file content.
Labels: theme, docs, settings
Epic: D
Depends on: TP-11, TP-21
Make filesystem themes discoverable.
docs/theme-custom-json.mddocs/theme-import.mdlib/features/settings/preferences_appearance_section.dart
Docs:
- show actual app support path behavior;
- mention accepted extensions;
- mention refresh/restart.
UI:
- show hint text:
- "Themes are loaded from app support themes folder."
- optional button:
Open themes folder- can be follow-up if cross-platform opening helper does not exist.
- User can understand where to put downloaded themes.
- UI does not promise watcher/live reload if not implemented.
Docs only unless adding button.
Labels: theme, frontend, bitsdojo
Epic: E
Depends on: TP-17
Ensure title bar / window controls follow custom theme background/canvas.
lib/main.dartlib/features/main_screen/main_screen.dart- any title bar/window button widgets.
Find where bitsdojo_window title area and window controls are styled.
Use:
QueryaThemeScope.of(context).workbench.canvasQueryaThemeScope.of(context).workbench.surfaceQueryaThemeScope.of(context).workbench.mutedForeground
Avoid:
- direct singleton reads inside deep widgets when inherited theme is available;
- app-wide notify on hover.
- Switching theme updates title bar background.
- Window buttons remain readable.
- Hover states use theme tokens.
- Widget test if title bar is testable.
- Otherwise manual smoke checklist in PR body:
- dark;
- light;
- custom dark;
- custom light.
Labels: theme, error-handling, stability
Epic: E
Depends on: TP-17
Prevent broken custom themes from breaking app startup.
lib/core/theme/theme_controller.dart- tests for controller.
On ThemeController.load():
- Read selected theme id/path.
- Try registry load.
- If failure:
- set active theme to Querya Dark;
- keep
selectedThemeLoadError; - do not crash;
- do not delete user setting automatically.
- Preferences can show:
- "Selected theme failed to load. Using Querya Dark."
- Missing selected file starts app with Querya Dark.
- Invalid selected file starts app with Querya Dark.
- Error visible in Preferences.
- User can choose another theme and clear error.
- missing file;
- invalid file;
- subsequent valid selection clears error.
Labels: theme, performance, tests
Epic: E
Depends on: TP-18, TP-21
Prevent regression where many themes make Preferences slow or overflow.
test/features/settings/theme_picker_button_test.dart- maybe
test/features/settings/preferences_appearance_section_test.dart
Create 60 fake ThemeDefinition objects.
Test:
- picker opens;
- only visible subset is built if measurable;
- no overflow exception;
- scroll to bottom works;
- select last item works.
If exact build count is hard to assert, assert behavior and no exceptions.
- Test fails if picker uses unbounded
Columnand overflows. - Test passes with
ListView.builder.
Labels: theme, tests, integration
Epic: E
Depends on: TP-21, TP-23
Cover the full import/select path with a fake filesystem theme.
test/features/settings/theme_import_flow_test.dart
Use fake/temp app support path if project test support allows it.
Flow:
- Put custom JSON in temp source.
- Import through service/controller.
- Registry list includes it.
- Select it.
ThemeController.activeThemechanges expected token.- Restart-like reload preserves selection.
- Custom theme can be imported, selected, and restored.
- Test does not depend on real user home directory.
Labels: theme, docs, qa
Epic: E
Depends on: TP-01 through TP-29
Prepare the feature for release and manual verification.
docs/theme-custom-json.mddocs/theme-import.mddocs/release-checklist.mdCHANGELOG.mdwhen release branch is prepared.
Add QA checklist:
- import valid custom dark;
- import valid custom light;
- import VS Code JSONC;
- select among 50+ fake themes or test pack;
- restart app and verify selected theme persists;
- delete selected theme file and restart;
- verify fallback + Preferences error;
- verify title bar/window controls colors;
- verify SQL/JSON highlighting still uses tokenColors.
- Release checklist includes custom theme scenarios.
- Docs include troubleshooting for invalid colors/missing fields.
- CHANGELOG entry can be written from completed issues.
These are intentionally out of the first implementation pass (shipped in 0.4.2). Shipped in 0.4.3 (milestone, epic #159) — see planned-0.4.3.md.
TP-F1 — File watcher for user themes folder (#160)
Use a filesystem watcher to auto-refresh themes after files are added/removed. Keep as follow-up because watchers differ by OS and can introduce lifecycle bugs.
TP-F2 — Theme marketplace metadata (#161)
Support metadata fields like preview image, tags, homepage, license. Useful only after custom theme format is stable.
TP-F3 — Visual theme editor (#162)
Allow editing theme colors in Preferences and export to querya.theme.v1. This is larger than parser/import support.
TP-F4 — Remote theme install (#163)
Install theme from URL. Requires network, trust/security decisions, and probably signature/checksum policy.
- TP-01 docs schema
- TP-02 fixtures
- TP-03 manifest model
- TP-04 color parser wrapper
- TP-05 shadcn color scheme mapping
- TP-06 editor theme mapping
- TP-07 workbench theme mapping
- TP-08 QueryaTheme factory
- TP-09 load result types
- TP-10 ThemeDefinition
- TP-11 theme paths
- TP-12 filesystem scan
- TP-13 load selected definition
- TP-14 parsed theme cache
- TP-15 AppSettings selected theme
- TP-16 legacy imported migration
- TP-17 ThemeController registry integration
- TP-18 ThemePickerButton shell
- TP-19 picker search/filter
- TP-20 safe preview card
- TP-21 Preferences integration
- TP-22 refresh themes action
- TP-23 multi-theme import
- TP-24 built-in theme assets
- TP-25 user theme folder docs
- TP-26 window chrome sync
- TP-27 startup fallback
- TP-28 50+ themes performance test
- TP-29 end-to-end import test
- TP-30 release QA docs