Shift+Enter did nothing because AcceptsReturn was only set from a style setter and never reached the box. Setting it on the element is half the fix: TextBox.OnKeyDown consumes Enter regardless of modifiers and runs before any bubbling handler, so the split chain would have died in its place. Enter is now taken in the tunnel phase and Shift+Enter is left to the box. Alongside, the notes list stops borrowing furniture it has no use for: no "0 open tasks" subtitle, no show-completed and list-settings buttons, and no details pane beside it — the editor spans that column instead of leaving it empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
180 lines
9.3 KiB
XML
180 lines
9.3 KiB
XML
<UserControl xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:vm="using:ClaudeDo.Ui.ViewModels.Islands"
|
|
xmlns:islands="using:ClaudeDo.Ui.Views.Islands"
|
|
xmlns:uiconverters="using:ClaudeDo.Ui.Converters"
|
|
xmlns:ctl="using:ClaudeDo.Ui.Views.Controls"
|
|
xmlns:loc="using:ClaudeDo.Ui.Localization"
|
|
x:Class="ClaudeDo.Ui.Views.Islands.TasksIslandView"
|
|
x:DataType="vm:TasksIslandViewModel">
|
|
<DockPanel LastChildFill="True">
|
|
|
|
<!-- Header -->
|
|
<Border DockPanel.Dock="Top" Classes="island-header">
|
|
<Grid ColumnDefinitions="*,Auto">
|
|
<StackPanel Grid.Column="0" Spacing="4">
|
|
<TextBlock Classes="eyebrow" Text="{Binding HeaderEyebrow}"/>
|
|
<TextBlock Classes="display"
|
|
Text="{Binding HeaderTitle}"
|
|
TextTrimming="CharacterEllipsis"/>
|
|
<TextBlock Classes="meta"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
Text="{Binding Subtitle}"
|
|
TextTrimming="CharacterEllipsis"/>
|
|
<ctl:OperationIndicator Status="{Binding PlanningOperation}"/>
|
|
</StackPanel>
|
|
|
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="4"
|
|
VerticalAlignment="Top">
|
|
<Border Classes="kbd" VerticalAlignment="Center" Margin="0,0,6,0"
|
|
IsVisible="{Binding HasStatusPill}">
|
|
<TextBlock Text="{Binding StatusPill}"/>
|
|
</Border>
|
|
<Button Classes="icon-btn" Classes.active="{Binding IsShowingCompleted}"
|
|
IsVisible="{Binding !IsNotesList}"
|
|
Command="{Binding ToggleShowCompletedCommand}"
|
|
ToolTip.Tip="{loc:Tr tasks.showCompletedTip}">
|
|
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.Eye}"/>
|
|
</Button>
|
|
<Button Classes="icon-btn" IsVisible="{Binding IsLetClaudeVisible}"
|
|
Command="{Binding LetClaudeHandleCommand}" ToolTip.Tip="{loc:Tr tasks.letClaudeTip}">
|
|
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.AgentSuggested}"/>
|
|
</Button>
|
|
<Button Classes="icon-btn" IsVisible="{Binding IsMergeReviewsVisible}"
|
|
Command="{Binding MergeReviewsCommand}" ToolTip.Tip="{loc:Tr tasks.mergeReviewsTip}">
|
|
<!-- Icon.GitBranch is line-art: stroke-rendered, PathIcon would fill the lines away -->
|
|
<Viewbox Width="16" Height="16">
|
|
<Path Classes="icon-stroke" Data="{StaticResource Icon.GitBranch}"/>
|
|
</Viewbox>
|
|
</Button>
|
|
<Button Classes="icon-btn" IsVisible="{Binding IsQuickClaudeVisible}"
|
|
Command="{Binding OpenQuickClaudeSessionCommand}" ToolTip.Tip="{loc:Tr tasks.quickClaudeTip}">
|
|
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.ArrowOut}"/>
|
|
</Button>
|
|
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
|
|
Command="{Binding ClearDayCommand}" ToolTip.Tip="{loc:Tr tasks.clearDayTip}">
|
|
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.Broom}"/>
|
|
</Button>
|
|
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
|
|
Command="{Binding ShowPrepLogCommand}" ToolTip.Tip="{loc:Tr tasks.planMyDayTip}">
|
|
<Viewbox Width="18" Height="18">
|
|
<Path Classes="icon-stroke" Data="{StaticResource Icon.PlanDay}"/>
|
|
</Viewbox>
|
|
</Button>
|
|
<Button Classes="icon-btn" IsVisible="{Binding !IsNotesList}"
|
|
Command="{Binding OpenListSettingsCommand}" ToolTip.Tip="{loc:Tr tasks.listSettingsTip}">
|
|
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.Settings}"/>
|
|
</Button>
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- Add-task row -->
|
|
<Border DockPanel.Dock="Top" Classes="add-task" Margin="16,14,16,8"
|
|
IsVisible="{Binding !IsNotesList}">
|
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
|
<Border Grid.Column="0" Classes="add-task-plus" VerticalAlignment="Center">
|
|
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.Plus}"
|
|
Foreground="{DynamicResource TextFaintBrush}"/>
|
|
</Border>
|
|
<TextBox Grid.Column="1" x:Name="AddTaskBox" Classes="add-task-input"
|
|
PlaceholderText="{loc:Tr tasks.addPlaceholder}"
|
|
Text="{Binding NewTaskTitle, Mode=TwoWay}"
|
|
VerticalAlignment="Center"
|
|
Margin="12,0,0,0">
|
|
<TextBox.KeyBindings>
|
|
<KeyBinding Gesture="Enter" Command="{Binding AddCommand}"/>
|
|
</TextBox.KeyBindings>
|
|
</TextBox>
|
|
<Border Grid.Column="2" Classes="kbd kbd-enter" VerticalAlignment="Center"
|
|
IsVisible="{Binding #AddTaskBox.IsFocused}">
|
|
<TextBlock Text="{loc:Tr tasks.enterKey}"/>
|
|
</Border>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- Task list: one flat, virtualized ListBox. Rows is HeaderRow | TaskRowViewModel — group
|
|
headers are regular entries, not a separate ItemsControl per section, so a
|
|
VirtualizingStackPanel actually bounds the realized container count.
|
|
Inset lives on the panel, NOT on the ListBox: Avalonia 12 leaves ScrollViewer.Padding
|
|
out of the Extent, so at max scroll the last row would sit below the viewport and stay
|
|
unreachable. -->
|
|
<Panel>
|
|
<ListBox x:Name="RowsListBox"
|
|
IsVisible="{Binding !IsNotesList}"
|
|
ItemsSource="{Binding Rows}"
|
|
Background="Transparent"
|
|
BorderThickness="0">
|
|
<ListBox.ItemsPanel>
|
|
<ItemsPanelTemplate>
|
|
<VirtualizingStackPanel Margin="10,4"/>
|
|
</ItemsPanelTemplate>
|
|
</ListBox.ItemsPanel>
|
|
<ListBox.Styles>
|
|
<!-- SelectedItem is never bound — selection is handled entirely by the inner row Button's
|
|
SelectCommand, mirroring the pre-virtualization ItemsControl. Avalonia's ListBox has
|
|
no "no selection" mode, so neutralize the app-wide selected/pointerover
|
|
ContentPresenter overlay (App.axaml) instead of letting it double up with
|
|
TaskRowView's own hover/selected style. -->
|
|
<Style Selector="ListBoxItem">
|
|
<Setter Property="Padding" Value="0"/>
|
|
<Setter Property="MinHeight" Value="0"/>
|
|
<Setter Property="CornerRadius" Value="0"/>
|
|
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
|
<Setter Property="Focusable" Value="{Binding Converter={x:Static uiconverters:NotHeaderRowConverter.Instance}}"/>
|
|
</Style>
|
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent"/>
|
|
</Style>
|
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent"/>
|
|
</Style>
|
|
</ListBox.Styles>
|
|
<ListBox.DataTemplates>
|
|
<DataTemplate DataType="vm:HeaderRow">
|
|
<Grid ColumnDefinitions="*,Auto" Margin="14,14,14,6">
|
|
<TextBlock Grid.Column="0" Classes="eyebrow section-label"
|
|
Classes.overdue="{Binding IsOverdue}"
|
|
Text="{Binding Label}" VerticalAlignment="Center"/>
|
|
<Button Grid.Column="1" Classes="icon-btn" IsVisible="{Binding HasAction}"
|
|
Command="{Binding ActionCommand}"
|
|
ToolTip.Tip="{loc:Tr tasks.clearCompletedTip}"
|
|
VerticalAlignment="Center">
|
|
<PathIcon Classes="danger" Data="{StaticResource Icon.Trash}" Width="13" Height="13"/>
|
|
</Button>
|
|
</Grid>
|
|
</DataTemplate>
|
|
<DataTemplate DataType="vm:TaskRowViewModel">
|
|
<Button Classes="flat" HorizontalAlignment="Stretch"
|
|
HorizontalContentAlignment="Stretch"
|
|
Command="{Binding $parent[ListBox].((vm:TasksIslandViewModel)DataContext).SelectCommand}"
|
|
CommandParameter="{Binding}">
|
|
<islands:TaskRowView/>
|
|
</Button>
|
|
</DataTemplate>
|
|
</ListBox.DataTemplates>
|
|
</ListBox>
|
|
|
|
<!-- Empty state: shown below the add-task row once the list has zero visible tasks. -->
|
|
<StackPanel IsVisible="{Binding IsTasksEmptyHintVisible}"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center"
|
|
MaxWidth="260" Spacing="6" IsHitTestVisible="False">
|
|
<TextBlock Text="{loc:Tr tasks.emptyHint}"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
TextAlignment="Center" TextWrapping="Wrap"/>
|
|
<TextBlock IsVisible="{Binding IsTasksEmptyRepoHintVisible}"
|
|
Classes="meta"
|
|
Text="{loc:Tr tasks.emptyHintNoWorkingDir}"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
TextAlignment="Center" TextWrapping="Wrap"/>
|
|
</StackPanel>
|
|
|
|
<!-- The notes list is not a task list: same island slot, different content. -->
|
|
<Panel IsVisible="{Binding IsNotesList}">
|
|
<islands:NotesEditorView DataContext="{Binding Notes}"/>
|
|
</Panel>
|
|
</Panel>
|
|
|
|
</DockPanel>
|
|
</UserControl>
|