mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-24 20:57:19 -08:00
refactor: rewrite the welcome page since the original TreeView
has many limitations (#391)
This commit is contained in:
parent
af6d2cc725
commit
38e2e0f3f4
12 changed files with 227 additions and 243 deletions
|
@ -1397,72 +1397,6 @@
|
|||
<Setter Property="IsVisible" Value="False"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="TreeViewItem">
|
||||
<Style.Resources>
|
||||
<x:Double x:Key="TreeViewItemIndent">16</x:Double>
|
||||
</Style.Resources>
|
||||
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="MinHeight" Value="24" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<StackPanel>
|
||||
<Border Name="PART_LayoutRoot"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
TemplatedControl.IsTemplateFocusTarget="True">
|
||||
<Grid>
|
||||
<Border Name="PART_Background" CornerRadius="{TemplateBinding CornerRadius}" Background="Transparent"/>
|
||||
|
||||
<Grid Name="PART_Header" ColumnDefinitions="16,*" Margin="{TemplateBinding Level, Mode=OneWay, Converter={StaticResource TreeViewItemLeftMarginConverter}}">
|
||||
<Panel Name="PART_ExpandCollapseChevronContainer">
|
||||
<ToggleButton Name="PART_ExpandCollapseChevron"
|
||||
Classes="tree_expander"
|
||||
Focusable="False"
|
||||
HorizontalAlignment="Center"
|
||||
IsChecked="{TemplateBinding IsExpanded, Mode=TwoWay}"/>
|
||||
</Panel>
|
||||
<ContentPresenter Name="PART_HeaderPresenter"
|
||||
Grid.Column="1"
|
||||
Focusable="False"
|
||||
Background="Transparent"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
Margin="{TemplateBinding Padding}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ItemsPresenter Name="PART_ItemsPresenter"
|
||||
IsVisible="{TemplateBinding IsExpanded}"
|
||||
ItemsPanel="{TemplateBinding ItemsPanel}" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
||||
<Style Selector="^ /template/ Border#PART_LayoutRoot:pointerover">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
<Style Selector="^ /template/ Border#PART_LayoutRoot:pointerover Border#PART_Background">
|
||||
<Setter Property="Background" Value="{DynamicResource Brush.AccentHovered}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:selected /template/ Border#PART_LayoutRoot">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
<Style Selector="^:selected /template/ Border#PART_LayoutRoot Border#PART_Background">
|
||||
<Setter Property="Background" Value="{DynamicResource Brush.Accent}" />
|
||||
<Setter Property="Opacity" Value=".4"/>
|
||||
</Style>
|
||||
<Style Selector="^:selected /template/ Border#PART_LayoutRoot:pointerover Border#PART_Background">
|
||||
<Setter Property="Background" Value="{DynamicResource Brush.Accent}" />
|
||||
<Setter Property="Opacity" Value=".65"/>
|
||||
</Style>
|
||||
</Style>
|
||||
|
||||
<Style Selector="NumericUpDown">
|
||||
<Style Selector="^ /template/ ButtonSpinner#PART_Spinner">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
|
|
|
@ -141,6 +141,7 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
Welcome.Instance.Refresh();
|
||||
launcher.OpenRepositoryInTab(node, page);
|
||||
});
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace SourceGit.ViewModels
|
|||
IsExpanded = false,
|
||||
}, _parent);
|
||||
|
||||
Welcome.Instance.Refresh();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace SourceGit.ViewModels
|
|||
public override Task<bool> Sure()
|
||||
{
|
||||
Preference.Instance.RemoveNode(_node);
|
||||
Welcome.Instance.Refresh();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,10 @@ namespace SourceGit.ViewModels
|
|||
_node.Bookmark = _bookmark;
|
||||
|
||||
if (needSort)
|
||||
{
|
||||
Preference.Instance.SortByRenamedNode(_node);
|
||||
Welcome.Instance.Refresh();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
var normalizedPath = _targetPath.Replace("\\", "/");
|
||||
Preference.Instance.FindOrAddNodeByRepositoryPath(normalizedPath, _parentNode, true);
|
||||
Welcome.Instance.Refresh();
|
||||
});
|
||||
|
||||
return true;
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
var normalized = root.Replace("\\", "/");
|
||||
var node = pref.FindOrAddNodeByRepositoryPath(normalized, null, false);
|
||||
Welcome.Instance.Refresh();
|
||||
OpenRepositoryInTab(node, null);
|
||||
}
|
||||
else if (pref.RestoreTabs)
|
||||
|
|
|
@ -49,6 +49,13 @@ namespace SourceGit.ViewModels
|
|||
set => SetProperty(ref _isVisible, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public int Depth
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = 0;
|
||||
|
||||
public AvaloniaList<RepositoryNode> SubNodes
|
||||
{
|
||||
get => _subNodes;
|
||||
|
|
|
@ -12,10 +12,11 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
public static Welcome Instance => _instance;
|
||||
|
||||
public AvaloniaList<RepositoryNode> RepositoryNodes
|
||||
public AvaloniaList<RepositoryNode> Rows
|
||||
{
|
||||
get => Preference.Instance.RepositoryNodes;
|
||||
}
|
||||
get;
|
||||
private set;
|
||||
} = [];
|
||||
|
||||
public string SearchFilter
|
||||
{
|
||||
|
@ -27,6 +28,60 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
public Welcome()
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_searchFilter))
|
||||
{
|
||||
foreach (var node in Preference.Instance.RepositoryNodes)
|
||||
ResetVisibility(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var node in Preference.Instance.RepositoryNodes)
|
||||
SetVisibilityBySearch(node);
|
||||
}
|
||||
|
||||
var rows = new List<RepositoryNode>();
|
||||
MakeTreeRows(rows, Preference.Instance.RepositoryNodes);
|
||||
Rows.Clear();
|
||||
Rows.AddRange(rows);
|
||||
}
|
||||
|
||||
public void ToggleNodeIsExpanded(RepositoryNode node)
|
||||
{
|
||||
node.IsExpanded = !node.IsExpanded;
|
||||
|
||||
var depth = node.Depth;
|
||||
var idx = Rows.IndexOf(node);
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
if (node.IsExpanded)
|
||||
{
|
||||
var subrows = new List<RepositoryNode>();
|
||||
MakeTreeRows(subrows, node.SubNodes, depth + 1);
|
||||
Rows.InsertRange(idx + 1, subrows);
|
||||
}
|
||||
else
|
||||
{
|
||||
var removeCount = 0;
|
||||
for (int i = idx + 1; i < Rows.Count; i++)
|
||||
{
|
||||
var row = Rows[i];
|
||||
if (row.Depth <= depth)
|
||||
break;
|
||||
|
||||
removeCount++;
|
||||
}
|
||||
Rows.RemoveRange(idx + 1, removeCount);
|
||||
}
|
||||
}
|
||||
|
||||
public void InitRepository(string path, RepositoryNode parent)
|
||||
{
|
||||
if (!Preference.Instance.IsGitConfigured())
|
||||
|
@ -36,10 +91,8 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
|
||||
if (PopupHost.CanCreatePopup())
|
||||
{
|
||||
PopupHost.ShowPopup(new Init(path, parent));
|
||||
}
|
||||
}
|
||||
|
||||
public void Clone()
|
||||
{
|
||||
|
@ -75,30 +128,7 @@ namespace SourceGit.ViewModels
|
|||
public void MoveNode(RepositoryNode from, RepositoryNode to)
|
||||
{
|
||||
Preference.Instance.MoveNode(from, to);
|
||||
}
|
||||
|
||||
public RepositoryNode GetPrevVisible(RepositoryNode node)
|
||||
{
|
||||
var visibleRows = new List<RepositoryNode>();
|
||||
CollectVisibleRows(visibleRows, RepositoryNodes);
|
||||
|
||||
var idx = visibleRows.IndexOf(node);
|
||||
if (idx <= 1)
|
||||
return null;
|
||||
|
||||
return visibleRows[idx - 1];
|
||||
}
|
||||
|
||||
public RepositoryNode GetNextVisible(RepositoryNode node)
|
||||
{
|
||||
var visibleRows = new List<RepositoryNode>();
|
||||
CollectVisibleRows(visibleRows, RepositoryNodes);
|
||||
|
||||
var idx = visibleRows.IndexOf(node);
|
||||
if (idx < 0 || idx >= visibleRows.Count - 1)
|
||||
return null;
|
||||
|
||||
return visibleRows[idx + 1];
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public ContextMenu CreateContextMenu(RepositoryNode node)
|
||||
|
@ -178,20 +208,6 @@ namespace SourceGit.ViewModels
|
|||
return menu;
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_searchFilter))
|
||||
{
|
||||
foreach (var node in RepositoryNodes)
|
||||
ResetVisibility(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var node in RepositoryNodes)
|
||||
SetVisibilityBySearch(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetVisibility(RepositoryNode node)
|
||||
{
|
||||
node.IsVisible = true;
|
||||
|
@ -226,6 +242,23 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
private void MakeTreeRows(List<RepositoryNode> rows, AvaloniaList<RepositoryNode> nodes, int depth = 0)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
if (!node.IsVisible)
|
||||
continue;
|
||||
|
||||
node.Depth = depth;
|
||||
rows.Add(node);
|
||||
|
||||
if (node.IsRepository || !node.IsExpanded)
|
||||
continue;
|
||||
|
||||
MakeTreeRows(rows, node.SubNodes, depth+1);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenAllInNode(Launcher launcher, RepositoryNode node)
|
||||
{
|
||||
foreach (var subNode in node.SubNodes)
|
||||
|
@ -237,20 +270,6 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
private void CollectVisibleRows(List<RepositoryNode> visible, AvaloniaList<RepositoryNode> collection)
|
||||
{
|
||||
foreach (var node in collection)
|
||||
{
|
||||
if (node.IsVisible)
|
||||
{
|
||||
visible.Add(node);
|
||||
|
||||
if (!node.IsRepository)
|
||||
CollectVisibleRows(visible, node.SubNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Welcome _instance = new Welcome();
|
||||
private string _searchFilter = string.Empty;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
<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"
|
||||
|
@ -19,7 +21,6 @@
|
|||
BorderThickness="1"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
Watermark="{DynamicResource Text.Welcome.Search}"
|
||||
KeyDown="OnSearchBoxKeyDown"
|
||||
VerticalContentAlignment="Center"
|
||||
Text="{Binding SearchFilter, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True">
|
||||
|
@ -34,30 +35,32 @@
|
|||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<TreeView Grid.Row="1"
|
||||
x:Name="ReposTree"
|
||||
<!-- Repository Tree -->
|
||||
<ListBox Grid.Row="1"
|
||||
x:Name="TreeContainer"
|
||||
Margin="0,8,8,0"
|
||||
ItemsSource="{Binding RepositoryNodes}"
|
||||
Focusable="True"
|
||||
Background="Transparent"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
ItemsSource="{Binding Rows}"
|
||||
SelectionMode="Single"
|
||||
Loaded="SetupTreeViewDragAndDrop"
|
||||
LostFocus="OnTreeViewLostFocus"
|
||||
SelectionChanged="OnTreeViewSelectionChanged"
|
||||
KeyDown="OnTreeViewKeyDown">
|
||||
<TreeView.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>
|
||||
</TreeView.ContextMenu>
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBox">
|
||||
<Setter Property="FocusAdorner">
|
||||
<FocusAdornerTemplate>
|
||||
<Border Background="Transparent" BorderThickness="0"/>
|
||||
</FocusAdornerTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<TreeView.Styles>
|
||||
<Style Selector="TreeViewItem" x:DataType="vm:RepositoryNode">
|
||||
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
|
||||
<Setter Property="IsVisible" Value="{Binding IsVisible}"/>
|
||||
<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>
|
||||
|
@ -65,13 +68,29 @@
|
|||
</FocusAdornerTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
</TreeView.Styles>
|
||||
</ListBox.Styles>
|
||||
|
||||
<TreeView.ItemTemplate>
|
||||
<TreeDataTemplate ItemsSource="{Binding SubNodes}">
|
||||
<Grid Height="30"
|
||||
ColumnDefinitions="18,Auto,*"
|
||||
Background="Transparent"
|
||||
<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.ItemTemplate>
|
||||
<DataTemplate DataType="vm:RepositoryNode">
|
||||
<Grid Background="Transparent"
|
||||
ColumnDefinitions="16,18,Auto,*"
|
||||
Margin="{Binding Depth, Converter={x:Static c:IntConverters.ToTreeMargin}}"
|
||||
Loaded="SetupTreeNodeDragAndDrop"
|
||||
ContextRequested="OnTreeNodeContextRequested"
|
||||
PointerPressed="OnPointerPressedTreeNode"
|
||||
|
@ -79,14 +98,21 @@
|
|||
PointerReleased="OnPointerReleasedOnTreeNode"
|
||||
DoubleTapped="OnDoubleTappedTreeNode"
|
||||
ClipToBounds="True">
|
||||
<Path Grid.Column="0"
|
||||
<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:BookmarkConverters.ToBrush}}"
|
||||
HorizontalAlignment="Center"
|
||||
Data="{StaticResource Icons.Bookmark}"
|
||||
IsVisible="{Binding IsRepository}"/>
|
||||
|
||||
<ToggleButton Grid.Column="0"
|
||||
<ToggleButton Grid.Column="1"
|
||||
Classes="folder"
|
||||
Focusable="False"
|
||||
Width="14" Height="14"
|
||||
|
@ -95,8 +121,11 @@
|
|||
IsChecked="{Binding IsExpanded}"
|
||||
IsVisible="{Binding !IsRepository}"/>
|
||||
|
||||
<TextBlock Grid.Column="1" Classes="primary" VerticalAlignment="Center" Text="{Binding Name}"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Classes="primary"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}"/>
|
||||
<TextBlock Grid.Column="3"
|
||||
Classes="primary"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
|
@ -104,12 +133,13 @@
|
|||
Text="{Binding Id}"
|
||||
IsVisible="{Binding IsRepository}"/>
|
||||
</Grid>
|
||||
</TreeDataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Tips -->
|
||||
<TextBlock Grid.Row="1"
|
||||
Classes="italic"
|
||||
Margin="0,0,8,0"
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class RepositoryTreeNodeToggleButton : ToggleButton
|
||||
{
|
||||
protected override Type StyleKeyOverride => typeof(ToggleButton);
|
||||
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
{
|
||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed &&
|
||||
DataContext is ViewModels.RepositoryNode { IsRepository: false } node)
|
||||
{
|
||||
ViewModels.Welcome.Instance.ToggleNodeIsExpanded(node);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Welcome : UserControl
|
||||
{
|
||||
public Welcome()
|
||||
|
@ -15,9 +33,30 @@ namespace SourceGit.Views
|
|||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
|
||||
if (!e.Handled)
|
||||
{
|
||||
if (e.Key == Key.Down && ViewModels.Welcome.Instance.Rows.Count > 0)
|
||||
{
|
||||
TreeContainer.SelectedIndex = 0;
|
||||
TreeContainer.Focus(NavigationMethod.Directional);
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.F &&
|
||||
((OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Meta)) ||
|
||||
(!OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Control))))
|
||||
{
|
||||
SearchBox.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupTreeViewDragAndDrop(object sender, RoutedEventArgs _)
|
||||
{
|
||||
if (sender is TreeView view)
|
||||
if (sender is ListBox view)
|
||||
{
|
||||
DragDrop.SetAllowDrop(view, true);
|
||||
view.AddHandler(DragDrop.DragOverEvent, DragOverTreeView);
|
||||
|
@ -35,65 +74,23 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
|
||||
private void OnSearchBoxKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Down || e.Key == Key.FnDownArrow)
|
||||
{
|
||||
var containers = ReposTree.GetRealizedContainers();
|
||||
if (containers == null)
|
||||
return;
|
||||
|
||||
foreach (var c in containers)
|
||||
{
|
||||
if (c is TreeViewItem { IsVisible: true } item)
|
||||
{
|
||||
ReposTree.SelectedItem = item.DataContext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTreeViewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (ReposTree.SelectedItem is ViewModels.RepositoryNode node)
|
||||
if (TreeContainer.SelectedItem is ViewModels.RepositoryNode node && e.Key == Key.Enter)
|
||||
{
|
||||
if (e.Key == Key.Space && node.IsRepository)
|
||||
if (node.IsRepository)
|
||||
{
|
||||
var parent = this.FindAncestorOfType<Launcher>();
|
||||
if (parent?.DataContext is ViewModels.Launcher launcher)
|
||||
if (parent is { DataContext: ViewModels.Launcher launcher })
|
||||
launcher.OpenRepositoryInTab(node, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModels.Welcome.Instance.ToggleNodeIsExpanded(node);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
var next = ViewModels.Welcome.Instance.GetNextVisible(node);
|
||||
if (next != null)
|
||||
ReposTree.SelectedItem = next;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Up)
|
||||
{
|
||||
var prev = ViewModels.Welcome.Instance.GetPrevVisible(node);
|
||||
if (prev != null)
|
||||
ReposTree.SelectedItem = prev;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTreeViewSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ReposTree.SelectedItem is ViewModels.RepositoryNode node)
|
||||
{
|
||||
var item = FindTreeViewItemByNode(node, ReposTree);
|
||||
item?.Focus(NavigationMethod.Directional);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTreeNodeContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
|
@ -256,17 +253,22 @@ namespace SourceGit.Views
|
|||
|
||||
private void OnDoubleTappedTreeNode(object sender, TappedEventArgs e)
|
||||
{
|
||||
var grid = sender as Grid;
|
||||
var to = grid?.DataContext as ViewModels.RepositoryNode;
|
||||
if (to is not { IsRepository: true })
|
||||
return;
|
||||
|
||||
if (sender is Grid { DataContext: ViewModels.RepositoryNode node })
|
||||
{
|
||||
if (node.IsRepository)
|
||||
{
|
||||
var parent = this.FindAncestorOfType<Launcher>();
|
||||
if (parent?.DataContext is ViewModels.Launcher launcher)
|
||||
launcher.OpenRepositoryInTab(to, null);
|
||||
if (parent is { DataContext: ViewModels.Launcher launcher })
|
||||
launcher.OpenRepositoryInTab(node, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModels.Welcome.Instance.ToggleNodeIsExpanded(node);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null)
|
||||
{
|
||||
|
@ -287,30 +289,12 @@ namespace SourceGit.Views
|
|||
|
||||
var normalizedPath = root.Replace("\\", "/");
|
||||
var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(normalizedPath, parent, true);
|
||||
ViewModels.Welcome.Instance.Refresh();
|
||||
|
||||
var launcher = this.FindAncestorOfType<Launcher>()?.DataContext as ViewModels.Launcher;
|
||||
launcher?.OpenRepositoryInTab(node, launcher.ActivePage);
|
||||
}
|
||||
|
||||
private TreeViewItem FindTreeViewItemByNode(ViewModels.RepositoryNode node, ItemsControl container)
|
||||
{
|
||||
var items = container.GetRealizedContainers();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item is TreeViewItem { DataContext: ViewModels.RepositoryNode test } treeViewItem)
|
||||
{
|
||||
if (test == node)
|
||||
return treeViewItem;
|
||||
|
||||
var child = FindTreeViewItemByNode(node, treeViewItem);
|
||||
if (child != null)
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool _pressedTreeNode = false;
|
||||
private Point _pressedTreeNodePosition = new Point();
|
||||
private bool _startDragTreeNode = false;
|
||||
|
|
|
@ -56,6 +56,8 @@ namespace SourceGit.Views
|
|||
|
||||
var normalizedPath = root.Replace("\\", "/");
|
||||
var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(normalizedPath, parent, false);
|
||||
ViewModels.Welcome.Instance.Refresh();
|
||||
|
||||
var launcher = this.FindAncestorOfType<Launcher>()?.DataContext as ViewModels.Launcher;
|
||||
launcher?.OpenRepositoryInTab(node, launcher.ActivePage);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue