From 211a3b19e1cf6af40d6cd7cab57a5a3d2d158fab Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 14 Jun 2026 00:11:01 +0300 Subject: [PATCH 1/2] feat(theme): add parseQueryaThemeColor wrapper Normalize Querya custom hex strings and delegate 3/4/6-digit values to parseVsCodeColor; parse 8-digit AARRGGBB alpha-first colors directly. --- lib/core/theme/parser/color_parser.dart | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/core/theme/parser/color_parser.dart b/lib/core/theme/parser/color_parser.dart index b1c7cdc4..38aa0c9d 100644 --- a/lib/core/theme/parser/color_parser.dart +++ b/lib/core/theme/parser/color_parser.dart @@ -33,6 +33,41 @@ Color parseVsCodeColor(String input) { throw FormatException('Unsupported color format: $input'); } +/// Parses Querya custom theme hex strings into Flutter [Color]. +/// +/// Accepts `#RRGGBB`, `RRGGBB`, `#AARRGGBB`, and `AARRGGBB`. Shorthand `#RGB` / +/// `#RGBA` and 6-digit values delegate to [parseVsCodeColor]. Eight-digit values +/// use alpha-first `AARRGGBB` (Querya custom), not VS Code `RRGGBBAA`. +Color parseQueryaThemeColor(String raw) { + final trimmed = raw.trim(); + if (trimmed.isEmpty) { + throw FormatException('Invalid Querya theme color: $raw'); + } + + var s = trimmed; + if (s.startsWith('#')) { + s = s.substring(1); + } + + if (s.length == 8) { + try { + final aa = int.parse(s.substring(0, 2), radix: 16); + final rr = int.parse(s.substring(2, 4), radix: 16); + final gg = int.parse(s.substring(4, 6), radix: 16); + final bb = int.parse(s.substring(6, 8), radix: 16); + return Color.fromARGB(aa, rr, gg, bb); + } on FormatException { + throw FormatException('Invalid Querya theme color: $raw'); + } + } + + try { + return parseVsCodeColor(trimmed.startsWith('#') ? trimmed : '#$s'); + } on FormatException { + throw FormatException('Invalid Querya theme color: $raw'); + } +} + /// Encodes a [Color] as a VS Code hex string (`#RRGGBB` or `#RRGGBBAA`). String formatVsCodeColor(Color color) { String channel(double component) => From 88183ed72604d6648a7ee7046eb360e2f2bd53d4 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 14 Jun 2026 00:11:01 +0300 Subject: [PATCH 2/2] test(theme): cover parseQueryaThemeColor formats and errors Closes #99. --- test/core/theme/parser/color_parser_test.dart | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/test/core/theme/parser/color_parser_test.dart b/test/core/theme/parser/color_parser_test.dart index f928edbc..d7b256f8 100644 --- a/test/core/theme/parser/color_parser_test.dart +++ b/test/core/theme/parser/color_parser_test.dart @@ -2,7 +2,7 @@ import 'dart:ui'; import 'package:flutter_test/flutter_test.dart'; import 'package:querya_desktop/core/theme/parser/color_parser.dart' - show formatVsCodeColor, parseVsCodeColor; + show formatVsCodeColor, parseQueryaThemeColor, parseVsCodeColor; void main() { group('parseVsCodeColor', () { @@ -34,4 +34,70 @@ void main() { expect(parseVsCodeColor(formatVsCodeColor(c)), c); }); }); + + group('parseQueryaThemeColor', () { + test('parses hash-prefixed RRGGBB', () { + expect(parseQueryaThemeColor('#1E1E1E'), const Color(0xFF1E1E1E)); + }); + + test('parses bare RRGGBB', () { + expect(parseQueryaThemeColor('1E1E1E'), const Color(0xFF1E1E1E)); + }); + + test('parses hash-prefixed AARRGGBB', () { + expect(parseQueryaThemeColor('#801E1E1E'), const Color(0x801E1E1E)); + }); + + test('parses bare AARRGGBB', () { + expect(parseQueryaThemeColor('FF1E1E1E'), const Color(0xFF1E1E1E)); + }); + + test('accepts lowercase hex', () { + expect(parseQueryaThemeColor('#ff1e1e1e'), const Color(0xFF1E1E1E)); + expect(parseQueryaThemeColor('1e1e1e'), const Color(0xFF1E1E1E)); + }); + + test('delegates shorthand RGB to parseVsCodeColor', () { + expect(parseQueryaThemeColor('#abc'), const Color(0xFFAABBCC)); + }); + + test('invalid length mentions value', () { + expect( + () => parseQueryaThemeColor('12345'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'Invalid Querya theme color: 12345', + ), + ), + ); + }); + + test('invalid characters mention value', () { + expect( + () => parseQueryaThemeColor('GGHHII'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'Invalid Querya theme color: GGHHII', + ), + ), + ); + }); + + test('empty string mentions value', () { + expect( + () => parseQueryaThemeColor(' '), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'Invalid Querya theme color: ', + ), + ), + ); + }); + }); }