Compare commits

...

5 commits

Author SHA1 Message Date
leo
1c345df37d
ux: add some tooltips to checkboxes
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled
2024-12-17 11:24:59 +08:00
leo
c768b1750e
feature: use -p:DisableUpdateDetection=true to disable built-in update detection feature (#819) 2024-12-17 10:26:35 +08:00
leo
707a227aca
ux: make Welcome page responsive (#821) 2024-12-17 09:36:06 +08:00
leo
f418b72c64
feature: use [$workspace] $repo_name ($repo_path) as main window's title (#818) 2024-12-16 15:47:33 +08:00
leo
5425fa64fe
refactor: use another way to open tooltip of SHA after getting commit info (#810) 2024-12-16 13:29:46 +08:00
17 changed files with 247 additions and 164 deletions

View file

@ -25,6 +25,18 @@ namespace SourceGit
private Action<object> _action = null;
}
public static bool IsCheckForUpdateCommandVisible
{
get
{
#if DISABLE_UPDATE_DETECTION
return false;
#else
return true;
#endif
}
}
public static readonly Command OpenPreferenceCommand = new Command(_ => OpenDialog(new Views.Preference()));
public static readonly Command OpenHotkeysCommand = new Command(_ => OpenDialog(new Views.Hotkeys()));
public static readonly Command OpenAppDataDirCommand = new Command(_ => Native.OS.OpenInFileManager(Native.OS.DataDir));

View file

@ -33,7 +33,7 @@
<NativeMenu>
<NativeMenuItem Header="{DynamicResource Text.About.Menu}" Command="{x:Static s:App.OpenAboutCommand}"/>
<NativeMenuItem Header="{DynamicResource Text.Hotkeys}" Command="{x:Static s:App.OpenHotkeysCommand}"/>
<NativeMenuItem Header="{DynamicResource Text.SelfUpdate}" Command="{x:Static s:App.CheckForUpdateCommand}"/>
<NativeMenuItem Header="{DynamicResource Text.SelfUpdate}" Command="{x:Static s:App.CheckForUpdateCommand}" IsVisible="{x:Static s:App.IsCheckForUpdateCommandVisible}"/>
<NativeMenuItemSeparator/>
<NativeMenuItem Header="{DynamicResource Text.Preference}" Command="{x:Static s:App.OpenPreferenceCommand}" Gesture="⌘+,"/>
<NativeMenuItem Header="{DynamicResource Text.OpenAppDataDir}" Command="{x:Static s:App.OpenAppDataDirCommand}"/>

View file

@ -548,9 +548,11 @@ namespace SourceGit
_launcher = new ViewModels.Launcher(startupRepo);
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
#if !DISABLE_UPDATE_DETECTION
var pref = ViewModels.Preference.Instance;
if (pref.ShouldCheck4UpdateOnStartup())
Check4Update();
#endif
}
private ViewModels.Launcher _launcher = null;

View file

@ -273,7 +273,7 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (without checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Fetch all remotes</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">Enable '--force' option</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">Override refs check</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Fetch without tags</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">Fetch Remote Changes</x:String>

View file

@ -276,7 +276,7 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">快进(fast-forward无需checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">拉取(fetch)</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">拉取所有的远程仓库</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">启用 --force 选项</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">覆盖REF检查</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">不拉取远程标签</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">远程仓库 </x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">拉取远程仓库内容</x:String>

View file

@ -276,7 +276,7 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">快進 (fast-forward無需 checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">提取 (fetch)</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">提取所有的遠端存放庫</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">啟用 [--force] 選項</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">覆寫 REFs 檢查</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">不提取遠端標籤</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">遠端存放庫:</x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">提取遠端存放庫內容</x:String>

View file

@ -26,6 +26,10 @@
<TrimMode>link</TrimMode>
</PropertyGroup>
<PropertyGroup Condition="'$(DisableUpdateDetection)' == 'true'">
<DefineConstants>$(DefineConstants);DISABLE_UPDATE_DETECTION</DefineConstants>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="App.ico" />
<AvaloniaResource Include="Resources/Fonts/*" />

View file

@ -11,6 +11,12 @@ namespace SourceGit.ViewModels
{
public class Launcher : ObservableObject
{
public string Title
{
get => _title;
private set => SetProperty(ref _title, value);
}
public AvaloniaList<LauncherPage> Pages
{
get;
@ -31,9 +37,10 @@ namespace SourceGit.ViewModels
if (SetProperty(ref _activePage, value))
{
PopupHost.Active = value;
UpdateTitle();
if (!_ignoreIndexChange && value is { Data: Repository repo })
ActiveWorkspace.ActiveIdx = ActiveWorkspace.Repositories.IndexOf(repo.FullPath);
_activeWorkspace.ActiveIdx = _activeWorkspace.Repositories.IndexOf(repo.FullPath);
}
}
}
@ -105,6 +112,9 @@ namespace SourceGit.ViewModels
}
_ignoreIndexChange = false;
if (string.IsNullOrEmpty(_title))
UpdateTitle();
}
public void Quit(double width, double height)
@ -185,6 +195,7 @@ namespace SourceGit.ViewModels
last.Node = new RepositoryNode() { Id = Guid.NewGuid().ToString() };
last.Data = Welcome.Instance;
last.Popup = null;
UpdateTitle();
GC.Collect();
}
@ -193,7 +204,6 @@ namespace SourceGit.ViewModels
App.Quit(0);
}
_ignoreIndexChange = false;
return;
}
@ -308,7 +318,10 @@ namespace SourceGit.ViewModels
page.Data = repo;
}
ActivePage = page;
if (page != _activePage)
ActivePage = page;
else
UpdateTitle();
ActiveWorkspace.Repositories.Clear();
foreach (var p in Pages)
@ -530,8 +543,37 @@ namespace SourceGit.ViewModels
page.Data = null;
}
private void UpdateTitle()
{
if (_activeWorkspace == null)
return;
var workspace = _activeWorkspace.Name;
if (_activePage is { Data: Repository repo })
{
var node = _activePage.Node;
var name = node.Name;
var path = node.Id;
if (!OperatingSystem.IsWindows())
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (path.StartsWith(home, StringComparison.Ordinal))
path = "~" + path.Substring(prefixLen);
}
Title = $"[{workspace}] {name} ({path})";
}
else
{
Title = $"[{workspace}] Repositories";
}
}
private Workspace _activeWorkspace = null;
private LauncherPage _activePage = null;
private bool _ignoreIndexChange = false;
private string _title = string.Empty;
}
}

View file

@ -54,7 +54,8 @@
<CheckBox Grid.Row="2" Grid.Column="1"
Content="{DynamicResource Text.Apply.IgnoreWS}"
IsChecked="{Binding IgnoreWhiteSpace, Mode=TwoWay}"/>
IsChecked="{Binding IgnoreWhiteSpace, Mode=TwoWay}"
ToolTip.Tip="--ignore-whitespace"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -5,6 +5,7 @@ using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Threading;
namespace SourceGit.Views
{
@ -124,7 +125,7 @@ namespace SourceGit.Views
e.Handled = true;
}
private async void OnSHAPointerEntered(object sender, PointerEventArgs e)
private void OnSHAPointerEntered(object sender, PointerEventArgs e)
{
if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha } ctl)
{
@ -132,14 +133,22 @@ namespace SourceGit.Views
if (tooltip is Models.Commit commit && commit.SHA == sha)
return;
var c = await Task.Run(() => detail.GetParent(sha));
if (c != null && ctl.IsVisible && ctl.DataContext is string newSHA && newSHA == sha)
Task.Run(() =>
{
ToolTip.SetTip(ctl, c);
var c = detail.GetParent(sha);
if (c == null) return;
if (ctl.IsPointerOver)
ToolTip.SetIsOpen(ctl, true);
}
Dispatcher.UIThread.Invoke(() =>
{
if (ctl.IsEffectivelyVisible && ctl.DataContext is string newSHA && newSHA == sha)
{
ToolTip.SetTip(ctl, c);
if (ctl.IsPointerOver)
ToolTip.SetIsOpen(ctl, true);
}
});
});
}
e.Handled = true;

View file

@ -34,15 +34,18 @@
<CheckBox Grid.Row="1" Grid.Column="1"
Content="{DynamicResource Text.Fetch.Force}"
IsChecked="{Binding Force, Mode=TwoWay}"/>
IsChecked="{Binding Force, Mode=TwoWay}"
ToolTip.Tip="--force"/>
<CheckBox Grid.Row="2" Grid.Column="1"
Content="{DynamicResource Text.Fetch.AllRemotes}"
IsChecked="{Binding FetchAllRemotes, Mode=TwoWay}"/>
IsChecked="{Binding FetchAllRemotes, Mode=TwoWay}"
ToolTip.Tip="--all"/>
<CheckBox Grid.Row="3" Grid.Column="1"
Content="{DynamicResource Text.Fetch.NoTags}"
IsChecked="{Binding NoTags, Mode=TwoWay}"/>
IsChecked="{Binding NoTags, Mode=TwoWay}"
ToolTip.Tip="--no-tags"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -10,7 +10,7 @@
x:DataType="vm:Launcher"
x:Name="ThisControl"
Icon="/App.ico"
Title="SourceGit"
Title="{Binding Title}"
MinWidth="1024" MinHeight="600"
WindowStartupLocation="CenterScreen">
<Grid>
@ -51,12 +51,12 @@
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-"/>
<MenuItem Header="{DynamicResource Text.SelfUpdate}" Command="{x:Static s:App.CheckForUpdateCommand}">
<MenuItem Header="{DynamicResource Text.SelfUpdate}" Command="{x:Static s:App.CheckForUpdateCommand}" IsVisible="{x:Static s:App.IsCheckForUpdateCommandVisible}">
<MenuItem.Icon>
<Path Width="14" Height="14" Data="{StaticResource Icons.SoftwareUpdate}"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-"/>
<MenuItem Header="-" IsVisible="{x:Static s:App.IsCheckForUpdateCommandVisible}"/>
<MenuItem Header="{DynamicResource Text.About}" Command="{x:Static s:App.OpenAboutCommand}">
<MenuItem.Icon>
<Path Width="14" Height="14" Data="{StaticResource Icons.Info}"/>

View file

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="using:SourceGit"
xmlns:m="using:SourceGit.Models"
xmlns:c="using:SourceGit.Converters"
xmlns:vm="using:SourceGit.ViewModels"
@ -45,7 +46,7 @@
<TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.General}"/>
</TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,Auto" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.General.Locale}"
HorizontalAlignment="Right"
@ -118,6 +119,7 @@
<CheckBox Grid.Row="6" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.General.Check4UpdatesOnStartup}"
IsVisible="{x:Static s:App.IsCheckForUpdateCommandVisible}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=Check4UpdatesOnStartup, Mode=TwoWay}"/>
</Grid>
</TabItem>

View file

