Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions docs/TALKER_SCREEN_FIXES.md
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions packages/talker_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
43 changes: 43 additions & 0 deletions packages/talker_flutter/example/lib/custom_logs_example.dart
Original file line number Diff line number Diff line change
@@ -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';
}
9 changes: 9 additions & 0 deletions packages/talker_flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -55,6 +56,14 @@ class _BaseExampleState extends State<BaseExample> {
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();
}

Expand Down
8 changes: 8 additions & 0 deletions packages/talker_flutter/lib/src/extensions/talker_data.dart
Original file line number Diff line number Diff line change
@@ -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;
}

Expand All @@ -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);
}
}
24 changes: 23 additions & 1 deletion packages/talker_flutter/lib/src/ui/widgets/data_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class TalkerDataCard extends StatefulWidget {
class _TalkerDataCardState extends State<TalkerDataCard> {
var _expanded = false;

// Threshold for detecting custom generateTextMessage() implementations
static const int _messageLengthThreshold = 50;

@override
void initState() {
_expanded = widget.expanded;
Expand Down Expand Up @@ -180,6 +183,7 @@ class _TalkerDataCardState extends State<TalkerDataCard> {
}

String? get _message {
// For HTTP logs, always use the generated text message which includes formatted content
final isHttpLog = [
TalkerKey.httpError,
TalkerKey.httpRequest,
Expand All @@ -188,7 +192,25 @@ class _TalkerDataCardState extends State<TalkerDataCard> {
if (isHttpLog) {
return widget.data.generateTextMessage();
}
return widget.data.displayMessage;

// 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 rawMessage = widget.data.displayMessage;

// 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 + _messageLengthThreshold) {
return generatedMessage;
}
}

return rawMessage;
}

String? get _errorMessage {
Expand Down
Loading