From f94bb35db7b3341e19bfd5eb2fa7061b2a4beb7e Mon Sep 17 00:00:00 2001 From: mika kuns Date: Mon, 20 Apr 2026 10:24:36 +0200 Subject: [PATCH] feat(ui): tasks island with rows, chips, add-task, selection TaskRowView with status chip (EqStatus converter + parameter), StrikeIfTrue, NotNullToBool converters. TasksIslandView with header, add-task TextBox (Enter=AddCommand), ItemsControl + flat Button for selection. Converters registered in App.axaml. Co-Authored-By: Claude Sonnet 4.6 --- src/ClaudeDo.App/App.axaml | 6 ++ .../Converters/EqStatusConverter.cs | 26 +++++++++ .../Converters/NotNullToBoolConverter.cs | 15 +++++ .../Converters/StrikeIfTrueConverter.cs | 16 ++++++ .../Views/Islands/TaskRowView.axaml | 57 +++++++++++++++++++ .../Views/Islands/TaskRowView.axaml.cs | 8 +++ .../Views/Islands/TasksIslandView.axaml | 43 +++++++++++++- 7 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 src/ClaudeDo.Ui/Converters/EqStatusConverter.cs create mode 100644 src/ClaudeDo.Ui/Converters/NotNullToBoolConverter.cs create mode 100644 src/ClaudeDo.Ui/Converters/StrikeIfTrueConverter.cs create mode 100644 src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml create mode 100644 src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml.cs diff --git a/src/ClaudeDo.App/App.axaml b/src/ClaudeDo.App/App.axaml index c5ca83e..0f53616 100644 --- a/src/ClaudeDo.App/App.axaml +++ b/src/ClaudeDo.App/App.axaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ClaudeDo.App.App" xmlns:local="using:ClaudeDo.App" + xmlns:converters="using:ClaudeDo.Ui.Converters" RequestedThemeVariant="Dark"> @@ -10,6 +11,11 @@ + + + + + diff --git a/src/ClaudeDo.Ui/Converters/EqStatusConverter.cs b/src/ClaudeDo.Ui/Converters/EqStatusConverter.cs new file mode 100644 index 0000000..0ba7ec7 --- /dev/null +++ b/src/ClaudeDo.Ui/Converters/EqStatusConverter.cs @@ -0,0 +1,26 @@ +using System.Globalization; +using Avalonia.Data.Converters; +using ClaudeDo.Data.Models; +using TaskStatus = ClaudeDo.Data.Models.TaskStatus; + +namespace ClaudeDo.Ui.Converters; + +/// +/// Returns true when the bound TaskStatus equals the ConverterParameter string. +/// Usage: Classes.running="{Binding Status, Converter={StaticResource EqStatus}, ConverterParameter=Running}" +/// +public class EqStatusConverter : IValueConverter +{ + public static EqStatusConverter Instance { get; } = new(); + + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is TaskStatus status && parameter is string name && + Enum.TryParse(name, ignoreCase: true, out var target)) + return status == target; + return false; + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + => throw new NotSupportedException(); +} diff --git a/src/ClaudeDo.Ui/Converters/NotNullToBoolConverter.cs b/src/ClaudeDo.Ui/Converters/NotNullToBoolConverter.cs new file mode 100644 index 0000000..fd4604b --- /dev/null +++ b/src/ClaudeDo.Ui/Converters/NotNullToBoolConverter.cs @@ -0,0 +1,15 @@ +using System.Globalization; +using Avalonia.Data.Converters; + +namespace ClaudeDo.Ui.Converters; + +public class NotNullToBoolConverter : IValueConverter +{ + public static NotNullToBoolConverter Instance { get; } = new(); + + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + => value is not null; + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + => throw new NotSupportedException(); +} diff --git a/src/ClaudeDo.Ui/Converters/StrikeIfTrueConverter.cs b/src/ClaudeDo.Ui/Converters/StrikeIfTrueConverter.cs new file mode 100644 index 0000000..c67a396 --- /dev/null +++ b/src/ClaudeDo.Ui/Converters/StrikeIfTrueConverter.cs @@ -0,0 +1,16 @@ +using System.Globalization; +using Avalonia.Data.Converters; +using Avalonia.Media; + +namespace ClaudeDo.Ui.Converters; + +public class StrikeIfTrueConverter : IValueConverter +{ + public static StrikeIfTrueConverter Instance { get; } = new(); + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + => value is true ? TextDecorations.Strikethrough : null; + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + => throw new NotSupportedException(); +} diff --git a/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml b/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml new file mode 100644 index 0000000..9f8242d --- /dev/null +++ b/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml.cs b/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml.cs new file mode 100644 index 0000000..f853cca --- /dev/null +++ b/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml.cs @@ -0,0 +1,8 @@ +using Avalonia.Controls; + +namespace ClaudeDo.Ui.Views.Islands; + +public partial class TaskRowView : UserControl +{ + public TaskRowView() { InitializeComponent(); } +} diff --git a/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml b/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml index d0d86bb..d7e8b2c 100644 --- a/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml +++ b/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml @@ -1,8 +1,47 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +