From 2cb487308f0c70e34eaad0fed8f34a260c0d1474 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:05:42 +0000 Subject: [PATCH 1/6] Initial plan From 0e58af7988fc668461b6236666a24678cd778828 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:15:15 +0000 Subject: [PATCH 2/6] Fix TalkerScreen empty logs and incorrect colors - Modified data_card.dart to use generateTextMessage() for custom logs - Created ansi_color_converter.dart utility to convert AnsiPen to Flutter Colors - Enhanced talker_data.dart extension to try converting pen field when key not in theme Co-authored-by: Frezyx <40857927+Frezyx@users.noreply.github.com> --- .../lib/src/extensions/talker_data.dart | 8 + .../lib/src/ui/widgets/data_card.dart | 16 ++ .../lib/src/utils/ansi_color_converter.dart | 149 ++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 packages/talker_flutter/lib/src/utils/ansi_color_converter.dart diff --git a/packages/talker_flutter/lib/src/extensions/talker_data.dart b/packages/talker_flutter/lib/src/extensions/talker_data.dart index 854b1f755..ad17d12ec 100644 --- a/packages/talker_flutter/lib/src/extensions/talker_data.dart +++ b/packages/talker_flutter/lib/src/extensions/talker_data.dart @@ -1,14 +1,17 @@ import 'package:flutter/material.dart'; import 'package:talker_flutter/talker_flutter.dart'; +import 'package:talker_flutter/src/utils/ansi_color_converter.dart'; extension TalkerDataFlutterExt on TalkerData { /// If [Talker Data][key] field is not provided trying to use color by [LogLevel] + /// If neither key nor logLevel is available, tries to convert the pen color Color getFlutterColor(TalkerScreenTheme theme) { Color? color; if (key != null) { color = theme.logColors[key]; } color ??= _getColorByLogLevel(theme); + color ??= _getColorFromPen(); return color ?? Colors.grey; } @@ -20,4 +23,9 @@ extension TalkerDataFlutterExt on TalkerData { } return null; } + + /// Tries to convert the pen (AnsiPen) to a Flutter Color + Color? _getColorFromPen() { + return AnsiColorConverter.tryConvertAnsiPenToColor(pen); + } } diff --git a/packages/talker_flutter/lib/src/ui/widgets/data_card.dart b/packages/talker_flutter/lib/src/ui/widgets/data_card.dart index a152dce97..ca63b67bf 100644 --- a/packages/talker_flutter/lib/src/ui/widgets/data_card.dart +++ b/packages/talker_flutter/lib/src/ui/widgets/data_card.dart @@ -180,6 +180,7 @@ class _TalkerDataCardState extends State { } String? get _message { + // For HTTP logs, use the generated text message which includes formatted content final isHttpLog = [ TalkerKey.httpError, TalkerKey.httpRequest, @@ -188,6 +189,21 @@ class _TalkerDataCardState extends State { if (isHttpLog) { return widget.data.generateTextMessage(); } + + // Check if this is a custom log that has overridden generateTextMessage() + // by comparing with the default implementation behavior + final generatedMessage = widget.data.generateTextMessage(); + final expectedDefaultMessage = widget.data.displayTitleWithTime() + + widget.data.displayMessage + + widget.data.displayException + + widget.data.displayStackTrace; + + // If the generated message is different from default (custom override exists), + // use it; otherwise use just the display message to avoid duplication + if (generatedMessage != expectedDefaultMessage) { + return generatedMessage; + } + return widget.data.displayMessage; } diff --git a/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart b/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart new file mode 100644 index 000000000..72f4c91ac --- /dev/null +++ b/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart @@ -0,0 +1,149 @@ +import 'package:flutter/material.dart'; +import 'package:talker_flutter/talker_flutter.dart'; + +/// Utility class to convert AnsiPen colors to Flutter Colors +class AnsiColorConverter { + /// Attempts to convert an AnsiPen to a Flutter Color + /// Returns null if conversion is not possible + static Color? tryConvertAnsiPenToColor(AnsiPen? pen) { + if (pen == null) { + return null; + } + + // Try to extract color information from the AnsiPen + // AnsiPen doesn't expose its internal state directly, so we'll + // apply it to a test string and parse the ANSI codes + final testString = 'test'; + final coloredString = pen(testString); + + // If the string hasn't been colored (no ANSI codes), return null + if (coloredString == testString) { + return null; + } + + // Extract ANSI color codes from the colored string + // ANSI format: \x1B[m\x1B[0m + final regex = RegExp(r'\x1B\[([0-9;]+)m'); + final match = regex.firstMatch(coloredString); + + if (match == null) { + return null; + } + + final codes = match.group(1)?.split(';').map(int.tryParse).whereType().toList(); + if (codes == null || codes.isEmpty) { + return null; + } + + // Parse ANSI color codes + // Standard colors: 30-37 (foreground), 90-97 (bright foreground) + // 256 colors: 38;5; + // RGB colors: 38;2;;; + for (int i = 0; i < codes.length; i++) { + final code = codes[i]; + + // Handle 256 color mode: 38;5; + if (code == 38 && i + 2 < codes.length && codes[i + 1] == 5) { + final colorIndex = codes[i + 2]; + return _xterm256ToColor(colorIndex); + } + + // Handle RGB mode: 38;2;;; + if (code == 38 && i + 4 < codes.length && codes[i + 1] == 2) { + final r = codes[i + 2]; + final g = codes[i + 3]; + final b = codes[i + 4]; + return Color.fromRGBO(r, g, b, 1.0); + } + + // Handle standard foreground colors (30-37) + if (code >= 30 && code <= 37) { + return _standardColorToFlutter(code - 30); + } + + // Handle bright foreground colors (90-97) + if (code >= 90 && code <= 97) { + return _brightColorToFlutter(code - 90); + } + } + + return null; + } + + /// Converts standard ANSI color (0-7) to Flutter Color + static Color _standardColorToFlutter(int colorIndex) { + switch (colorIndex) { + case 0: // Black + return const Color(0xFF000000); + case 1: // Red + return const Color.fromARGB(255, 239, 83, 80); + case 2: // Green + return const Color(0xFF26FF3C); + case 3: // Yellow + return const Color.fromARGB(255, 239, 108, 0); + case 4: // Blue + return const Color.fromARGB(255, 66, 165, 245); + case 5: // Magenta + return const Color(0xFFF602C1); + case 6: // Cyan + return const Color(0xFF63FAFE); + case 7: // White + return const Color(0xFFFFFFFF); + default: + return Colors.grey; + } + } + + /// Converts bright ANSI color (0-7) to Flutter Color + static Color _brightColorToFlutter(int colorIndex) { + switch (colorIndex) { + case 0: // Bright Black (Gray) + return const Color.fromARGB(255, 158, 158, 158); + case 1: // Bright Red + return const Color.fromARGB(255, 255, 118, 118); + case 2: // Bright Green + return const Color(0xFF56FEA8); + case 3: // Bright Yellow + return const Color.fromARGB(255, 255, 213, 79); + case 4: // Bright Blue + return const Color.fromARGB(255, 100, 181, 246); + case 5: // Bright Magenta + return const Color(0xFFAF5FFF); + case 6: // Bright Cyan + return const Color(0xFF84FFFF); + case 7: // Bright White + return const Color(0xFFFFFFFF); + default: + return Colors.grey; + } + } + + /// Converts xterm-256 color index to Flutter Color + /// This is a simplified conversion focusing on common colors + static Color _xterm256ToColor(int index) { + // System colors (0-15) + if (index < 8) { + return _standardColorToFlutter(index); + } + if (index < 16) { + return _brightColorToFlutter(index - 8); + } + + // 216 colors (16-231): 6x6x6 RGB cube + if (index < 232) { + final i = index - 16; + final r = ((i / 36).floor() * 255 / 5).round(); + final g = (((i % 36) / 6).floor() * 255 / 5).round(); + final b = ((i % 6) * 255 / 5).round(); + return Color.fromRGBO(r, g, b, 1.0); + } + + // Grayscale (232-255) + if (index < 256) { + final gray = ((index - 232) * 255 / 23).round(); + return Color.fromRGBO(gray, gray, gray, 1.0); + } + + return Colors.grey; + } +} From 60597eea1ff70342e3356beb6c25df0576003a64 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:17:27 +0000 Subject: [PATCH 3/6] Add example custom logs to demonstrate the fixes - Created custom_logs_example.dart with examples of custom logs - Updated main.dart to use the example logs - Demonstrates both generateTextMessage() override and pen color conversion Co-authored-by: Frezyx <40857927+Frezyx@users.noreply.github.com> --- .../example/lib/custom_logs_example.dart | 43 +++++++++++++++++++ packages/talker_flutter/example/lib/main.dart | 9 ++++ 2 files changed, 52 insertions(+) create mode 100644 packages/talker_flutter/example/lib/custom_logs_example.dart diff --git a/packages/talker_flutter/example/lib/custom_logs_example.dart b/packages/talker_flutter/example/lib/custom_logs_example.dart new file mode 100644 index 000000000..9598a8313 --- /dev/null +++ b/packages/talker_flutter/example/lib/custom_logs_example.dart @@ -0,0 +1,43 @@ +import 'package:talker_flutter/talker_flutter.dart'; + +/// Example custom log that overrides generateTextMessage() +/// This demonstrates the fix for empty logs issue +class CustomFormattedLog extends TalkerLog { + CustomFormattedLog(String message, {this.extraData}) : super(message); + + final String? extraData; + + static const logKey = 'custom_formatted_log'; + + @override + String? get key => logKey; + + @override + AnsiPen get pen => AnsiPen()..xterm(121); // Bright green + + @override + String generateTextMessage({TimeFormat timeFormat = TimeFormat.timeAndSeconds}) { + var msg = '[$title] $message'; + if (extraData != null) { + msg += '\nExtra Data: $extraData'; + } + return msg; + } +} + +/// Example custom log that only overrides pen and key +/// This demonstrates the fix for color issue +class CustomColorLog extends TalkerLog { + CustomColorLog(String message) : super(message); + + static const logKey = 'custom_color_log'; + + @override + String? get key => logKey; + + @override + AnsiPen get pen => AnsiPen()..magenta(); // Magenta color + + @override + String get title => 'custom'; +} diff --git a/packages/talker_flutter/example/lib/main.dart b/packages/talker_flutter/example/lib/main.dart index 723f6b231..dd77c105e 100644 --- a/packages/talker_flutter/example/lib/main.dart +++ b/packages/talker_flutter/example/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:talker_example/extended_example/extended_example.dart'; +import 'package:talker_example/custom_logs_example.dart'; import 'package:talker_flutter/talker_flutter.dart'; /// You can see [ExtendedExample] to @@ -55,6 +56,14 @@ class _BaseExampleState extends State { talker.info('2.......'); talker.info('1'); talker.logCustom(YourCustomLog('Custom log message')); + + // Test custom logs with overridden generateTextMessage() and pen + talker.logCustom(CustomFormattedLog( + 'User login attempt', + extraData: 'username: john@example.com', + )); + talker.logCustom(CustomColorLog('Custom colored log without theme entry')); + super.initState(); } From 0ca5b356022145b43953915f443eb2b9cb140f2f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:18:36 +0000 Subject: [PATCH 4/6] Add documentation for TalkerScreen fixes - Created TALKER_SCREEN_FIXES.md with detailed explanation - Updated CHANGELOG.md with fix descriptions - Documented migration guide and examples Co-authored-by: Frezyx <40857927+Frezyx@users.noreply.github.com> --- docs/TALKER_SCREEN_FIXES.md | 115 +++++++++++++++++++++++++++ packages/talker_flutter/CHANGELOG.md | 5 ++ 2 files changed, 120 insertions(+) create mode 100644 docs/TALKER_SCREEN_FIXES.md diff --git a/docs/TALKER_SCREEN_FIXES.md b/docs/TALKER_SCREEN_FIXES.md new file mode 100644 index 000000000..b220bc83d --- /dev/null +++ b/docs/TALKER_SCREEN_FIXES.md @@ -0,0 +1,115 @@ +# TalkerScreen Custom Log Fixes + +This document describes the fixes implemented for TalkerScreen color and log display issues. + +## Issues Fixed + +### 1. Empty Logs for Custom Logs +**Problem**: When creating a custom log that overrides `generateTextMessage()`, the TalkerScreen would display empty log entries because it only used `generateTextMessage()` for HTTP logs. + +**Solution**: Modified `data_card.dart` to detect when a custom log has overridden `generateTextMessage()` by comparing the generated output with the default implementation. If different, it uses the custom implementation. + +**Example**: +```dart +class CustomLog extends TalkerLog { + CustomLog(String message) : super(message); + + @override + String generateTextMessage({TimeFormat timeFormat = TimeFormat.timeAndSeconds}) { + return '[$title] $message\nExtra: some data'; + } +} +``` + +This log will now display its formatted message in TalkerScreen. + +### 2. Incorrect Colors for Custom Logs +**Problem**: When creating a custom log that overrides the `pen` property, the colors were not displayed correctly in TalkerScreen because the UI only looked up colors by `key` in `TalkerScreenTheme.logColors`. + +**Solution**: +1. Created `AnsiColorConverter` utility that converts `AnsiPen` terminal colors to Flutter `Color` objects +2. Enhanced `getFlutterColor()` to use the converted pen color as a fallback when the key is not found in the theme + +**Example**: +```dart +class CustomColorLog extends TalkerLog { + CustomColorLog(String message) : super(message); + + @override + AnsiPen get pen => AnsiPen()..magenta(); + + @override + String? get key => 'custom_log'; +} +``` + +This log will now display in magenta color in TalkerScreen even if `'custom_log'` is not defined in `TalkerScreenTheme.logColors`. + +## How It Works + +### Color Lookup Priority +The color for a log in TalkerScreen is now determined in this order: +1. Look up by `key` in `TalkerScreenTheme.logColors` +2. Look up by `logLevel` (converted to key) +3. Convert `pen` (AnsiPen) to Flutter Color +4. Default to `Colors.grey` + +### AnsiPen to Color Conversion +The `AnsiColorConverter` supports: +- Standard ANSI colors (red, green, blue, yellow, cyan, magenta, white, black) +- Bright ANSI colors +- xterm 256 color palette +- RGB colors + +The converter parses ANSI escape codes from the pen and maps them to appropriate Flutter Color values. + +## Migration Guide + +### Before (Required Two Configurations) +```dart +// Configure colors for console +final talker = TalkerFlutter.init( + settings: TalkerSettings( + colors: { + 'my_log': AnsiPen()..green(), + }, + ), +); + +// Also configure colors for UI +TalkerScreen( + talker: talker, + theme: TalkerScreenTheme( + logColors: { + 'my_log': Colors.green, + }, + ), +) +``` + +### After (Only One Configuration Needed) +```dart +// Configure colors for console (will be automatically used in UI) +final talker = TalkerFlutter.init( + settings: TalkerSettings( + colors: { + 'my_log': AnsiPen()..green(), + }, + ), +); + +// No need to duplicate color configuration +TalkerScreen( + talker: talker, + theme: TalkerScreenTheme(), // Uses pen color automatically +) +``` + +You can still override colors in `TalkerScreenTheme.logColors` if you want different colors in the UI vs console. + +## Files Changed + +- `packages/talker_flutter/lib/src/ui/widgets/data_card.dart` - Enhanced `_message` getter +- `packages/talker_flutter/lib/src/extensions/talker_data.dart` - Enhanced `getFlutterColor()` method +- `packages/talker_flutter/lib/src/utils/ansi_color_converter.dart` - New utility class +- `packages/talker_flutter/example/lib/custom_logs_example.dart` - Example custom logs diff --git a/packages/talker_flutter/CHANGELOG.md b/packages/talker_flutter/CHANGELOG.md index 7510f2b8f..d1897890c 100644 --- a/packages/talker_flutter/CHANGELOG.md +++ b/packages/talker_flutter/CHANGELOG.md @@ -1,3 +1,8 @@ +# Unreleased +- [talker_flutter] Fix TalkerScreen displaying empty logs for custom logs with overridden generateTextMessage() +- [talker_flutter] Fix TalkerScreen colors for custom logs by converting AnsiPen to Flutter Colors +- [talker_flutter] Add AnsiColorConverter utility for automatic pen color conversion + # 5.1.5 - [talker_grpc_logger] Update dependency grpc to v5 From 5f423c13a5491867f951c960a256e1ba83d895f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:20:28 +0000 Subject: [PATCH 5/6] Address code review feedback - Improved custom log detection heuristic to be more robust - Made color definitions consistent using Color(0xFFxxx) format - Added caching to AnsiColorConverter to improve performance Co-authored-by: Frezyx <40857927+Frezyx@users.noreply.github.com> --- .../lib/src/ui/widgets/data_card.dart | 27 +++++++------ .../lib/src/utils/ansi_color_converter.dart | 40 ++++++++++++++----- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/packages/talker_flutter/lib/src/ui/widgets/data_card.dart b/packages/talker_flutter/lib/src/ui/widgets/data_card.dart index ca63b67bf..ce049056b 100644 --- a/packages/talker_flutter/lib/src/ui/widgets/data_card.dart +++ b/packages/talker_flutter/lib/src/ui/widgets/data_card.dart @@ -180,7 +180,7 @@ class _TalkerDataCardState extends State { } String? get _message { - // For HTTP logs, use the generated text message which includes formatted content + // For HTTP logs, always use the generated text message which includes formatted content final isHttpLog = [ TalkerKey.httpError, TalkerKey.httpRequest, @@ -190,21 +190,24 @@ class _TalkerDataCardState extends State { return widget.data.generateTextMessage(); } - // Check if this is a custom log that has overridden generateTextMessage() - // by comparing with the default implementation behavior + // For custom logs that override generateTextMessage(), detect by checking + // if the generated message differs significantly from just the raw message. + // This is a heuristic approach that works for most common cases. final generatedMessage = widget.data.generateTextMessage(); - final expectedDefaultMessage = widget.data.displayTitleWithTime() + - widget.data.displayMessage + - widget.data.displayException + - widget.data.displayStackTrace; + final rawMessage = widget.data.displayMessage; - // If the generated message is different from default (custom override exists), - // use it; otherwise use just the display message to avoid duplication - if (generatedMessage != expectedDefaultMessage) { - return generatedMessage; + // If the generated message contains additional content beyond just the raw message + // (excluding title/time which are shown separately), use the generated message + if (rawMessage.isNotEmpty && generatedMessage.contains(rawMessage)) { + // Check if generated message has additional content beyond title/time/message + // by looking for newlines or additional text + if (generatedMessage.contains('\n') || + generatedMessage.length > rawMessage.length + 50) { + return generatedMessage; + } } - return widget.data.displayMessage; + return rawMessage; } String? get _errorMessage { diff --git a/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart b/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart index 72f4c91ac..573c0c121 100644 --- a/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart +++ b/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart @@ -3,6 +3,9 @@ import 'package:talker_flutter/talker_flutter.dart'; /// Utility class to convert AnsiPen colors to Flutter Colors class AnsiColorConverter { + // Cache to avoid repeated conversions of the same pen + static final Map _cache = {}; + /// Attempts to convert an AnsiPen to a Flutter Color /// Returns null if conversion is not possible static Color? tryConvertAnsiPenToColor(AnsiPen? pen) { @@ -10,14 +13,20 @@ class AnsiColorConverter { return null; } + // Check cache first + if (_cache.containsKey(pen)) { + return _cache[pen]; + } + // Try to extract color information from the AnsiPen - // AnsiPen doesn't expose its internal state directly, so we'll + // AnsiPen doesn't expose its internal state directly, so we // apply it to a test string and parse the ANSI codes final testString = 'test'; final coloredString = pen(testString); // If the string hasn't been colored (no ANSI codes), return null if (coloredString == testString) { + _cache[pen] = null; return null; } @@ -27,18 +36,27 @@ class AnsiColorConverter { final match = regex.firstMatch(coloredString); if (match == null) { + _cache[pen] = null; return null; } final codes = match.group(1)?.split(';').map(int.tryParse).whereType().toList(); if (codes == null || codes.isEmpty) { + _cache[pen] = null; return null; } // Parse ANSI color codes - // Standard colors: 30-37 (foreground), 90-97 (bright foreground) - // 256 colors: 38;5; - // RGB colors: 38;2;;; + final color = _parseAnsiCodes(codes); + _cache[pen] = color; + return color; + } + + /// Parse ANSI color codes to extract color + /// Standard colors: 30-37 (foreground), 90-97 (bright foreground) + /// 256 colors: 38;5; + /// RGB colors: 38;2;;; + static Color? _parseAnsiCodes(List codes) { for (int i = 0; i < codes.length; i++) { final code = codes[i]; @@ -76,13 +94,13 @@ class AnsiColorConverter { case 0: // Black return const Color(0xFF000000); case 1: // Red - return const Color.fromARGB(255, 239, 83, 80); + return const Color(0xFFEF5350); case 2: // Green return const Color(0xFF26FF3C); case 3: // Yellow - return const Color.fromARGB(255, 239, 108, 0); + return const Color(0xFFEF6C00); case 4: // Blue - return const Color.fromARGB(255, 66, 165, 245); + return const Color(0xFF42A5F5); case 5: // Magenta return const Color(0xFFF602C1); case 6: // Cyan @@ -98,15 +116,15 @@ class AnsiColorConverter { static Color _brightColorToFlutter(int colorIndex) { switch (colorIndex) { case 0: // Bright Black (Gray) - return const Color.fromARGB(255, 158, 158, 158); + return const Color(0xFF9E9E9E); case 1: // Bright Red - return const Color.fromARGB(255, 255, 118, 118); + return const Color(0xFFFF7676); case 2: // Bright Green return const Color(0xFF56FEA8); case 3: // Bright Yellow - return const Color.fromARGB(255, 255, 213, 79); + return const Color(0xFFFFD54F); case 4: // Bright Blue - return const Color.fromARGB(255, 100, 181, 246); + return const Color(0xFF64B5F6); case 5: // Bright Magenta return const Color(0xFFAF5FFF); case 6: // Bright Cyan From 4205a5fe9f98a25275692032b32707e609af03e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:24:23 +0000 Subject: [PATCH 6/6] Address final code review feedback - Added named constants for magic numbers - Extracted color mappings to static const maps - Improved code maintainability and readability Co-authored-by: Frezyx <40857927+Frezyx@users.noreply.github.com> --- .../lib/src/ui/widgets/data_card.dart | 5 +- .../lib/src/utils/ansi_color_converter.dart | 74 ++++++++----------- 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/packages/talker_flutter/lib/src/ui/widgets/data_card.dart b/packages/talker_flutter/lib/src/ui/widgets/data_card.dart index ce049056b..9f90b9afb 100644 --- a/packages/talker_flutter/lib/src/ui/widgets/data_card.dart +++ b/packages/talker_flutter/lib/src/ui/widgets/data_card.dart @@ -29,6 +29,9 @@ class TalkerDataCard extends StatefulWidget { class _TalkerDataCardState extends State { var _expanded = false; + // Threshold for detecting custom generateTextMessage() implementations + static const int _messageLengthThreshold = 50; + @override void initState() { _expanded = widget.expanded; @@ -202,7 +205,7 @@ class _TalkerDataCardState extends State { // Check if generated message has additional content beyond title/time/message // by looking for newlines or additional text if (generatedMessage.contains('\n') || - generatedMessage.length > rawMessage.length + 50) { + generatedMessage.length > rawMessage.length + _messageLengthThreshold) { return generatedMessage; } } diff --git a/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart b/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart index 573c0c121..47b0da29c 100644 --- a/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart +++ b/packages/talker_flutter/lib/src/utils/ansi_color_converter.dart @@ -3,9 +3,36 @@ import 'package:talker_flutter/talker_flutter.dart'; /// Utility class to convert AnsiPen colors to Flutter Colors class AnsiColorConverter { + // Test string used to extract ANSI color codes + static const String _testString = 'test'; + // Cache to avoid repeated conversions of the same pen static final Map _cache = {}; + // Standard ANSI color mappings + static const Map _standardColors = { + 0: Color(0xFF000000), // Black + 1: Color(0xFFEF5350), // Red + 2: Color(0xFF26FF3C), // Green + 3: Color(0xFFEF6C00), // Yellow + 4: Color(0xFF42A5F5), // Blue + 5: Color(0xFFF602C1), // Magenta + 6: Color(0xFF63FAFE), // Cyan + 7: Color(0xFFFFFFFF), // White + }; + + // Bright ANSI color mappings + static const Map _brightColors = { + 0: Color(0xFF9E9E9E), // Bright Black (Gray) + 1: Color(0xFFFF7676), // Bright Red + 2: Color(0xFF56FEA8), // Bright Green + 3: Color(0xFFFFD54F), // Bright Yellow + 4: Color(0xFF64B5F6), // Bright Blue + 5: Color(0xFFAF5FFF), // Bright Magenta + 6: Color(0xFF84FFFF), // Bright Cyan + 7: Color(0xFFFFFFFF), // Bright White + }; + /// Attempts to convert an AnsiPen to a Flutter Color /// Returns null if conversion is not possible static Color? tryConvertAnsiPenToColor(AnsiPen? pen) { @@ -21,11 +48,10 @@ class AnsiColorConverter { // Try to extract color information from the AnsiPen // AnsiPen doesn't expose its internal state directly, so we // apply it to a test string and parse the ANSI codes - final testString = 'test'; - final coloredString = pen(testString); + final coloredString = pen(_testString); // If the string hasn't been colored (no ANSI codes), return null - if (coloredString == testString) { + if (coloredString == _testString) { _cache[pen] = null; return null; } @@ -90,50 +116,12 @@ class AnsiColorConverter { /// Converts standard ANSI color (0-7) to Flutter Color static Color _standardColorToFlutter(int colorIndex) { - switch (colorIndex) { - case 0: // Black - return const Color(0xFF000000); - case 1: // Red - return const Color(0xFFEF5350); - case 2: // Green - return const Color(0xFF26FF3C); - case 3: // Yellow - return const Color(0xFFEF6C00); - case 4: // Blue - return const Color(0xFF42A5F5); - case 5: // Magenta - return const Color(0xFFF602C1); - case 6: // Cyan - return const Color(0xFF63FAFE); - case 7: // White - return const Color(0xFFFFFFFF); - default: - return Colors.grey; - } + return _standardColors[colorIndex] ?? Colors.grey; } /// Converts bright ANSI color (0-7) to Flutter Color static Color _brightColorToFlutter(int colorIndex) { - switch (colorIndex) { - case 0: // Bright Black (Gray) - return const Color(0xFF9E9E9E); - case 1: // Bright Red - return const Color(0xFFFF7676); - case 2: // Bright Green - return const Color(0xFF56FEA8); - case 3: // Bright Yellow - return const Color(0xFFFFD54F); - case 4: // Bright Blue - return const Color(0xFF64B5F6); - case 5: // Bright Magenta - return const Color(0xFFAF5FFF); - case 6: // Bright Cyan - return const Color(0xFF84FFFF); - case 7: // Bright White - return const Color(0xFFFFFFFF); - default: - return Colors.grey; - } + return _brightColors[colorIndex] ?? Colors.grey; } /// Converts xterm-256 color index to Flutter Color