@ -99,11 +99,13 @@
<CheckBox Grid.Row="5" Grid.Column="1"
Content="{DynamicResource Text.Pull.NoTags}"
IsChecked="{Binding NoTags, Mode=TwoWay}"/>
IsChecked="{Binding NoTags, Mode=TwoWay}"
ToolTip.Tip="--no-tags"/>
<CheckBox Grid.Row="6" Grid.Column="1"
Content="{DynamicResource Text.Pull.UseRebase}"
IsChecked="{Binding UseRebase, Mode=TwoWay}"/>
IsChecked="{Binding UseRebase, Mode=TwoWay}"
ToolTip.Tip="--rebase"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -83,21 +83,25 @@
Height="32"
Content="{DynamicResource Text.Push.Tracking}"
IsChecked="{Binding Tracking, Mode=TwoWay}"
IsVisible="{Binding IsSetTrackOptionVisible}"/>
IsVisible="{Binding IsSetTrackOptionVisible}"
ToolTip.Tip="-u"/>
<CheckBox Grid.Row="4" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Push.CheckSubmodules}"
IsChecked="{Binding CheckSubmodules, Mode=TwoWay}"
IsVisible="{Binding IsCheckSubmodulesVisible}"/>
IsVisible="{Binding IsCheckSubmodulesVisible}"
ToolTip.Tip="--recurse-submodules=check"/>
<CheckBox Grid.Row="5" Grid.Column="1"
Content="{DynamicResource Text.Push.WithAllTags}"
IsChecked="{Binding PushAllTags, Mode=TwoWay}"/>
IsChecked="{Binding PushAllTags, Mode=TwoWay}"
ToolTip.Tip="--tags"/>
<CheckBox Grid.Row="6" Grid.Column="1"
Content="{DynamicResource Text.Push.Force}"
IsChecked="{Binding ForcePush, Mode=TwoWay}"/>
IsChecked="{Binding ForcePush, Mode=TwoWay}"
ToolTip.Tip="--force-with-lease"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -27,18 +27,21 @@
Height="32"
Content="{DynamicResource Text.Stash.IncludeUntracked}"
IsChecked="{Binding IncludeUntracked, Mode=TwoWay}"
IsVisible="{Binding !HasSelectedFiles}"/>
IsVisible="{Binding !HasSelectedFiles}"
ToolTip.Tip="--include-untracked"/>
<CheckBox Grid.Row="2" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Stash.OnlyStagedChanges}"
IsChecked="{Binding OnlyStaged, Mode=TwoWay}"
IsVisible="{Binding !HasSelectedFiles}"/>
IsVisible="{Binding !HasSelectedFiles}"
ToolTip.Tip="--staged"/>
<CheckBox Grid.Row="3" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Stash.KeepIndex}"
IsChecked="{Binding KeepIndex, Mode=TwoWay}"/>
IsChecked="{Binding KeepIndex, Mode=TwoWay}"
ToolTip.Tip="--keep-index"/>
<TextBlock Grid.Row="4" Grid.Column="1"
Margin="0,4,0,0"

View file

