Add Explorer Workbench with hierarchical, off-UI Storage analysis.

Storage queries run in the background with cancellation and covering indexes so switching views no longer freezes the UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-22 12:43:05 +02:00
commit e9aba73552
130 changed files with 15110 additions and 0 deletions

View File

@@ -0,0 +1,630 @@
<Window x:Class="Explorer.App.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Explorer.Presentation.ViewModels;assembly=Explorer.Presentation"
xmlns:local="clr-namespace:Explorer.App"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
Title="Explorer Workbench"
Icon="pack://application:,,,/Assets/explorer-workbench.ico"
Height="820" Width="1280"
MinHeight="500" MinWidth="800"
Background="{DynamicResource Bg}"
Foreground="{DynamicResource Fg}"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
ResizeMode="CanResize"
UseLayoutRounding="True"
SnapsToDevicePixels="True"
PreviewKeyDown="OnPreviewKeyDown">
<shell:WindowChrome.WindowChrome>
<shell:WindowChrome CaptionHeight="40"
ResizeBorderThickness="6"
GlassFrameThickness="0"
CornerRadius="0"
UseAeroCaptionButtons="False"/>
</shell:WindowChrome.WindowChrome>
<DockPanel>
<Border DockPanel.Dock="Top" Height="40" Background="{DynamicResource Panel}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="0,0,0,1"
MouseLeftButtonDown="OnTitleBarMouseDown">
<Grid>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="12,0,0,0" IsHitTestVisible="False">
<Image Width="20" Height="20" Margin="0,0,8,0" VerticalAlignment="Center"
RenderOptions.BitmapScalingMode="HighQuality"
Source="pack://application:,,,/Assets/explorer-workbench-20.png"/>
<TextBlock Text="Explorer Workbench" FontWeight="SemiBold" VerticalAlignment="Center" Foreground="{DynamicResource Fg}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Style="{StaticResource CaptionButton}" Content="─" Click="OnMinimize" ToolTip="Minimize"/>
<Button x:Name="MaxRestoreButton" Style="{StaticResource CaptionButton}" Content="☐" Click="OnMaxRestore" ToolTip="Maximize"/>
<Button Style="{StaticResource CaptionCloseButton}" Content="✕" Click="OnCloseWindow" ToolTip="Close"/>
</StackPanel>
</Grid>
</Border>
<Border DockPanel.Dock="Top" Background="{DynamicResource Panel}" BorderBrush="{DynamicResource Stroke}" BorderThickness="0,0,0,1" Padding="8">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="280"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<Button Content="←" Command="{Binding BackCommand}" Width="36" Margin="0,0,4,0" ToolTip="Back (Alt+Left)"/>
<Button Content="→" Command="{Binding ForwardCommand}" Width="36" Margin="0,0,4,0" ToolTip="Forward (Alt+Right)"/>
<Button Content="↑" Command="{Binding UpCommand}" Width="36" Margin="0,0,4,0" ToolTip="Up (Alt+Up)"/>
<Button Content="↻" Command="{Binding RefreshCommand}" Width="36" Margin="0,0,12,0" ToolTip="Refresh (F5)"/>
<Button Content="New tab" Command="{Binding NewTabCommand}" Margin="0,0,4,0"/>
<Button Content="Split" Command="{Binding SplitCommand}" Margin="0,0,4,0"/>
<Button Content="Index" Command="{Binding BuildIndexCommand}" Margin="0,0,4,0"/>
<Button Content="Details" Command="{Binding SetViewCommand}" CommandParameter="Details" Margin="8,0,4,0"/>
<Button Content="List" Command="{Binding SetViewCommand}" CommandParameter="List" Margin="0,0,4,0"/>
<Button Content="Preview" Command="{Binding SetViewCommand}" CommandParameter="Preview"/>
</StackPanel>
<ComboBox Grid.Column="1" Margin="12,0" Style="{StaticResource PathComboBox}"
ItemsSource="{Binding PathHistory}"
Text="{Binding PathText, UpdateSourceTrigger=PropertyChanged}"
PreviewKeyDown="OnPathKeyDown"
SelectionChanged="OnPathHistorySelected"/>
<TextBox Grid.Column="2" Text="{Binding Search.Text, UpdateSourceTrigger=PropertyChanged}"
KeyDown="OnSearchKeyDown"/>
<StackPanel Grid.Column="3" Orientation="Horizontal" Margin="8,0,0,0">
<Button Content="Search" Command="{Binding SearchCommand}" Margin="0,0,4,0"/>
<Button Content="Theme" Command="{Binding ToggleThemeCommand}"/>
</StackPanel>
</Grid>
</Border>
<Border DockPanel.Dock="Bottom" Background="{DynamicResource Panel}" BorderBrush="{DynamicResource Stroke}" BorderThickness="0,1,0,0" Padding="8,6">
<Grid>
<TextBlock Text="{Binding Footer}" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<ItemsControl ItemsSource="{Binding Transfers.Jobs}" Margin="0,0,12,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,10,0">
<TextBlock VerticalAlignment="Center" FontSize="11" Foreground="{DynamicResource FgMuted}"
Text="{Binding Op, StringFormat={}{0}:}"/>
<TextBlock VerticalAlignment="Center" FontSize="11" Margin="4,0,0,0" Text="{Binding Status}"/>
<Button Margin="6,0,0,0" Padding="6,2" FontSize="11"
Content="{Binding Status, Converter={StaticResource TransferAction}}"
Command="{Binding DataContext.CancelTransferCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Storage" Command="{Binding Analysis.OpenCommand}" Margin="0,0,6,0"/>
<Button Content="Duplicates" Command="{Binding Duplicates.OpenCommand}" Margin="0,0,6,0"/>
<Button Content="Add network" Click="OnAddNetwork" Margin="0,0,6,0"/>
<Button Content="Add OneDrive" Click="OnAddOneDrive"/>
</StackPanel>
</Grid>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="260" MinWidth="160"/>
<ColumnDefinition Width="6"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Background="{DynamicResource Panel}">
<TextBlock DockPanel.Dock="Top" Margin="12,10,12,6" FontWeight="SemiBold" Foreground="{DynamicResource Fg}" Text="Locations"/>
<TreeView x:Name="NavTree" ItemsSource="{Binding Tree.Roots}"
SelectedItemChanged="OnTreeSelected"
TreeViewItem.Expanded="OnTreeExpanded"
HorizontalContentAlignment="Stretch">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock FontFamily="{StaticResource Symbol}" Text="{Binding Glyph}" Margin="0,0,8,0" Foreground="{DynamicResource Accent}"/>
<TextBlock Text="{Binding Label}" Foreground="{DynamicResource Fg}"/>
<TextBlock Text="{Binding Status}" Margin="8,0,0,0" Foreground="{DynamicResource FgMuted}" FontSize="11"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</DockPanel>
<GridSplitter Grid.Column="1" Width="6" HorizontalAlignment="Stretch" Background="{DynamicResource Stroke}"/>
<DockPanel Grid.Column="2" LastChildFill="True">
<TabControl x:Name="Tabs" ItemsSource="{Binding Tabs}" SelectedItem="{Binding ActiveTab}"
SelectionChanged="OnTabChanged"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" MinWidth="120">
<TextBlock Text="⋮" Margin="0,0,8,0" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center"/>
<TextBlock Text="{Binding Title}" Margin="0,0,8,0" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" MaxWidth="160"/>
<Button Content="×" Padding="4,0" MinWidth="22" Click="OnCloseTab" Tag="{Binding}"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid Loaded="OnPaneSplitLoaded"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="0"/>
<ColumnDefinition Width="0" MinWidth="0"/>
<ColumnDefinition Width="0" MinWidth="0"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" DataContext="{Binding Left}" Style="{StaticResource PaneChrome}"
PreviewMouseDown="OnPaneChromeMouseDown">
<DockPanel LastChildFill="True">
<ContentControl DockPanel.Dock="Top" Content="{Binding}" ContentTemplate="{StaticResource PaneAddressBar}"
Focusable="False"/>
<Border DockPanel.Dock="Top" Background="{DynamicResource Banner}" Padding="10,8"
Visibility="{Binding ShowIndexBanner, Converter={StaticResource BoolVis}}">
<DockPanel>
<Button DockPanel.Dock="Right" Content="Build index" Click="OnBuildIndex"/>
<TextBlock Text="{Binding IndexBannerText}" TextWrapping="Wrap" VerticalAlignment="Center"
Foreground="{DynamicResource Fg}"/>
</DockPanel>
</Border>
<Grid>
<ListView ItemsSource="{Binding Items}"
MouseDoubleClick="OnItemDoubleClick"
SelectionChanged="OnSelectionChanged"
AllowDrop="True"
PreviewMouseLeftButtonDown="OnListMouseDown"
Drop="OnListDrop"
DragOver="OnListDragOver"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
GotFocus="OnPaneFocus"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
local:ListViewLayout.StretchFirstColumn="True"
Visibility="{Binding ViewMode, Converter={StaticResource ViewDetails}}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" CellTemplate="{StaticResource NameWithIcon}"/>
<GridViewColumn Header="Date modified" Width="148" DisplayMemberBinding="{Binding ModifiedLabel}"/>
<GridViewColumn Header="Type" Width="100" DisplayMemberBinding="{Binding TypeLabel}"/>
<GridViewColumn Header="Size" Width="110" DisplayMemberBinding="{Binding SizeLabel}"/>
</GridView>
</ListView.View>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" Click="OnCtxOpen"/>
<Separator/>
<MenuItem Header="Cut" Command="{Binding DataContext.CutCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Copy" Command="{Binding DataContext.CopyCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Paste" Command="{Binding DataContext.PasteCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Delete" Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Rename" Click="OnCtxRename"/>
<Separator/>
<MenuItem Header="New folder" Command="{Binding DataContext.NewFolderCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Copy path" Command="{Binding DataContext.CopyPathCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<Separator/>
<MenuItem Header="Refresh" Command="{Binding DataContext.RefreshCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Rescan folder" Command="{Binding DataContext.RescanFolderCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<Separator Visibility="{Binding DataContext.ShowCloudPin, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolVis}}"/>
<MenuItem Header="Always keep on this device"
Command="{Binding DataContext.PinCloudCommand, RelativeSource={RelativeSource AncestorType=Window}}"
Visibility="{Binding DataContext.ShowCloudPin, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolVis}}"/>
<MenuItem Header="Free up space"
Command="{Binding DataContext.FreeUpCloudSpaceCommand, RelativeSource={RelativeSource AncestorType=Window}}"
Visibility="{Binding DataContext.ShowCloudDehydrate, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolVis}}"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
<ListView ItemsSource="{Binding Items}"
MouseDoubleClick="OnItemDoubleClick"
SelectionChanged="OnSelectionChanged"
AllowDrop="True"
PreviewMouseLeftButtonDown="OnListMouseDown"
Drop="OnListDrop"
DragOver="OnListDragOver"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
GotFocus="OnPaneFocus"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
local:ListViewLayout.StretchFirstColumn="True"
Visibility="{Binding ViewMode, Converter={StaticResource ViewList}}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" CellTemplate="{StaticResource NameWithIcon}"/>
</GridView>
</ListView.View>
</ListView>
<ListView ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource PreviewTile}"
ItemContainerStyle="{StaticResource IconListItem}"
MouseDoubleClick="OnItemDoubleClick"
SelectionChanged="OnSelectionChanged"
AllowDrop="True"
PreviewMouseLeftButtonDown="OnListMouseDown"
Drop="OnListDrop"
DragOver="OnListDragOver"
GotFocus="OnPaneFocus"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Left"
Visibility="{Binding ViewMode, Converter={StaticResource ViewPreview}}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=ScrollViewer}}"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
</DockPanel>
</Border>
<GridSplitter Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ResizeBehavior="PreviousAndNext"
Background="{DynamicResource Stroke}"
Visibility="{Binding IsSplit, Converter={StaticResource BoolVis}}"
DragCompleted="OnSplitDragCompleted"/>
<Border Grid.Column="2"
DataContext="{Binding Right}"
Style="{StaticResource PaneChrome}"
PreviewMouseDown="OnPaneChromeMouseDown"
Visibility="{Binding DataContext.IsSplit, RelativeSource={RelativeSource AncestorType=Grid}, Converter={StaticResource BoolVis}}">
<DockPanel LastChildFill="True">
<ContentControl DockPanel.Dock="Top" Content="{Binding}" ContentTemplate="{StaticResource PaneAddressBar}"
Focusable="False"/>
<Border DockPanel.Dock="Top" Background="{DynamicResource Banner}" Padding="10,8"
Visibility="{Binding ShowIndexBanner, Converter={StaticResource BoolVis}}">
<DockPanel>
<Button DockPanel.Dock="Right" Content="Build index" Click="OnBuildIndex"/>
<TextBlock Text="{Binding IndexBannerText}" TextWrapping="Wrap" VerticalAlignment="Center"
Foreground="{DynamicResource Fg}"/>
</DockPanel>
</Border>
<Grid>
<ListView ItemsSource="{Binding Items}"
MouseDoubleClick="OnItemDoubleClick"
SelectionChanged="OnSelectionChanged"
AllowDrop="True"
PreviewMouseLeftButtonDown="OnListMouseDown"
Drop="OnListDrop"
DragOver="OnListDragOver"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
GotFocus="OnPaneFocus"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
local:ListViewLayout.StretchFirstColumn="True"
Visibility="{Binding ViewMode, Converter={StaticResource ViewDetails}}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" CellTemplate="{StaticResource NameWithIcon}"/>
<GridViewColumn Header="Date modified" Width="148" DisplayMemberBinding="{Binding ModifiedLabel}"/>
<GridViewColumn Header="Type" Width="100" DisplayMemberBinding="{Binding TypeLabel}"/>
<GridViewColumn Header="Size" Width="110" DisplayMemberBinding="{Binding SizeLabel}"/>
</GridView>
</ListView.View>
</ListView>
<ListView ItemsSource="{Binding Items}"
MouseDoubleClick="OnItemDoubleClick"
SelectionChanged="OnSelectionChanged"
AllowDrop="True"
PreviewMouseLeftButtonDown="OnListMouseDown"
Drop="OnListDrop"
DragOver="OnListDragOver"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
GotFocus="OnPaneFocus"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
local:ListViewLayout.StretchFirstColumn="True"
Visibility="{Binding ViewMode, Converter={StaticResource ViewList}}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" CellTemplate="{StaticResource NameWithIcon}"/>
</GridView>
</ListView.View>
</ListView>
<ListView ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource PreviewTile}"
ItemContainerStyle="{StaticResource IconListItem}"
MouseDoubleClick="OnItemDoubleClick"
SelectionChanged="OnSelectionChanged"
AllowDrop="True"
PreviewMouseLeftButtonDown="OnListMouseDown"
Drop="OnListDrop"
DragOver="OnListDragOver"
GotFocus="OnPaneFocus"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Left"
Visibility="{Binding ViewMode, Converter={StaticResource ViewPreview}}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=ScrollViewer}}"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
</DockPanel>
</Border>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</DockPanel>
<Border Grid.Column="2" Background="#99000000" Visibility="{Binding Search.IsOpen, Converter={StaticResource BoolVis}}">
<Border Background="{DynamicResource Panel}" BorderBrush="{DynamicResource Stroke}" BorderThickness="1" Margin="40" Padding="16">
<DockPanel>
<DockPanel DockPanel.Dock="Top" LastChildFill="True" Margin="0,0,0,12">
<Button DockPanel.Dock="Right" Content="Close" Click="OnCloseSearch" Margin="8,0,0,0"/>
<TextBlock Text="Search" FontSize="18" FontWeight="SemiBold" Foreground="{DynamicResource Fg}" VerticalAlignment="Center"/>
</DockPanel>
<Grid DockPanel.Dock="Top" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="220"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Name" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center" Margin="0,0,8,8"/>
<TextBox Grid.Column="1" Margin="0,0,16,8" Text="{Binding Search.Text, UpdateSourceTrigger=PropertyChanged}"
KeyDown="OnSearchKeyDown"/>
<TextBlock Grid.Column="2" Text="Scope" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center" Margin="0,0,8,8"/>
<ComboBox Grid.Column="3" Margin="0,0,0,8"
ItemsSource="{Binding Search.ScopeChoices}"
DisplayMemberPath="Label"
SelectedValuePath="Kind"
SelectedValue="{Binding Search.Scope}"/>
<TextBlock Grid.Row="1" Text="Extension" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center" Margin="0,0,8,0"/>
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" Margin="0,0,16,0">
<TextBox Width="90" Text="{Binding Search.Extension, UpdateSourceTrigger=PropertyChanged}"/>
<CheckBox Content="Files" Margin="16,0,8,0" VerticalAlignment="Center" Foreground="{DynamicResource Fg}"
IsChecked="{Binding Search.FilesOnly}"/>
<CheckBox Content="Folders" VerticalAlignment="Center" Foreground="{DynamicResource Fg}"
IsChecked="{Binding Search.FoldersOnly}"/>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="2" Text="Size" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center" Margin="0,0,8,0"/>
<StackPanel Grid.Row="1" Grid.Column="3" Orientation="Horizontal">
<TextBox Width="90" Margin="0,0,8,0" Text="{Binding Search.MinSizeText, UpdateSourceTrigger=PropertyChanged}"
ToolTip="Minimum size, e.g. 10MB"/>
<TextBox Width="90" Text="{Binding Search.MaxSizeText, UpdateSourceTrigger=PropertyChanged}"
ToolTip="Maximum size, e.g. 1GB"/>
</StackPanel>
</Grid>
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
<Button DockPanel.Dock="Right" Content="Search" Command="{Binding SearchCommand}"/>
<TextBlock Text="{Binding Search.Status}" Foreground="{DynamicResource Fg}" VerticalAlignment="Center"/>
</DockPanel>
<ProgressBar DockPanel.Dock="Top" Margin="0,0,0,8" IsIndeterminate="True"
Visibility="{Binding Search.IsBusy, Converter={StaticResource BoolVis}}"/>
<ListView ItemsSource="{Binding Search.Results}" MouseDoubleClick="OnSearchDoubleClick"
VirtualizingPanel.IsVirtualizing="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
Background="{DynamicResource Panel}" Foreground="{DynamicResource Fg}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="220" CellTemplate="{StaticResource NameWithIcon}"/>
<GridViewColumn Header="Path" Width="420" DisplayMemberBinding="{Binding FullPath}"/>
<GridViewColumn Header="Size" Width="100" DisplayMemberBinding="{Binding SizeLabel}"/>
</GridView>
</ListView.View>
</ListView>
</DockPanel>
</Border>
</Border>
<Border Grid.Column="2" Background="#99000000" Visibility="{Binding Analysis.IsOpen, Converter={StaticResource BoolVis}}">
<Border Background="{DynamicResource Panel}" BorderBrush="{DynamicResource Stroke}" BorderThickness="1" Margin="24" Padding="16">
<DockPanel>
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,12">
<Button DockPanel.Dock="Right" Content="Close" Command="{Binding Analysis.CloseCommand}"/>
<TextBlock Text="Storage" FontSize="18" FontWeight="SemiBold" Foreground="{DynamicResource Fg}" VerticalAlignment="Center"/>
</DockPanel>
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
<TextBlock DockPanel.Dock="Left" Text="Location" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center" Margin="0,0,8,0"/>
<ComboBox DockPanel.Dock="Left" ItemsSource="{Binding Analysis.Scopes}" SelectedItem="{Binding Analysis.SelectedScope}"
DisplayMemberPath="Label" Width="220" Margin="0,0,16,0"/>
<TextBlock DockPanel.Dock="Left" Text="View" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center" Margin="0,0,8,0"/>
<ComboBox DockPanel.Dock="Left" ItemsSource="{Binding Analysis.Pages}" SelectedItem="{Binding Analysis.Page}" Width="150" Margin="0,0,16,0"/>
<TextBlock Text="{Binding Analysis.Status}" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center"/>
</DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="0,0,0,10">
<Button Content="Open" Command="{Binding OpenStorageHereCommand}" Margin="0,0,6,0" IsEnabled="{Binding Analysis.CanAct}"/>
<Button Content="Open in other pane" Command="{Binding OpenStorageOtherCommand}" Margin="0,0,6,0"
IsEnabled="{Binding Analysis.CanAct}"
Visibility="{Binding ActiveTab.IsSplit, Converter={StaticResource BoolVis}}"/>
<Button Content="Open in new tab" Command="{Binding OpenStorageTabCommand}" Margin="0,0,6,0" IsEnabled="{Binding Analysis.CanAct}"/>
<Button Content="Search here" Command="{Binding SearchStorageCommand}" Margin="0,0,6,0" IsEnabled="{Binding Analysis.CanAct}"/>
<Button Content="Rescan" Command="{Binding RescanStorageCommand}" Margin="0,0,6,0" IsEnabled="{Binding Analysis.CanAct}"/>
<Button Content="Copy path" Command="{Binding CopyStoragePathCommand}" IsEnabled="{Binding Analysis.CanAct}"/>
</WrapPanel>
<ProgressBar DockPanel.Dock="Top" Margin="0,0,0,8" Height="4" IsIndeterminate="True"
IsHitTestVisible="False"
Visibility="{Binding Analysis.IsBusy, Converter={StaticResource BoolVis}}"/>
<Grid>
<Grid Visibility="{Binding Analysis.IsTree, Converter={StaticResource BoolVis}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Margin="6,0,22,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="170"/>
<ColumnDefinition Width="220"/>
<ColumnDefinition Width="88"/>
<ColumnDefinition Width="72"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name" Foreground="{DynamicResource FgMuted}"/>
<TextBlock Grid.Column="1" Text="Contents" Foreground="{DynamicResource FgMuted}"/>
<TextBlock Grid.Column="2" Text="Relative size" Foreground="{DynamicResource FgMuted}" Margin="8,0"/>
<TextBlock Grid.Column="3" Text="Size" HorizontalAlignment="Right" Foreground="{DynamicResource FgMuted}"/>
<TextBlock Grid.Column="4" Text="State" Margin="8,0,0,0" Foreground="{DynamicResource FgMuted}"/>
</Grid>
<ListView Grid.Row="1" ItemsSource="{Binding Analysis.VisibleNodes}"
SelectedItem="{Binding Analysis.SelectedNode}"
MouseDoubleClick="OnStorageTreeDoubleClick"
ItemContainerStyle="{StaticResource PlainListItem}"
Background="{DynamicResource Panel}" Foreground="{DynamicResource Fg}"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.CanContentScroll="True">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="170"/>
<ColumnDefinition Width="220"/>
<ColumnDefinition Width="88"/>
<ColumnDefinition Width="72"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Margin="{Binding Indent, Converter={StaticResource Indent}}">
<Grid Width="18" Height="18" Margin="0,0,6,0">
<Button Width="18" Height="18" Padding="0"
Command="{Binding DataContext.Analysis.ToggleNodeCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding}"
Visibility="{Binding CanExpand, Converter={StaticResource BoolVis}}">
<TextBlock FontSize="11" Foreground="{DynamicResource FgMuted}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="▸"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded}" Value="True">
<Setter Property="Text" Value="▾"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
</Grid>
<TextBlock FontFamily="{StaticResource Symbol}" Text="{Binding Glyph}" FontSize="14"
Foreground="{DynamicResource Accent}" Margin="0,0,8,0" VerticalAlignment="Center"/>
<TextBlock Text="{Binding Name}" Foreground="{DynamicResource Fg}" TextTrimming="CharacterEllipsis"
VerticalAlignment="Center" ToolTip="{Binding FullPath}"/>
</StackPanel>
<TextBlock Grid.Column="1" Text="{Binding CountLabel}" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center"/>
<ProgressBar Grid.Column="2" Style="{StaticResource StorageSizeBar}" Value="{Binding Fraction}"
ToolTip="{Binding SizeLabel}"/>
<TextBlock Grid.Column="3" Text="{Binding SizeLabel}" HorizontalAlignment="Right" Foreground="{DynamicResource Fg}" VerticalAlignment="Center"/>
<TextBlock Grid.Column="4" Text="{Binding State}" Margin="8,0,0,0" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center"
Visibility="{Binding HasState, Converter={StaticResource BoolVis}}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" Command="{Binding DataContext.OpenStorageHereCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Open in other pane" Command="{Binding DataContext.OpenStorageOtherCommand, RelativeSource={RelativeSource AncestorType=Window}}"
Visibility="{Binding DataContext.ActiveTab.IsSplit, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolVis}}"/>
<MenuItem Header="Open in new tab" Command="{Binding DataContext.OpenStorageTabCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Search within this location" Command="{Binding DataContext.SearchStorageCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Rescan this location" Command="{Binding DataContext.RescanStorageCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Copy path" Command="{Binding DataContext.CopyStoragePathCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
</Grid>
<Grid Visibility="{Binding Analysis.IsRanking, Converter={StaticResource BoolVis}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Margin="6,0,22,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="140"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="88"/>
<ColumnDefinition Width="72"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name" Foreground="{DynamicResource FgMuted}"/>
<TextBlock Grid.Column="1" Text="Location" Foreground="{DynamicResource FgMuted}" Margin="8,0"/>
<TextBlock Grid.Column="2" Text="Contents" Foreground="{DynamicResource FgMuted}"/>
<TextBlock Grid.Column="3" Text="Relative size" Foreground="{DynamicResource FgMuted}" Margin="8,0"/>
<TextBlock Grid.Column="4" Text="Size" HorizontalAlignment="Right" Foreground="{DynamicResource FgMuted}"/>
<TextBlock Grid.Column="5" Text="State" Margin="8,0,0,0" Foreground="{DynamicResource FgMuted}"/>
</Grid>
<ListView Grid.Row="1" ItemsSource="{Binding Analysis.Rows}"
SelectedItem="{Binding Analysis.SelectedRow}"
MouseDoubleClick="OnStorageRankDoubleClick"
ItemContainerStyle="{StaticResource PlainListItem}"
Background="{DynamicResource Panel}" Foreground="{DynamicResource Fg}"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.CanContentScroll="True">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="140"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="88"/>
<ColumnDefinition Width="72"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Foreground="{DynamicResource Fg}" TextTrimming="CharacterEllipsis"
VerticalAlignment="Center" ToolTip="{Binding Path}"/>
<TextBlock Grid.Column="1" Text="{Binding ShortPath}" Foreground="{DynamicResource FgMuted}"
TextTrimming="CharacterEllipsis" VerticalAlignment="Center" Margin="8,0" ToolTip="{Binding Path}"/>
<TextBlock Grid.Column="2" Text="{Binding CountLabel}" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center"/>
<ProgressBar Grid.Column="3" Style="{StaticResource StorageSizeBar}" Value="{Binding Fraction}"
ToolTip="{Binding SizeLabel}"/>
<TextBlock Grid.Column="4" Text="{Binding SizeLabel}" HorizontalAlignment="Right" Foreground="{DynamicResource Fg}" VerticalAlignment="Center"/>
<TextBlock Grid.Column="5" Text="{Binding State}" Margin="8,0,0,0" Foreground="{DynamicResource FgMuted}" VerticalAlignment="Center"
Visibility="{Binding HasState, Converter={StaticResource BoolVis}}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" Command="{Binding DataContext.OpenStorageHereCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Open in other pane" Command="{Binding DataContext.OpenStorageOtherCommand, RelativeSource={RelativeSource AncestorType=Window}}"
Visibility="{Binding DataContext.ActiveTab.IsSplit, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolVis}}"/>
<MenuItem Header="Open in new tab" Command="{Binding DataContext.OpenStorageTabCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Search within this location" Command="{Binding DataContext.SearchStorageCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Rescan this location" Command="{Binding DataContext.RescanStorageCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="Copy path" Command="{Binding DataContext.CopyStoragePathCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
</Grid>
</Grid>
</DockPanel>
</Border>
</Border>
<Border Grid.Column="2" Background="#99000000" Visibility="{Binding Duplicates.IsOpen, Converter={StaticResource BoolVis}}">
<Border Background="{DynamicResource Panel}" BorderBrush="{DynamicResource Stroke}" BorderThickness="1" Margin="80" Padding="16">
<DockPanel>
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
<Button DockPanel.Dock="Right" Content="Close" Click="OnCloseDuplicates"/>
<TextBlock Text="Duplicates" FontSize="18" FontWeight="SemiBold" Foreground="{DynamicResource Fg}"/>
</DockPanel>
<TextBlock DockPanel.Dock="Top" Text="{Binding Duplicates.Status}" Foreground="{DynamicResource Fg}" Margin="0,0,0,8"/>
<ProgressBar DockPanel.Dock="Top" Margin="0,0,0,8" IsIndeterminate="True"
Visibility="{Binding Duplicates.IsBusy, Converter={StaticResource BoolVis}}"/>
<ListBox ItemsSource="{Binding Duplicates.Groups}" Background="{DynamicResource Panel}" Foreground="{DynamicResource Fg}"
BorderBrush="{DynamicResource Stroke}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="{DynamicResource Fg}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="8,6"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DockPanel>
</Border>
</Border>
</Grid>
</DockPanel>
</Window>