diff --git a/src/ClaudeDo.Ui/Converters/WorkerLogLevelToBrushConverter.cs b/src/ClaudeDo.Ui/Converters/WorkerLogLevelToBrushConverter.cs new file mode 100644 index 0000000..85a3158 --- /dev/null +++ b/src/ClaudeDo.Ui/Converters/WorkerLogLevelToBrushConverter.cs @@ -0,0 +1,45 @@ +using System; +using System.Globalization; +using Avalonia; +using Avalonia.Data.Converters; +using Avalonia.Media; +using ClaudeDo.Data.Models; + +namespace ClaudeDo.Ui.Converters; + +public sealed class WorkerLogLevelToBrushConverter : IValueConverter +{ + private static readonly IBrush SuccessBrush = new SolidColorBrush(Color.Parse("#4CAF50")); + private static readonly IBrush WarnBrush = new SolidColorBrush(Color.Parse("#FFA726")); + private static readonly IBrush ErrorBrush = new SolidColorBrush(Color.Parse("#EF5350")); + private static readonly IBrush InfoFallback = new SolidColorBrush(Color.Parse("#888888")); + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not WorkerLogLevel level) + return AvaloniaProperty.UnsetValue; + + return level switch + { + WorkerLogLevel.Success => SuccessBrush, + WorkerLogLevel.Warn => WarnBrush, + WorkerLogLevel.Error => ErrorBrush, + WorkerLogLevel.Info => ResolveInfoBrush(), + _ => AvaloniaProperty.UnsetValue, + }; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => + throw new NotSupportedException(); + + private static IBrush ResolveInfoBrush() + { + if (Application.Current is { } app && + app.Resources.TryGetResource("TextDimBrush", app.ActualThemeVariant, out var res) && + res is IBrush brush) + { + return brush; + } + return InfoFallback; + } +} diff --git a/tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj b/tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj index ac032c8..e8fd759 100644 --- a/tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj +++ b/tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj @@ -10,6 +10,8 @@ + + diff --git a/tests/ClaudeDo.Ui.Tests/WorkerLogLevelToBrushConverterTests.cs b/tests/ClaudeDo.Ui.Tests/WorkerLogLevelToBrushConverterTests.cs new file mode 100644 index 0000000..303e634 --- /dev/null +++ b/tests/ClaudeDo.Ui.Tests/WorkerLogLevelToBrushConverterTests.cs @@ -0,0 +1,45 @@ +using System.Globalization; +using Avalonia; +using Avalonia.Media; +using ClaudeDo.Data.Models; +using ClaudeDo.Ui.Converters; +using Xunit; + +namespace ClaudeDo.Ui.Tests; + +public class WorkerLogLevelToBrushConverterTests +{ + [Theory] + [InlineData(WorkerLogLevel.Success, "#FF4CAF50")] + [InlineData(WorkerLogLevel.Warn, "#FFFFA726")] + [InlineData(WorkerLogLevel.Error, "#FFEF5350")] + public void Convert_maps_level_to_expected_brush_color(WorkerLogLevel level, string expectedArgb) + { + var converter = new WorkerLogLevelToBrushConverter(); + + var result = converter.Convert(level, typeof(IBrush), null, CultureInfo.InvariantCulture); + + var solid = Assert.IsType(result); + Assert.Equal(expectedArgb.ToLowerInvariant(), $"#{solid.Color.ToUInt32():X8}".ToLowerInvariant()); + } + + [Fact] + public void Convert_info_returns_a_brush_fallback_when_no_app() + { + var converter = new WorkerLogLevelToBrushConverter(); + + var result = converter.Convert(WorkerLogLevel.Info, typeof(IBrush), null, CultureInfo.InvariantCulture); + + Assert.IsAssignableFrom(result); + } + + [Fact] + public void Convert_unknown_value_returns_unset() + { + var converter = new WorkerLogLevelToBrushConverter(); + + var result = converter.Convert("not a level", typeof(IBrush), null, CultureInfo.InvariantCulture); + + Assert.Equal(AvaloniaProperty.UnsetValue, result); + } +}