@ -9,149 +9,148 @@
x:Class="SourceGit.Views.Welcome"
x:DataType="vm:Welcome">
<Grid RowDefinitions="*,36">
<Grid Grid.Row="0" Margin="0,8" ColumnDefinitions="*,600,*">
<Grid Grid.Column="1" RowDefinitions="Auto,*">
<!-- Search Box -->
<TextBox Grid.Row="0"
x:Name="SearchBox"
Height="32"
Padding="0"
CornerRadius="16"
BorderBrush="{DynamicResource Brush.Border0}"
BorderThickness="1"
Background="{DynamicResource Brush.Contents}"
Watermark="{DynamicResource Text.Welcome.Search}"
VerticalContentAlignment="Center"
Text="{Binding SearchFilter, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True">
<TextBox.Styles>
<Style Selector="TextBox:pointerover /template/ Border#PART_BorderElement">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border0}"/>
</Style>
<Style Selector="TextBox:focus /template/ Border#PART_BorderElement">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border0}"/>
</Style>
</TextBox.Styles>
<!-- Managed Repositories -->
<Grid Grid.Column="1" MinWidth="600" Margin="8" RowDefinitions="Auto,*" HorizontalAlignment="Center">
<!-- Search Box -->
<TextBox Grid.Row="0"
x:Name="SearchBox"
Height="32"
Padding="0"
CornerRadius="16"
BorderBrush="{DynamicResource Brush.Border0}"
BorderThickness="1"
Background="{DynamicResource Brush.Contents}"
Watermark="{DynamicResource Text.Welcome.Search}"
VerticalContentAlignment="Center"
Text="{Binding SearchFilter, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True">
<TextBox.Styles>
<Style Selector="TextBox:pointerover /template/ Border#PART_BorderElement">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border0}"/>
</Style>
<Style Selector="TextBox:focus /template/ Border#PART_BorderElement">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border0}"/>
</Style>
</TextBox.Styles>
<TextBox.InnerLeftContent>
<Path Width="16" Height="16" Margin="6,0,3,0" Data="{StaticResource Icons.Search}" Fill="{DynamicResource Brush.FG2}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerLeftContent>
<Path Width="16" Height="16" Margin="6,0,3,0" Data="{StaticResource Icons.Search}" Fill="{DynamicResource Brush.FG2}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<Button Classes="icon_button" IsVisible="{Binding SearchFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" Command="{Binding ClearSearchFilter}">
<Path Width="16" Height="16" Margin="0,0,0,0" Data="{StaticResource Icons.Clear}" Fill="{DynamicResource Brush.FG1}"/>
</Button>
</TextBox.InnerRightContent>
</TextBox>
<TextBox.InnerRightContent>
<Button Classes="icon_button" IsVisible="{Binding SearchFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" Command="{Binding ClearSearchFilter}">
<Path Width="16" Height="16" Margin="0,0,0,0" Data="{StaticResource Icons.Clear}" Fill="{DynamicResource Brush.FG1}"/>
</Button>
</TextBox.InnerRightContent>
</TextBox>
<!-- Repository Tree -->
<v:RepositoryListBox Grid.Row="1"
x:Name="TreeContainer"
Margin="0,8,8,0"
Focusable="True"
Background="Transparent"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Rows}"
SelectionMode="Single"
Loaded="SetupTreeViewDragAndDrop"
LostFocus="OnTreeViewLostFocus"
KeyDown="OnTreeViewKeyDown">
<ListBox.Styles>
<Style Selector="ListBox">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Border Background="Transparent" BorderThickness="0"/>
</FocusAdornerTemplate>
</Setter>
</Style>
<!-- Repository Tree -->
<v:RepositoryListBox Grid.Row="1"
x:Name="TreeContainer"
Margin="0,8,8,0"
Focusable="True"
Background="Transparent"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Rows}"
SelectionMode="Single"
Loaded="SetupTreeViewDragAndDrop"
LostFocus="OnTreeViewLostFocus"
KeyDown="OnTreeViewKeyDown">
<ListBox.Styles>
<Style Selector="ListBox">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Border Background="Transparent" BorderThickness="0"/>
</FocusAdornerTemplate>
</Setter>
</Style>
<Style Selector="ListBoxItem" x:DataType="vm:RepositoryNode">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="30"/>
<Setter Property="CornerRadius" Value="4"/>
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Border Background="Transparent" BorderThickness="0"/>
</FocusAdornerTemplate>
</Setter>
</Style>
</ListBox.Styles>
<Style Selector="ListBoxItem" x:DataType="vm:RepositoryNode">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="30"/>
<Setter Property="CornerRadius" Value="4"/>
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Border Background="Transparent" BorderThickness="0"/>
</FocusAdornerTemplate>
</Setter>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{DynamicResource Text.Welcome.AddRootFolder}" Command="{Binding AddRootNode}">
<MenuItem.Icon>
<Path Width="12" Height="12" Data="{DynamicResource Icons.Folder.Add}"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{DynamicResource Text.Welcome.AddRootFolder}" Command="{Binding AddRootNode}">
<MenuItem.Icon>
<Path Width="12" Height="12" Data="{DynamicResource Icons.Folder.Add}"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:RepositoryNode">
<Grid Background="Transparent"
Height="30"
ColumnDefinitions="16,18,Auto,*"
Margin="{Binding Depth, Converter={x:Static c:IntConverters.ToTreeMargin}}"
Loaded="SetupTreeNodeDragAndDrop"
ContextRequested="OnTreeNodeContextRequested"
PointerPressed="OnPointerPressedTreeNode"
PointerMoved="OnPointerMovedOverTreeNode"
PointerReleased="OnPointerReleasedOnTreeNode"
DoubleTapped="OnDoubleTappedTreeNode"
ClipToBounds="True">
<v:RepositoryTreeNodeToggleButton Grid.Column="0"
Classes="tree_expander"
Focusable="False"
HorizontalAlignment="Center"
IsChecked="{Binding IsExpanded, Mode=OneWay}"
IsVisible="{Binding !IsRepository}"/>
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:RepositoryNode">
<Grid Background="Transparent"
Height="30"
ColumnDefinitions="16,18,Auto,*"
Margin="{Binding Depth, Converter={x:Static c:IntConverters.ToTreeMargin}}"
Loaded="SetupTreeNodeDragAndDrop"
ContextRequested="OnTreeNodeContextRequested"
PointerPressed="OnPointerPressedTreeNode"
PointerMoved="OnPointerMovedOverTreeNode"
PointerReleased="OnPointerReleasedOnTreeNode"
DoubleTapped="OnDoubleTappedTreeNode"
ClipToBounds="True">
<v:RepositoryTreeNodeToggleButton Grid.Column="0"
Classes="tree_expander"
Focusable="False"
HorizontalAlignment="Center"
IsChecked="{Binding IsExpanded, Mode=OneWay}"
IsVisible="{Binding !IsRepository}"/>
<Path Grid.Column="1"
Width="14" Height="14"
Fill="{Binding Bookmark, Converter={x:Static c:IntConverters.ToBookmarkBrush}}"
HorizontalAlignment="Center"
Data="{StaticResource Icons.Bookmark}"
IsVisible="{Binding IsRepository}"/>
<Path Grid.Column="1"
Width="14" Height="14"
Fill="{Binding Bookmark, Converter={x:Static c:IntConverters.ToBookmarkBrush}}"
HorizontalAlignment="Center"
Data="{StaticResource Icons.Bookmark}"
IsVisible="{Binding IsRepository}"/>
<ToggleButton Grid.Column="1"
Classes="folder"
Focusable="False"
Width="14" Height="14"
HorizontalAlignment="Left"
Foreground="{DynamicResource Brush.FG1}"
IsChecked="{Binding IsExpanded}"
IsVisible="{Binding !IsRepository}"/>
<ToggleButton Grid.Column="1"
Classes="folder"
Focusable="False"
Width="14" Height="14"
HorizontalAlignment="Left"
Foreground="{DynamicResource Brush.FG1}"
IsChecked="{Binding IsExpanded}"
IsVisible="{Binding !IsRepository}"/>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<TextBlock Classes="primary" VerticalAlignment="Center" Text="{Binding Name}"/>
<Path Margin="2,0,0,0"
Width="12" Height="12"
Data="{StaticResource Icons.Error}"
Fill="Orange"
IsVisible="{Binding IsInvalid}"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<TextBlock Classes="primary" VerticalAlignment="Center" Text="{Binding Name}"/>
<Path Margin="2,0,0,0"
Width="12" Height="12"
Data="{StaticResource Icons.Error}"
Fill="Orange"
IsVisible="{Binding IsInvalid}"/>
</StackPanel>
<TextBlock Grid.Column="3"
Classes="primary"
Margin="8,0"
HorizontalAlignment="Right" VerticalAlignment="Center"
<Border Grid.Column="3" Margin="8,0" VerticalAlignment="Center" ClipToBounds="True">
<TextBlock Classes="primary"
HorizontalAlignment="Right"
Foreground="{DynamicResource Brush.FG2}"
Text="{Binding Id, Converter={x:Static c:PathConverters.RelativeToHome}}"
IsVisible="{Binding IsRepository}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</v:RepositoryListBox>
</Grid>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</v:RepositoryListBox>
</Grid>
<!-- Tips -->