Dragging a task row onto a user list in the Lists island now reassigns it to that list. The task drag holds the pointer capture, so the release is resolved geometrically (new case between the Mission Control and reorder cases) instead of going through the Lists island's own DragDrop path, which never sees a DragEventArgs during a task drag. TaskRepository.MoveToListAsync reassigns the task plus every descendant (a child must never sit in a different list than its parent) and appends the task at the end of the target list. Guards: running tasks and tasks holding an Active/Kept worktree are rejected to the footer error strip; a move that changes repo asks for confirmation naming both repos. The source repo is read from the task's own list rather than the island's current list, which is a smart/virtual list with no working dir of its own whenever one of those is shown.
213 lines
11 KiB
XML
213 lines
11 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:converters="using:ClaudeDo.Ui.Converters"
|
|
xmlns:loc="using:ClaudeDo.Ui.Localization"
|
|
x:Class="ClaudeDo.Ui.Views.Islands.ListsIslandView"
|
|
x:DataType="vm:ListsIslandViewModel">
|
|
<DockPanel LastChildFill="True">
|
|
|
|
<!-- ── Header ── -->
|
|
<Border DockPanel.Dock="Top" Classes="island-header">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock Classes="heading" Text="{loc:Tr lists.heading}"/>
|
|
|
|
<!-- Search row -->
|
|
<Border Classes="search-wrap" Margin="0,8,0,12">
|
|
<Grid ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center">
|
|
<PathIcon Grid.Column="0" Width="14" Height="14"
|
|
Data="{StaticResource Icon.Search}"
|
|
Foreground="{DynamicResource TextFaintBrush}"
|
|
Margin="2,0,0,0"/>
|
|
<TextBox Grid.Column="1" x:Name="SearchBox" Classes="search-inner"
|
|
PlaceholderText="{loc:Tr lists.searchPlaceholder}"
|
|
Text="{Binding SearchText, Mode=TwoWay}"/>
|
|
<Border Grid.Column="2" Classes="kbd" Margin="0,0,2,0">
|
|
<TextBlock Text="{loc:Tr lists.searchKbd}"/>
|
|
</Border>
|
|
</Grid>
|
|
</Border>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- ── Footer ── -->
|
|
<Border DockPanel.Dock="Bottom"
|
|
BorderBrush="{DynamicResource LineBrush}" BorderThickness="0,1,0,0"
|
|
Padding="12,10">
|
|
<Grid ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center">
|
|
<!-- Avatar circle -->
|
|
<Border Grid.Column="0" Classes="avatar-circle"
|
|
VerticalAlignment="Center">
|
|
<TextBlock Classes="eyebrow"
|
|
Text="{Binding UserInitials}"
|
|
FontWeight="SemiBold"
|
|
Foreground="{DynamicResource DeepBrush}"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
</Border>
|
|
<!-- Name + machine -->
|
|
<StackPanel Grid.Column="1" Margin="8,0" Spacing="1" VerticalAlignment="Center">
|
|
<TextBlock Classes="title" Text="{Binding UserName}"/>
|
|
<TextBlock Classes="meta" Text="{Binding MachineNameLocal}"/>
|
|
</StackPanel>
|
|
<!-- Settings button -->
|
|
<Button Grid.Column="2" Classes="icon-btn" VerticalAlignment="Center"
|
|
Command="{Binding OpenSettingsCommand}"
|
|
ToolTip.Tip="{loc:Tr lists.settingsTip}">
|
|
<PathIcon Data="{StaticResource Icon.Settings}"
|
|
Width="15" Height="15"
|
|
Foreground="{DynamicResource TextMuteBrush}"/>
|
|
</Button>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- ── Scrollable body ── -->
|
|
<ScrollViewer>
|
|
<StackPanel Margin="6,0,6,4">
|
|
|
|
<!-- SMART LISTS section -->
|
|
<TextBlock Classes="section-label" Text="{loc:Tr lists.smartListsLabel}" Margin="10,10,10,4"/>
|
|
<ItemsControl ItemsSource="{Binding SmartLists}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate DataType="vm:ListNavItemViewModel">
|
|
<Border Classes="list-item" Classes.active="{Binding IsActive}"
|
|
Tapped="OnItemTapped">
|
|
<Grid ColumnDefinitions="20,*,Auto">
|
|
<!-- Left accent bar for active state -->
|
|
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
|
Background="Transparent"
|
|
CornerRadius="8" IsHitTestVisible="False"
|
|
IsVisible="{Binding IsActive}">
|
|
<Border Width="2" Height="16"
|
|
Background="{DynamicResource AccentBrush}"
|
|
CornerRadius="1"
|
|
HorizontalAlignment="Left" VerticalAlignment="Center"
|
|
Margin="-8,0,0,0"/>
|
|
</Border>
|
|
<!-- Icon -->
|
|
<PathIcon Grid.Column="0" Classes="list-icon"
|
|
Width="14" Height="14"
|
|
Data="{Binding IconKey, Converter={StaticResource IconKey}}"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
<!-- Name -->
|
|
<TextBlock Grid.Column="1" Classes="list-label"
|
|
Text="{Binding Name}"
|
|
VerticalAlignment="Center" Margin="8,0"
|
|
Foreground="{DynamicResource TextDimBrush}" FontSize="{StaticResource FontSizeBody}"/>
|
|
<!-- Count -->
|
|
<TextBlock Grid.Column="2" Classes="list-count"
|
|
Text="{Binding Count}"/>
|
|
</Grid>
|
|
</Border>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
|
|
<!-- MY LISTS section -->
|
|
<TextBlock Classes="section-label" Text="{loc:Tr lists.myListsLabel}" Margin="10,10,10,4"/>
|
|
<ItemsControl ItemsSource="{Binding UserLists}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate DataType="vm:ListNavItemViewModel">
|
|
<Grid RowDefinitions="Auto,Auto,Auto">
|
|
|
|
<!-- Above-row drop indicator -->
|
|
<Border Grid.Row="0" Height="2" VerticalAlignment="Center" Margin="4,0"
|
|
Background="{DynamicResource MossBrush}" CornerRadius="1"
|
|
IsVisible="{Binding DropHintAbove}"/>
|
|
|
|
<Border Grid.Row="1" Classes="list-item" Classes.active="{Binding IsActive}"
|
|
Classes.drop-target="{Binding IsTaskDropTarget}"
|
|
Tapped="OnItemTapped"
|
|
DragDrop.AllowDrop="True"
|
|
DragDrop.DragOver="OnListDragOver"
|
|
DragDrop.Drop="OnListDrop">
|
|
<Border.ContextMenu>
|
|
<ContextMenu>
|
|
<MenuItem Header="{loc:Tr lists.contextSettings}"
|
|
Command="{Binding $parent[UserControl].((vm:ListsIslandViewModel)DataContext).OpenListSettingsCommand}"
|
|
CommandParameter="{Binding}"/>
|
|
<MenuItem Header="{loc:Tr lists.contextWorktrees}"
|
|
Command="{Binding $parent[UserControl].((vm:ListsIslandViewModel)DataContext).OpenWorktreesOverviewCommand}"
|
|
CommandParameter="{Binding}"/>
|
|
<Separator IsVisible="{Binding WorkingDir, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
|
<MenuItem Header="{loc:Tr lists.contextOpenExplorer}"
|
|
IsVisible="{Binding WorkingDir, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
|
Command="{Binding $parent[UserControl].((vm:ListsIslandViewModel)DataContext).OpenInExplorerCommand}"
|
|
CommandParameter="{Binding}"/>
|
|
<MenuItem Header="{loc:Tr lists.contextOpenTerminal}"
|
|
IsVisible="{Binding WorkingDir, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
|
Command="{Binding $parent[UserControl].((vm:ListsIslandViewModel)DataContext).OpenInTerminalCommand}"
|
|
CommandParameter="{Binding}"/>
|
|
<Separator IsVisible="{Binding WorkingDir, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
|
<MenuItem Header="{loc:Tr lists.contextLetClaude}"
|
|
IsVisible="{Binding WorkingDir, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
|
Command="{Binding $parent[UserControl].((vm:ListsIslandViewModel)DataContext).LetClaudeHandleListCommand}"
|
|
CommandParameter="{Binding}"/>
|
|
</ContextMenu>
|
|
</Border.ContextMenu>
|
|
<Grid ColumnDefinitions="20,*,Auto">
|
|
<!-- Left accent bar for active state -->
|
|
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
|
Background="Transparent"
|
|
CornerRadius="8" IsHitTestVisible="False"
|
|
IsVisible="{Binding IsActive}">
|
|
<Border Width="2" Height="16"
|
|
Background="{DynamicResource AccentBrush}"
|
|
CornerRadius="1"
|
|
HorizontalAlignment="Left" VerticalAlignment="Center"
|
|
Margin="-8,0,0,0"/>
|
|
</Border>
|
|
<!-- Color dot (6px circle, color from DotColorKey) -->
|
|
<Ellipse Grid.Column="0"
|
|
Width="6" Height="6"
|
|
Fill="{Binding DotColorKey, Converter={StaticResource DotBrush}}"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
<!-- Name -->
|
|
<TextBlock Grid.Column="1" Classes="list-label"
|
|
Text="{Binding Name}"
|
|
VerticalAlignment="Center" Margin="8,0"
|
|
Foreground="{DynamicResource TextDimBrush}" FontSize="{StaticResource FontSizeBody}"/>
|
|
<!-- Count -->
|
|
<TextBlock Grid.Column="2" Classes="list-count"
|
|
Text="{Binding Count}"/>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- Below-row drop indicator (last item only) -->
|
|
<Border Grid.Row="2" Height="2" VerticalAlignment="Center" Margin="4,0"
|
|
Background="{DynamicResource MossBrush}" CornerRadius="1"
|
|
IsVisible="{Binding DropHintBelow}"/>
|
|
</Grid>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
|
|
<!-- New list + import row -->
|
|
<Grid ColumnDefinitions="*,Auto" Margin="0,4,0,0">
|
|
<Button Grid.Column="0" Classes="new-list-btn"
|
|
Command="{Binding CreateListCommand}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<PathIcon Data="{StaticResource Icon.Plus}"
|
|
Width="13" Height="13"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
VerticalAlignment="Center"/>
|
|
<TextBlock Classes="body"
|
|
Text="{loc:Tr lists.newList}"
|
|
Foreground="{DynamicResource TextMuteBrush}"
|
|
VerticalAlignment="Center"/>
|
|
</StackPanel>
|
|
</Button>
|
|
<Button Grid.Column="1" Classes="icon-btn" Margin="6,0,0,0"
|
|
Command="{Binding OpenRepoImportCommand}"
|
|
ToolTip.Tip="{loc:Tr lists.addReposTip}">
|
|
<PathIcon Data="{StaticResource Icon.Folder}"
|
|
Width="14" Height="14"
|
|
Foreground="{DynamicResource TextMuteBrush}"/>
|
|
</Button>
|
|
</Grid>
|
|
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
</DockPanel>
|
|
</UserControl>
|