From b3aed0dae98c88abe24b359a8410ac5e5950d4fa Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Thu, 28 May 2026 10:12:57 +0300 Subject: [PATCH] feat(theme): parse VS Code HEX/RGBA color strings Adds parseVsCodeColor for #RGB, #RGBA, #RRGGBB, #RRGGBBAA formats. Closes #53 --- lib/core/theme/parser/color_parser.dart | 47 +++++++++++++++++++ test/core/theme/parser/color_parser_test.dart | 29 ++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 lib/core/theme/parser/color_parser.dart create mode 100644 test/core/theme/parser/color_parser_test.dart diff --git a/lib/core/theme/parser/color_parser.dart b/lib/core/theme/parser/color_parser.dart new file mode 100644 index 00000000..065a1bc8 --- /dev/null +++ b/lib/core/theme/parser/color_parser.dart @@ -0,0 +1,47 @@ +import 'dart:ui'; + +/// Parses VS Code color strings into Flutter [Color]. +Color parseVsCodeColor(String input) { + var s = input.trim(); + if (s.isEmpty) { + throw FormatException('Empty color string'); + } + if (s.startsWith('#')) { + s = s.substring(1); + } + if (s.length == 3) { + final r = s[0]; + final g = s[1]; + final b = s[2]; + s = '$r$r$g$g$b$b'; + return Color(int.parse('FF$s', radix: 16)); + } + if (s.length == 4) { + final r = s[0]; + final g = s[1]; + final b = s[2]; + final a = s[3]; + s = '$r$r$g$g$b$b$a$a'; + return _fromRgbaHex(s); + } + if (s.length == 6) { + return Color(int.parse('FF$s', radix: 16)); + } + if (s.length == 8) { + return _fromRgbaHex(s); + } + throw FormatException('Unsupported color format: $input'); +} + +Color _fromRgbaHex(String eight) { + final rr = eight.substring(0, 2); + final gg = eight.substring(2, 4); + final bb = eight.substring(4, 6); + final aa = eight.substring(6, 8); + return Color.fromARGB( + int.parse(aa, radix: 16), + int.parse(rr, radix: 16), + int.parse(gg, radix: 16), + int.parse(bb, radix: 16), + ); +} diff --git a/test/core/theme/parser/color_parser_test.dart b/test/core/theme/parser/color_parser_test.dart new file mode 100644 index 00000000..78c4fdd9 --- /dev/null +++ b/test/core/theme/parser/color_parser_test.dart @@ -0,0 +1,29 @@ +import 'dart:ui'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/core/theme/parser/color_parser.dart'; + +void main() { + group('parseVsCodeColor', () { + test('6-digit hex', () { + expect(parseVsCodeColor('#1e1e1e'), const Color(0xFF1E1E1E)); + }); + + test('8-digit RRGGBBAA', () { + expect(parseVsCodeColor('#11223344').alpha, 0x44); + }); + + test('3-digit shorthand', () { + expect(parseVsCodeColor('#abc'), const Color(0xFFAABBCC)); + }); + + test('4-digit shorthand with alpha', () { + final c = parseVsCodeColor('#abcd'); + expect(c, isA()); + }); + + test('invalid throws', () { + expect(() => parseVsCodeColor('nope'), throwsFormatException); + }); + }); +}