mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-05-25 14:15:00 +00:00
project: reorganize the structure of the project.
* remove dotnet-tool.json because the project does not rely on any dotnet tools. * remove Directory.Build.props because the solution has only one project. * move src/SourceGit to src. It's not needed to put all sources into a subfolder of src since there's only one project.
This commit is contained in:
parent
96e60da7ad
commit
96d4150d26
319 changed files with 37 additions and 53 deletions
103
src/Views/About.axaml
Normal file
103
src/Views/About.axaml
Normal file
|
@ -0,0 +1,103 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.About"
|
||||
x:DataType="v:About"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.About}"
|
||||
Background="Transparent"
|
||||
SizeToContent="WidthAndHeight"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<Path Grid.Column="0"
|
||||
Width="14" Height="14"
|
||||
Margin="10,0,0,0"
|
||||
Data="{StaticResource Icons.Info}"
|
||||
IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
|
||||
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<Button Classes="caption_button_macos" Click="CloseWindow">
|
||||
<Grid>
|
||||
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
|
||||
<Path Height="6" Width="6" Stretch="Fill" Fill="#404040" Stroke="#404040" StrokeThickness="1" Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.About}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"/>
|
||||
|
||||
<Button Grid.Column="2"
|
||||
Classes="caption_button"
|
||||
Click="CloseWindow"
|
||||
IsVisible="{OnPlatform True, macOS=False}">
|
||||
<Path Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*" Background="{DynamicResource Brush.Window}">
|
||||
<Image Grid.Column="0"
|
||||
Width="200" Height="200"
|
||||
Margin="8,0"
|
||||
Source="/App.ico"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Vertical" Margin="0,8,32,8">
|
||||
<StackPanel Height="48" Orientation="Horizontal">
|
||||
<TextBlock Classes="bold" Text="SourceGit" FontSize="32" />
|
||||
<Border Margin="12,0,0,0" Height="20" CornerRadius="10" Background="{DynamicResource Brush.Accent1}" Effect="drop-shadow(0 0 6 #40000000)">
|
||||
<TextBlock Classes="monospace" Margin="8,0" Text="{Binding Version}" FontSize="12" Foreground="White"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Margin="2,0,0,0" Text="{DynamicResource Text.About.SubTitle}" FontSize="16"/>
|
||||
|
||||
<TextBlock Margin="2,8,0,0" Text="{DynamicResource Text.About.Copyright}" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
|
||||
<StackPanel Orientation="Vertical" Margin="0,24,0,0">
|
||||
<StackPanel Orientation="Horizontal" Height="18">
|
||||
<TextBlock Text="{DynamicResource Text.About.BuildWith}" />
|
||||
<TextBlock Text="Avalonia UI" Cursor="Hand" Foreground="{DynamicResource Brush.Accent1}" TextDecorations="Underline" PointerPressed="OnVisitAvaloniaUI"/>
|
||||
<TextBlock Text=" & " />
|
||||
<TextBlock Text="AvaloniaEdit" Cursor="Hand" Foreground="{DynamicResource Brush.Accent1}" TextDecorations="Underline" PointerPressed="OnVisitAvaloniaEdit"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Height="18" Margin="0,2,0,0">
|
||||
<TextBlock Text="{DynamicResource Text.About.Fonts}" />
|
||||
<TextBlock Text="JetBrains Mono" Cursor="Hand" Foreground="{DynamicResource Brush.Accent1}" TextDecorations="Underline" PointerPressed="OnVisitJetBrainsMonoFont"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Height="18" Margin="0,2,0,0">
|
||||
<TextBlock Text="{DynamicResource Text.About.SourceCode}" />
|
||||
<TextBlock Text="Github" Cursor="Hand" Foreground="{DynamicResource Brush.Accent1}" TextDecorations="Underline" PointerPressed="OnVisitSourceCode"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
59
src/Views/About.axaml.cs
Normal file
59
src/Views/About.axaml.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Reflection;
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class About : Window
|
||||
{
|
||||
public string Version
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public About()
|
||||
{
|
||||
var ver = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
Version = $"{ver.Major}.{ver.Minor}";
|
||||
DataContext = this;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
|
||||
private void CloseWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnVisitAvaloniaUI(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
Native.OS.OpenBrowser("https://www.avaloniaui.net/");
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnVisitAvaloniaEdit(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
Native.OS.OpenBrowser("https://github.com/AvaloniaUI/AvaloniaEdit");
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnVisitJetBrainsMonoFont(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
Native.OS.OpenBrowser("https://www.jetbrains.com/lp/mono/");
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnVisitSourceCode(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
Native.OS.OpenBrowser("https://github.com/sourcegit-scm/sourcegit");
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
61
src/Views/AddRemote.axaml
Normal file
61
src/Views/AddRemote.axaml
Normal file
|
@ -0,0 +1,61 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.AddRemote"
|
||||
x:DataType="vm:AddRemote">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Remote.AddTitle}"/>
|
||||
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,Auto" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Remote.Name}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.Remote.Name.Placeholder}"
|
||||
Text="{Binding Name, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Remote.URL}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.Remote.URL.Placeholder}"
|
||||
Text="{Binding Url, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.SSHKey}"
|
||||
IsVisible="{Binding UseSSH}"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1"
|
||||
x:Name="txtSSHKey"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
IsVisible="{Binding UseSSH}"
|
||||
Watermark="{DynamicResource Text.SSHKey.Placeholder}"
|
||||
Text="{Binding SSHKey, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectSSHKey">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
27
src/Views/AddRemote.axaml.cs
Normal file
27
src/Views/AddRemote.axaml.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class AddRemote : UserControl
|
||||
{
|
||||
public AddRemote()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void SelectSSHKey(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("SSHKey") { Patterns = ["*.*"] }] };
|
||||
var toplevel = TopLevel.GetTopLevel(this);
|
||||
var selected = await toplevel.StorageProvider.OpenFilePickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
txtSSHKey.Text = selected[0].Path.LocalPath;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
45
src/Views/AddSubmodule.axaml
Normal file
45
src/Views/AddSubmodule.axaml
Normal file
|
@ -0,0 +1,45 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.AddSubmodule"
|
||||
x:DataType="vm:AddSubmodule">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Submodule.Add}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.URL}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.RepositoryURL}"
|
||||
Text="{Binding Url, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Submodule.RelativePath}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.Submodule.RelativePath.Placeholder}"
|
||||
Text="{Binding RelativePath, Mode=TwoWay}"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Submodule.FetchNested}"
|
||||
IsChecked="{Binding Recursive, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/AddSubmodule.axaml.cs
Normal file
12
src/Views/AddSubmodule.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class AddSubmodule : UserControl
|
||||
{
|
||||
public AddSubmodule()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
61
src/Views/Apply.axaml
Normal file
61
src/Views/Apply.axaml
Normal file
|
@ -0,0 +1,61 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Apply"
|
||||
x:DataType="vm:Apply">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Apply.Title}"/>
|
||||
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Apply.File}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
x:Name="txtPatchFile"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Watermark="{DynamicResource Text.Apply.File.Placeholder}"
|
||||
Text="{Binding PatchFile, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectPatchFile">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Apply.WS}"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding WhiteSpaceModes}"
|
||||
SelectedItem="{Binding SelectedWhiteSpaceMode, Mode=TwoWay}"
|
||||
IsEnabled="{Binding !IgnoreWhiteSpace}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:ApplyWhiteSpaceMode}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
<TextBlock Text="{Binding Desc}" Margin="8,0,0,0" FontSize="11" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Apply.IgnoreWS}"
|
||||
IsChecked="{Binding IgnoreWhiteSpace, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
30
src/Views/Apply.axaml.cs
Normal file
30
src/Views/Apply.axaml.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Apply : UserControl
|
||||
{
|
||||
public Apply()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void SelectPatchFile(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
if (topLevel == null)
|
||||
return;
|
||||
|
||||
var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }] };
|
||||
var selected = await topLevel.StorageProvider.OpenFilePickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
txtPatchFile.Text = selected[0].Path.LocalPath;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
66
src/Views/Archive.axaml
Normal file
66
src/Views/Archive.axaml
Normal file
|
@ -0,0 +1,66 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Archive"
|
||||
x:DataType="vm:Archive">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Archive.Title}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Archive.Revision}"/>
|
||||
<ContentControl Grid.Column="1" Content="{Binding BasedOn}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:Branch">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Converter={x:Static c:BranchConverters.ToName}}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Tag">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Tag}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Archive.File}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
x:Name="txtSaveFile"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Watermark="{DynamicResource Text.Archive.File.Placeholder}"
|
||||
Text="{Binding SaveFile, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectOutputFile">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
27
src/Views/Archive.axaml.cs
Normal file
27
src/Views/Archive.axaml.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Archive : UserControl
|
||||
{
|
||||
public Archive()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void SelectOutputFile(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var options = new FilePickerSaveOptions() { DefaultExtension = ".zip", FileTypeChoices = [new FilePickerFileType("ZIP") { Patterns = ["*.zip"] }] };
|
||||
var toplevel = TopLevel.GetTopLevel(this);
|
||||
var selected = await toplevel.StorageProvider.SaveFilePickerAsync(options);
|
||||
if (selected != null)
|
||||
{
|
||||
txtSaveFile.Text = selected.Path.LocalPath;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
115
src/Views/AssumeUnchangedManager.axaml
Normal file
115
src/Views/AssumeUnchangedManager.axaml
Normal file
|
@ -0,0 +1,115 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.AssumeUnchangedManager"
|
||||
x:DataType="vm:AssumeUnchangedManager"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.AssumeUnchanged}"
|
||||
Background="Transparent"
|
||||
Width="600" Height="400"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<Path Grid.Column="0"
|
||||
Width="14" Height="14"
|
||||
Margin="10,0,0,0"
|
||||
Data="{StaticResource Icons.File.Ignore}"
|
||||
IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
|
||||
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<Button Classes="caption_button_macos" Click="CloseWindow">
|
||||
<Grid>
|
||||
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
|
||||
<Path Height="6" Width="6" Stretch="Fill" Fill="#404040" Stroke="#404040" StrokeThickness="1" Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.AssumeUnchanged}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"/>
|
||||
|
||||
<Button Grid.Column="2"
|
||||
Classes="caption_button"
|
||||
Click="CloseWindow"
|
||||
IsVisible="{OnPlatform True, macOS=False}">
|
||||
<Path Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- Unchanged Files -->
|
||||
<Grid Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<DataGrid Margin="8"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
ItemsSource="{Binding Files}"
|
||||
SelectionMode="Single"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="None"
|
||||
Focusable="False"
|
||||
RowHeight="26"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="8,0,4,0" Data="{StaticResource Icons.File}"/>
|
||||
<TextBlock Text="{Binding}" Margin="4,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Classes="icon_button"
|
||||
Command="{Binding $parent[v:AssumeUnchangedManager].DataContext.(vm:AssumeUnchangedManager).Remove}"
|
||||
CommandParameter="{Binding}">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Clear}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<!-- Empty -->
|
||||
<StackPanel Orientation="Vertical"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsVisible="{Binding Files.Count, Converter={x:Static c:IntConverters.IsZero}}">
|
||||
<Path Width="48" Height="48" Data="{StaticResource Icons.Empty}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<TextBlock Margin="0,16,0,0" Text="{DynamicResource Text.AssumeUnchanged.Empty}" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
24
src/Views/AssumeUnchangedManager.axaml.cs
Normal file
24
src/Views/AssumeUnchangedManager.axaml.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class AssumeUnchangedManager : Window
|
||||
{
|
||||
public AssumeUnchangedManager()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
|
||||
private void CloseWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
32
src/Views/AutoFocusBehaviour.cs
Normal file
32
src/Views/AutoFocusBehaviour.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class AutoFocusBehaviour : AvaloniaObject
|
||||
{
|
||||
public static readonly AttachedProperty<bool> IsEnabledProperty =
|
||||
AvaloniaProperty.RegisterAttached<AutoFocusBehaviour, InputElement, bool>("IsEnabled", false, false);
|
||||
|
||||
static AutoFocusBehaviour()
|
||||
{
|
||||
IsEnabledProperty.Changed.AddClassHandler<InputElement>((input, e) =>
|
||||
{
|
||||
if (input.GetValue(IsEnabledProperty))
|
||||
{
|
||||
input.AttachedToVisualTree += (o, _) => (o as InputElement).Focus(NavigationMethod.Directional);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static bool GetIsEnabled(AvaloniaObject elem)
|
||||
{
|
||||
return elem.GetValue(IsEnabledProperty);
|
||||
}
|
||||
|
||||
public static void SetIsEnabled(AvaloniaObject elem, bool value)
|
||||
{
|
||||
elem.SetValue(IsEnabledProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
141
src/Views/Avatar.cs
Normal file
141
src/Views/Avatar.cs
Normal file
|
@ -0,0 +1,141 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class Avatar : Control, Models.IAvatarHost
|
||||
{
|
||||
private static readonly GradientStops[] FALLBACK_GRADIENTS = [
|
||||
new GradientStops() { new GradientStop(Colors.Orange, 0), new GradientStop(Color.FromRgb(255, 213, 134), 1) },
|
||||
new GradientStops() { new GradientStop(Colors.DodgerBlue, 0), new GradientStop(Colors.LightSkyBlue, 1) },
|
||||
new GradientStops() { new GradientStop(Colors.LimeGreen, 0), new GradientStop(Color.FromRgb(124, 241, 124), 1) },
|
||||
new GradientStops() { new GradientStop(Colors.Orchid, 0), new GradientStop(Color.FromRgb(248, 161, 245), 1) },
|
||||
new GradientStops() { new GradientStop(Colors.Tomato, 0), new GradientStop(Color.FromRgb(252, 165, 150), 1) },
|
||||
];
|
||||
|
||||
public static readonly StyledProperty<Models.User> UserProperty =
|
||||
AvaloniaProperty.Register<Avatar, Models.User>(nameof(User));
|
||||
|
||||
public Models.User User
|
||||
{
|
||||
get => GetValue(UserProperty);
|
||||
set => SetValue(UserProperty, value);
|
||||
}
|
||||
|
||||
static Avatar()
|
||||
{
|
||||
UserProperty.Changed.AddClassHandler<Avatar>(OnUserPropertyChanged);
|
||||
}
|
||||
|
||||
public Avatar()
|
||||
{
|
||||
var refetch = new MenuItem() { Header = App.Text("RefetchAvatar") };
|
||||
refetch.Click += (o, e) =>
|
||||
{
|
||||
if (User != null)
|
||||
{
|
||||
Models.AvatarManager.Request(_emailMD5, true);
|
||||
InvalidateVisual();
|
||||
}
|
||||
};
|
||||
|
||||
ContextMenu = new ContextMenu();
|
||||
ContextMenu.Items.Add(refetch);
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
if (User == null)
|
||||
return;
|
||||
|
||||
var corner = (float)Math.Max(2, Bounds.Width / 16);
|
||||
var img = Models.AvatarManager.Request(_emailMD5, false);
|
||||
if (img != null)
|
||||
{
|
||||
var rect = new Rect(0, 0, Bounds.Width, Bounds.Height);
|
||||
context.PushClip(new RoundedRect(rect, corner));
|
||||
context.DrawImage(img, rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
Point textOrigin = new Point((Bounds.Width - _fallbackLabel.Width) * 0.5, (Bounds.Height - _fallbackLabel.Height) * 0.5);
|
||||
context.DrawRectangle(_fallbackBrush, null, new Rect(0, 0, Bounds.Width, Bounds.Height), corner, corner);
|
||||
context.DrawText(_fallbackLabel, textOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAvatarResourceChanged(string md5)
|
||||
{
|
||||
if (_emailMD5 == md5)
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnLoaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnLoaded(e);
|
||||
Models.AvatarManager.Subscribe(this);
|
||||
}
|
||||
|
||||
protected override void OnUnloaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnUnloaded(e);
|
||||
Models.AvatarManager.Unsubscribe(this);
|
||||
}
|
||||
|
||||
private static void OnUserPropertyChanged(Avatar avatar, AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
if (avatar.User == null)
|
||||
{
|
||||
avatar._emailMD5 = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var placeholder = string.IsNullOrWhiteSpace(avatar.User.Name) ? "?" : avatar.User.Name.Substring(0, 1);
|
||||
var chars = placeholder.ToCharArray();
|
||||
var sum = 0;
|
||||
foreach (var c in chars)
|
||||
sum += Math.Abs(c);
|
||||
|
||||
var lowered = avatar.User.Email.ToLower(CultureInfo.CurrentCulture).Trim();
|
||||
var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(lowered));
|
||||
var builder = new StringBuilder();
|
||||
foreach (var c in hash)
|
||||
builder.Append(c.ToString("x2"));
|
||||
var md5 = builder.ToString();
|
||||
if (avatar._emailMD5 != md5)
|
||||
avatar._emailMD5 = md5;
|
||||
|
||||
avatar._fallbackBrush = new LinearGradientBrush
|
||||
{
|
||||
GradientStops = FALLBACK_GRADIENTS[sum % FALLBACK_GRADIENTS.Length],
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
};
|
||||
|
||||
var typeface = new Typeface("fonts:SourceGit#JetBrains Mono");
|
||||
|
||||
avatar._fallbackLabel = new FormattedText(
|
||||
placeholder,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
avatar.Width * 0.65,
|
||||
Brushes.White);
|
||||
|
||||
avatar.InvalidateVisual();
|
||||
}
|
||||
|
||||
private FormattedText _fallbackLabel = null;
|
||||
private LinearGradientBrush _fallbackBrush = null;
|
||||
private string _emailMD5 = null;
|
||||
}
|
||||
}
|
152
src/Views/Blame.axaml
Normal file
152
src/Views/Blame.axaml
Normal file
|
@ -0,0 +1,152 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Blame"
|
||||
x:Name="me"
|
||||
x:DataType="vm:Blame"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.Blame}"
|
||||
Background="Transparent"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
MinWidth="1280" MinHeight="720"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid Margin="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToContentMargin}}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="24"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="3"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
|
||||
<!-- Bottom border -->
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="4"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<!-- Caption Buttons (macOS) -->
|
||||
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<v:CaptionButtonsMacOS/>
|
||||
</Border>
|
||||
|
||||
<!-- Icon -->
|
||||
<Path Grid.Column="1" Margin="8,0,0,0" Width="12" Height="12" Data="{StaticResource Icons.Blame}"/>
|
||||
|
||||
<!-- Title -->
|
||||
<TextBlock Grid.Column="2" Margin="8,0,0,0" Text="{DynamicResource Text.Blame}" FontWeight="Bold" IsHitTestVisible="False" VerticalAlignment="Center"/>
|
||||
|
||||
<!-- Caption Buttons (Windows/Linux) -->
|
||||
<Border Grid.Column="3" IsVisible="{OnPlatform True, macOS=False}">
|
||||
<v:CaptionButtons/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- File -->
|
||||
<Border Grid.Row="1" Padding="8,0" Background="{DynamicResource Brush.Window}">
|
||||
<TextBlock Text="{Binding Title}" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<!-- Body -->
|
||||
<Grid Grid.Row="2" Background="{DynamicResource Brush.Window}">
|
||||
<!-- Blame View -->
|
||||
<v:BlameTextEditor HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Margin="4,0,4,4"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
BorderThickness="1"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}"
|
||||
BlameData="{Binding Data}"/>
|
||||
|
||||
<!-- Not supported mask (for binary files) -->
|
||||
<StackPanel Orientation="Vertical"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsBinary}">
|
||||
<Path Width="64" Height="64" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Error}"/>
|
||||
<TextBlock Margin="0,16,0,0" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}" Text="{DynamicResource Text.BlameTypeNotSupported}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Loading -->
|
||||
<Path Width="48" Height="48"
|
||||
Classes="rotating"
|
||||
Data="{StaticResource Icons.Loading}"
|
||||
IsVisible="{Binding Data, Converter={x:Static ObjectConverters.IsNull}}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Custom window sizer for Linux -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="3" IsVisible="{OnPlatform False, Linux=True}" IsHitTestVisible="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.IsNormal}}">
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Cursor="TopLeftCorner"
|
||||
Tag="{x:Static WindowEdge.NorthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
Cursor="TopSide"
|
||||
Tag="{x:Static WindowEdge.North}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Cursor="TopRightCorner"
|
||||
Tag="{x:Static WindowEdge.NorthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch"
|
||||
Cursor="LeftSide"
|
||||
Tag="{x:Static WindowEdge.West}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Stretch"
|
||||
Cursor="RightSide"
|
||||
Tag="{x:Static WindowEdge.East}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||
Cursor="BottomLeftCorner"
|
||||
Tag="{x:Static WindowEdge.SouthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
|
||||
Cursor="BottomSide"
|
||||
Tag="{x:Static WindowEdge.South}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Cursor="BottomRightCorner"
|
||||
Tag="{x:Static WindowEdge.SouthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
376
src/Views/Blame.axaml.cs
Normal file
376
src/Views/Blame.axaml.cs
Normal file
|
@ -0,0 +1,376 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
|
||||
using AvaloniaEdit;
|
||||
using AvaloniaEdit.Document;
|
||||
using AvaloniaEdit.Editing;
|
||||
using AvaloniaEdit.Rendering;
|
||||
using AvaloniaEdit.TextMate;
|
||||
using AvaloniaEdit.Utils;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class BlameTextEditor : TextEditor
|
||||
{
|
||||
public class CommitInfoMargin : AbstractMargin
|
||||
{
|
||||
public CommitInfoMargin(BlameTextEditor editor)
|
||||
{
|
||||
_editor = editor;
|
||||
ClipToBounds = true;
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
if (_editor.BlameData == null)
|
||||
return;
|
||||
|
||||
var view = TextView;
|
||||
if (view != null && view.VisualLinesValid)
|
||||
{
|
||||
var typeface = view.CreateTypeface();
|
||||
var underlinePen = new Pen(Brushes.DarkOrange, 1);
|
||||
|
||||
foreach (var line in view.VisualLines)
|
||||
{
|
||||
var lineNumber = line.FirstDocumentLine.LineNumber;
|
||||
if (lineNumber > _editor.BlameData.LineInfos.Count)
|
||||
break;
|
||||
|
||||
var info = _editor.BlameData.LineInfos[lineNumber - 1];
|
||||
var x = 0.0;
|
||||
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - view.VerticalOffset;
|
||||
if (!info.IsFirstInGroup && y > view.DefaultLineHeight * 0.6)
|
||||
continue;
|
||||
|
||||
var shaLink = new FormattedText(
|
||||
info.CommitSHA,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_editor.FontSize,
|
||||
Brushes.DarkOrange);
|
||||
context.DrawText(shaLink, new Point(x, y));
|
||||
context.DrawLine(underlinePen, new Point(x, y + shaLink.Baseline + 2), new Point(x + shaLink.Width, y + shaLink.Baseline + 2));
|
||||
x += shaLink.Width + 8;
|
||||
|
||||
var time = new FormattedText(
|
||||
info.Time,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_editor.FontSize,
|
||||
_editor.Foreground);
|
||||
context.DrawText(time, new Point(x, y));
|
||||
x += time.Width + 8;
|
||||
|
||||
var author = new FormattedText(
|
||||
info.Author,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_editor.FontSize,
|
||||
_editor.Foreground);
|
||||
context.DrawText(author, new Point(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var view = TextView;
|
||||
var maxWidth = 0.0;
|
||||
if (view != null && view.VisualLinesValid && _editor.BlameData != null)
|
||||
{
|
||||
var typeface = view.CreateTypeface();
|
||||
var calculated = new HashSet<string>();
|
||||
foreach (var line in view.VisualLines)
|
||||
{
|
||||
var lineNumber = line.FirstDocumentLine.LineNumber;
|
||||
if (lineNumber > _editor.BlameData.LineInfos.Count)
|
||||
break;
|
||||
|
||||
var info = _editor.BlameData.LineInfos[lineNumber - 1];
|
||||
|
||||
if (calculated.Contains(info.CommitSHA))
|
||||
continue;
|
||||
calculated.Add(info.CommitSHA);
|
||||
|
||||
var x = 0.0;
|
||||
var shaLink = new FormattedText(
|
||||
info.CommitSHA,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_editor.FontSize,
|
||||
Brushes.DarkOrange);
|
||||
x += shaLink.Width + 8;
|
||||
|
||||
var time = new FormattedText(
|
||||
info.Time,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_editor.FontSize,
|
||||
_editor.Foreground);
|
||||
x += time.Width + 8;
|
||||
|
||||
var author = new FormattedText(
|
||||
info.Author,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_editor.FontSize,
|
||||
_editor.Foreground);
|
||||
x += author.Width;
|
||||
|
||||
if (maxWidth < x)
|
||||
maxWidth = x;
|
||||
}
|
||||
}
|
||||
|
||||
return new Size(maxWidth, 0);
|
||||
}
|
||||
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
{
|
||||
base.OnPointerPressed(e);
|
||||
|
||||
var view = TextView;
|
||||
if (!e.Handled && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && view != null && view.VisualLinesValid)
|
||||
{
|
||||
var pos = e.GetPosition(this);
|
||||
var typeface = view.CreateTypeface();
|
||||
|
||||
foreach (var line in view.VisualLines)
|
||||
{
|
||||
var lineNumber = line.FirstDocumentLine.LineNumber;
|
||||
if (lineNumber >= _editor.BlameData.LineInfos.Count)
|
||||
break;
|
||||
|
||||
var info = _editor.BlameData.LineInfos[lineNumber - 1];
|
||||
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - view.VerticalOffset;
|
||||
var shaLink = new FormattedText(
|
||||
info.CommitSHA,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
_editor.FontSize,
|
||||
Brushes.DarkOrange);
|
||||
|
||||
var rect = new Rect(0, y, shaLink.Width, shaLink.Height);
|
||||
if (rect.Contains(pos))
|
||||
{
|
||||
_editor.OnCommitSHAClicked(info.CommitSHA);
|
||||
e.Handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly BlameTextEditor _editor = null;
|
||||
}
|
||||
|
||||
public class VerticalSeperatorMargin : AbstractMargin
|
||||
{
|
||||
public VerticalSeperatorMargin(BlameTextEditor editor)
|
||||
{
|
||||
_editor = editor;
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var pen = new Pen(_editor.BorderBrush, 1);
|
||||
context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height));
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
return new Size(1, 0);
|
||||
}
|
||||
|
||||
private readonly BlameTextEditor _editor = null;
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Models.BlameData> BlameDataProperty =
|
||||
AvaloniaProperty.Register<BlameTextEditor, Models.BlameData>(nameof(BlameData));
|
||||
|
||||
public Models.BlameData BlameData
|
||||
{
|
||||
get => GetValue(BlameDataProperty);
|
||||
set => SetValue(BlameDataProperty, value);
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(TextEditor);
|
||||
|
||||
public BlameTextEditor() : base(new TextArea(), new TextDocument())
|
||||
{
|
||||
IsReadOnly = true;
|
||||
ShowLineNumbers = false;
|
||||
WordWrap = false;
|
||||
|
||||
_textMate = Models.TextMateHelper.CreateForEditor(this);
|
||||
|
||||
TextArea.LeftMargins.Add(new LineNumberMargin() { Margin = new Thickness(8, 0) });
|
||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
|
||||
TextArea.LeftMargins.Add(new CommitInfoMargin(this) { Margin = new Thickness(8, 0) });
|
||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
|
||||
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
|
||||
TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged;
|
||||
TextArea.TextView.Margin = new Thickness(4, 0);
|
||||
}
|
||||
|
||||
public void OnCommitSHAClicked(string sha)
|
||||
{
|
||||
if (DataContext is ViewModels.Blame blame)
|
||||
{
|
||||
blame.NavigateToCommit(sha);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUnloaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnUnloaded(e);
|
||||
|
||||
TextArea.LeftMargins.Clear();
|
||||
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
|
||||
TextArea.TextView.VisualLinesChanged -= OnTextViewVisualLinesChanged;
|
||||
|
||||
if (_textMate != null)
|
||||
{
|
||||
_textMate.Dispose();
|
||||
_textMate = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == BlameDataProperty)
|
||||
{
|
||||
if (BlameData != null)
|
||||
{
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, BlameData.File);
|
||||
Text = BlameData.Content;
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = string.Empty;
|
||||
}
|
||||
}
|
||||
else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null)
|
||||
{
|
||||
Models.TextMateHelper.SetThemeByApp(_textMate);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
var selected = SelectedText;
|
||||
if (string.IsNullOrEmpty(selected))
|
||||
return;
|
||||
|
||||
var icon = new Avalonia.Controls.Shapes.Path();
|
||||
icon.Width = 10;
|
||||
icon.Height = 10;
|
||||
icon.Stretch = Stretch.Uniform;
|
||||
icon.Data = App.Current?.FindResource("Icons.Copy") as StreamGeometry;
|
||||
|
||||
var copy = new MenuItem();
|
||||
copy.Header = App.Text("Copy");
|
||||
copy.Icon = icon;
|
||||
copy.Click += (o, ev) =>
|
||||
{
|
||||
App.CopyText(selected);
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
var menu = new ContextMenu();
|
||||
menu.Items.Add(copy);
|
||||
menu.Open(TextArea.TextView);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnTextViewVisualLinesChanged(object sender, EventArgs e)
|
||||
{
|
||||
foreach (var margin in TextArea.LeftMargins)
|
||||
{
|
||||
if (margin is CommitInfoMargin commitInfo)
|
||||
{
|
||||
commitInfo.InvalidateMeasure();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TextMate.Installation _textMate = null;
|
||||
}
|
||||
|
||||
public partial class Blame : Window
|
||||
{
|
||||
public Blame()
|
||||
{
|
||||
if (App.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
Owner = desktop.MainWindow;
|
||||
}
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = WindowState.Maximized;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void CustomResizeWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
if (border.Tag is WindowEdge edge)
|
||||
{
|
||||
BeginResizeDrag(edge, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
private void OnCommitSHAPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.Blame blame)
|
||||
{
|
||||
var txt = sender as TextBlock;
|
||||
blame.NavigateToCommit(txt.Text);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
21
src/Views/CaptionButtons.axaml
Normal file
21
src/Views/CaptionButtons.axaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CaptionButtons">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Classes="caption_button" Click="MinimizeWindow">
|
||||
<Path Data="{StaticResource Icons.Window.Minimize}"/>
|
||||
</Button>
|
||||
<Button Classes="caption_button" Click="MaximizeOrRestoreWindow">
|
||||
<Path Data="{Binding $parent[Window].WindowState, Converter={x:Static c:WindowStateConverters.ToMaxOrRestoreIcon}}"/>
|
||||
</Button>
|
||||
<Button Classes="caption_button" Click="CloseWindow">
|
||||
<Path Data="{StaticResource Icons.Window.Close}" Width="9" Height="9"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</UserControl>
|
41
src/Views/CaptionButtons.axaml.cs
Normal file
41
src/Views/CaptionButtons.axaml.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CaptionButtons : UserControl
|
||||
{
|
||||
public CaptionButtons()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MinimizeWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = this.FindAncestorOfType<Window>();
|
||||
if (window != null)
|
||||
{
|
||||
window.WindowState = WindowState.Minimized;
|
||||
}
|
||||
}
|
||||
|
||||
private void MaximizeOrRestoreWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = this.FindAncestorOfType<Window>();
|
||||
if (window != null)
|
||||
{
|
||||
window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = this.FindAncestorOfType<Window>();
|
||||
if (window != null)
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
32
src/Views/CaptionButtonsMacOS.axaml
Normal file
32
src/Views/CaptionButtonsMacOS.axaml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:v="using:SourceGit.Views"
|
||||
xmlns:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CaptionButtonsMacOS">
|
||||
<Grid Classes="caption_button_box">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Classes="caption_button_macos" Click="CloseWindow" Margin="10,0,0,0">
|
||||
<Grid>
|
||||
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
|
||||
<Path Height="6" Width="6" Stretch="Fill" Fill="#404040" Stroke="#404040" StrokeThickness="1" Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
<Button Classes="caption_button_macos" Click="MinimizeWindow">
|
||||
<Grid>
|
||||
<Ellipse Fill="{DynamicResource Brush.MacOS.Minimize}"/>
|
||||
<Path Height="2" Width="8" Stretch="Fill" Fill="#404040" Data="{StaticResource Icons.MacOS.Minimize}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
<Button Classes="caption_button_macos" Click="MaximizeOrRestoreWindow">
|
||||
<Grid>
|
||||
<Ellipse Fill="{DynamicResource Brush.MacOS.Maximize}"/>
|
||||
<Path Height="6" Width="6" Stretch="Fill" Fill="#404040" Data="{StaticResource Icons.MacOS.Maximize}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
41
src/Views/CaptionButtonsMacOS.axaml.cs
Normal file
41
src/Views/CaptionButtonsMacOS.axaml.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CaptionButtonsMacOS : UserControl
|
||||
{
|
||||
public CaptionButtonsMacOS()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MinimizeWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = this.FindAncestorOfType<Window>();
|
||||
if (window != null)
|
||||
{
|
||||
window.WindowState = WindowState.Minimized;
|
||||
}
|
||||
}
|
||||
|
||||
private void MaximizeOrRestoreWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = this.FindAncestorOfType<Window>();
|
||||
if (window != null)
|
||||
{
|
||||
window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = this.FindAncestorOfType<Window>();
|
||||
if (window != null)
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
125
src/Views/ChangeStatusIcon.cs
Normal file
125
src/Views/ChangeStatusIcon.cs
Normal file
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class ChangeStatusIcon : Control
|
||||
{
|
||||
private static readonly IBrush[] BACKGROUNDS = [
|
||||
Brushes.Transparent,
|
||||
new LinearGradientBrush
|
||||
{
|
||||
GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) },
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
},
|
||||
new LinearGradientBrush
|
||||
{
|
||||
GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) },
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
},
|
||||
new LinearGradientBrush
|
||||
{
|
||||
GradientStops = new GradientStops() { new GradientStop(Colors.Tomato, 0), new GradientStop(Color.FromRgb(252, 165, 150), 1) },
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
},
|
||||
new LinearGradientBrush
|
||||
{
|
||||
GradientStops = new GradientStops() { new GradientStop(Colors.Orchid, 0), new GradientStop(Color.FromRgb(248, 161, 245), 1) },
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
},
|
||||
new LinearGradientBrush
|
||||
{
|
||||
GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) },
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
},
|
||||
new LinearGradientBrush
|
||||
{
|
||||
GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) },
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
},
|
||||
new LinearGradientBrush
|
||||
{
|
||||
GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) },
|
||||
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
|
||||
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
|
||||
},
|
||||
];
|
||||
|
||||
private static readonly string[] INDICATOR = ["?", "±", "+", "−", "➜", "❏", "U", "★"];
|
||||
|
||||
public static readonly StyledProperty<bool> IsWorkingCopyChangeProperty =
|
||||
AvaloniaProperty.Register<ChangeStatusIcon, bool>(nameof(IsWorkingCopyChange));
|
||||
|
||||
public bool IsWorkingCopyChange
|
||||
{
|
||||
get => GetValue(IsWorkingCopyChangeProperty);
|
||||
set => SetValue(IsWorkingCopyChangeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Models.Change> ChangeProperty =
|
||||
AvaloniaProperty.Register<ChangeStatusIcon, Models.Change>(nameof(Change));
|
||||
|
||||
public Models.Change Change
|
||||
{
|
||||
get => GetValue(ChangeProperty);
|
||||
set => SetValue(ChangeProperty, value);
|
||||
}
|
||||
|
||||
static ChangeStatusIcon()
|
||||
{
|
||||
AffectsRender<ChangeStatusIcon>(IsWorkingCopyChangeProperty, ChangeProperty);
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
if (Change == null || Bounds.Width <= 0)
|
||||
return;
|
||||
|
||||
var typeface = new Typeface("fonts:SourceGit#JetBrains Mono");
|
||||
|
||||
IBrush background = null;
|
||||
string indicator;
|
||||
if (IsWorkingCopyChange)
|
||||
{
|
||||
if (Change.IsConflit)
|
||||
{
|
||||
background = Brushes.OrangeRed;
|
||||
indicator = "!";
|
||||
}
|
||||
else
|
||||
{
|
||||
background = BACKGROUNDS[(int)Change.WorkTree];
|
||||
indicator = INDICATOR[(int)Change.WorkTree];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
background = BACKGROUNDS[(int)Change.Index];
|
||||
indicator = INDICATOR[(int)Change.Index];
|
||||
}
|
||||
|
||||
var txt = new FormattedText(
|
||||
indicator,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
Bounds.Width * 0.8,
|
||||
Brushes.White);
|
||||
|
||||
float corner = (float)Math.Max(2, Bounds.Width / 16);
|
||||
Point textOrigin = new Point((Bounds.Width - txt.Width) * 0.5, (Bounds.Height - txt.Height) * 0.5);
|
||||
context.DrawRectangle(background, null, new Rect(0, 0, Bounds.Width, Bounds.Height), corner, corner);
|
||||
context.DrawText(txt, textOrigin);
|
||||
}
|
||||
}
|
||||
}
|
35
src/Views/ChangeViewModeSwitcher.axaml
Normal file
35
src/Views/ChangeViewModeSwitcher.axaml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.ChangeViewModeSwitcher"
|
||||
x:DataType="v:ChangeViewModeSwitcher">
|
||||
<Button Classes="icon_button" Padding="0" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" ToolTip.Tip="{DynamicResource Text.ChangeDisplayMode}">
|
||||
<Button.Flyout>
|
||||
<MenuFlyout Placement="BottomEdgeAlignedLeft">
|
||||
<MenuItem Header="{DynamicResource Text.ChangeDisplayMode.List}" Command="{Binding SwitchMode}" CommandParameter="{x:Static m:ChangeViewMode.List}">
|
||||
<MenuItem.Icon>
|
||||
<Path Width="12" Height="12" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.List}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{DynamicResource Text.ChangeDisplayMode.Grid}" Command="{Binding SwitchMode}" CommandParameter="{x:Static m:ChangeViewMode.Grid}">
|
||||
<MenuItem.Icon>
|
||||
<Path Width="12" Height="12" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Grid}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{DynamicResource Text.ChangeDisplayMode.Tree}" Command="{Binding SwitchMode}" CommandParameter="{x:Static m:ChangeViewMode.Tree}">
|
||||
<MenuItem.Icon>
|
||||
<Path Width="12" Height="12" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Tree}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
|
||||
<Path Stretch="Uniform" Fill="{DynamicResource Brush.FG2}" Data="{Binding ViewMode, Converter={x:Static c:ChangeViewModeConverters.ToIcon}}"/>
|
||||
</Button>
|
||||
</UserControl>
|
28
src/Views/ChangeViewModeSwitcher.axaml.cs
Normal file
28
src/Views/ChangeViewModeSwitcher.axaml.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class ChangeViewModeSwitcher : UserControl
|
||||
{
|
||||
public static readonly StyledProperty<Models.ChangeViewMode> ViewModeProperty =
|
||||
AvaloniaProperty.Register<ChangeViewModeSwitcher, Models.ChangeViewMode>(nameof(ViewMode));
|
||||
|
||||
public Models.ChangeViewMode ViewMode
|
||||
{
|
||||
get => GetValue(ViewModeProperty);
|
||||
set => SetValue(ViewModeProperty, value);
|
||||
}
|
||||
|
||||
public ChangeViewModeSwitcher()
|
||||
{
|
||||
DataContext = this;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void SwitchMode(object param)
|
||||
{
|
||||
ViewMode = (Models.ChangeViewMode)param;
|
||||
}
|
||||
}
|
||||
}
|
19
src/Views/Checkout.axaml
Normal file
19
src/Views/Checkout.axaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Checkout"
|
||||
x:DataType="vm:Checkout">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Checkout}"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,16,0,0">
|
||||
<TextBlock Text="{DynamicResource Text.Checkout.Target}"/>
|
||||
<Path Width="14" Height="14" Margin="8,0" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Branch}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Checkout.axaml.cs
Normal file
12
src/Views/Checkout.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Checkout : UserControl
|
||||
{
|
||||
public Checkout()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
32
src/Views/CherryPick.axaml
Normal file
32
src/Views/CherryPick.axaml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CherryPick"
|
||||
x:DataType="vm:CherryPick">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.CherryPick}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.CherryPick.Commit}"/>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding Target.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Target.Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="1"
|
||||
Content="{DynamicResource Text.CherryPick.CommitChanges}"
|
||||
IsChecked="{Binding AutoCommit, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/CherryPick.axaml.cs
Normal file
12
src/Views/CherryPick.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CherryPick : UserControl
|
||||
{
|
||||
public CherryPick()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
19
src/Views/Cleanup.axaml
Normal file
19
src/Views/Cleanup.axaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Cleanup"
|
||||
x:DataType="vm:Cleanup">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Repository.Clean}"/>
|
||||
<TextBlock Text="{DynamicResource Text.Repository.CleanTips}"
|
||||
Margin="0,16,0,0"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Cleanup.axaml.cs
Normal file
12
src/Views/Cleanup.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Cleanup : UserControl
|
||||
{
|
||||
public Cleanup()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
18
src/Views/ClearStashes.axaml
Normal file
18
src/Views/ClearStashes.axaml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.ClearStashes"
|
||||
x:DataType="vm:ClearStashes">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.ClearStashes}"/>
|
||||
|
||||
<TextBlock Margin="0,16,0,8"
|
||||
Text="{DynamicResource Text.ClearStashes.Message}"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/ClearStashes.axaml.cs
Normal file
12
src/Views/ClearStashes.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class ClearStashes : UserControl
|
||||
{
|
||||
public ClearStashes()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
56
src/Views/Clone.axaml
Normal file
56
src/Views/Clone.axaml
Normal file
|
@ -0,0 +1,56 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Clone"
|
||||
x:DataType="vm:Clone">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock Classes="bold" FontSize="18" Text="{DynamicResource Text.Clone}"/>
|
||||
|
||||
<Grid Margin="8,16,0,0" Height="28" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.RemoteURL}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" Text="{Binding Remote, Mode=TwoWay}" v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="120,*" IsVisible="{Binding UseSSH}">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.SSHKey}"/>
|
||||
<TextBox Grid.Column="1"
|
||||
x:Name="txtSSHKey"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Watermark="{DynamicResource Text.SSHKey.Placeholder}"
|
||||
Text="{Binding SSHKey, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectSSHKey">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.ParentFolder}"/>
|
||||
<TextBox Grid.Column="1"
|
||||
x:Name="txtParentFolder"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding ParentFolder, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Margin="4,0,0,0" Click="SelectParentFolder">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.LocalName}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" Watermark="{DynamicResource Text.Clone.LocalName.Placeholder}" Text="{Binding Local, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.AdditionalParam}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" Watermark="{DynamicResource Text.Clone.AdditionalParam.Placeholder}" Text="{Binding ExtraArgs, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
40
src/Views/Clone.axaml.cs
Normal file
40
src/Views/Clone.axaml.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Clone : UserControl
|
||||
{
|
||||
public Clone()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void SelectParentFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
|
||||
var toplevel = TopLevel.GetTopLevel(this);
|
||||
var selected = await toplevel.StorageProvider.OpenFolderPickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
txtParentFolder.Text = selected[0].Path.LocalPath;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void SelectSSHKey(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("SSHKey") { Patterns = ["*.*"] }] };
|
||||
var toplevel = TopLevel.GetTopLevel(this);
|
||||
var selected = await toplevel.StorageProvider.OpenFilePickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
txtSSHKey.Text = selected[0].Path.LocalPath;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
112
src/Views/CommitBaseInfo.axaml
Normal file
112
src/Views/CommitBaseInfo.axaml
Normal file
|
@ -0,0 +1,112 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CommitBaseInfo">
|
||||
<UserControl.DataTemplates>
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<!-- Author & Committer -->
|
||||
<Grid ColumnDefinitions="96,*,96,*" Margin="0,8">
|
||||
<!-- Author -->
|
||||
<v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Author}"/>
|
||||
<StackPanel Grid.Column="1" Margin="16,0,8,0" Orientation="Vertical">
|
||||
<TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Author}"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,8">
|
||||
<SelectableTextBlock Text="{Binding Author.Name}" Margin="2,0,8,0"/>
|
||||
<SelectableTextBlock Text="{Binding Author.Email}" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</StackPanel>
|
||||
<SelectableTextBlock Text="{Binding AuthorTimeStr}"
|
||||
Margin="2,0,0,0"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
|
||||
Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Committer -->
|
||||
<v:Avatar Grid.Column="2" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Committer}" IsVisible="{Binding IsCommitterVisible}"/>
|
||||
<StackPanel Grid.Column="3" Margin="16,0,8,0" Orientation="Vertical" IsVisible="{Binding IsCommitterVisible}">
|
||||
<TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Committer}"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,8">
|
||||
<SelectableTextBlock Text="{Binding Committer.Name}" Margin="2,0,8,0"/>
|
||||
<SelectableTextBlock Text="{Binding Committer.Email}" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</StackPanel>
|
||||
<SelectableTextBlock Text="{Binding CommitterTimeStr}"
|
||||
Margin="2,0,0,0"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
|
||||
Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Line -->
|
||||
<Rectangle Height=".65" Margin="8" Fill="{DynamicResource Brush.Border2}" VerticalAlignment="Center"/>
|
||||
|
||||
<!-- Base Information -->
|
||||
<Grid RowDefinitions="24,Auto,Auto,Auto" ColumnDefinitions="96,*">
|
||||
<!-- SHA -->
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.SHA}" />
|
||||
<SelectableTextBlock Grid.Row="0" Grid.Column="1" Text="{Binding SHA}" Margin="12,0,0,0" VerticalAlignment="Center" FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}"/>
|
||||
|
||||
<!-- PARENTS -->
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Parents}" IsVisible="{Binding Parents.Count, Converter={x:Static c:IntConverters.IsGreaterThanZero}}"/>
|
||||
<ItemsControl Grid.Row="1" Grid.Column="1" Height="24" Margin="12,0,0,0" ItemsSource="{Binding Parents}" IsVisible="{Binding Parents.Count, Converter={x:Static c:IntConverters.IsGreaterThanZero}}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Classes="monospace"
|
||||
Text="{Binding Converter={x:Static c:StringConverters.ToShortSHA}}"
|
||||
Foreground="DarkOrange"
|
||||
TextDecorations="Underline"
|
||||
Margin="0,0,16,0"
|
||||
PointerPressed="OnParentSHAPressed"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- REFS -->
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Refs}" IsVisible="{Binding Decorators.Count, Converter={x:Static c:IntConverters.IsGreaterThanZero}}"/>
|
||||
<ItemsControl Grid.Row="2" Grid.Column="1" Height="24" Margin="12,0,0,0" ItemsSource="{Binding Decorators}" IsVisible="{Binding Decorators.Count, Converter={x:Static c:IntConverters.IsGreaterThanZero}}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type m:Decorator}">
|
||||
<Border Height="16" Margin="0,0,6,0" CornerRadius="2" ClipToBounds="True">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Background="{DynamicResource Brush.Decorator}" Width="16">
|
||||
<Path Width="8" Height="8" Stretch="Fill" Data="{Binding Type, Converter={x:Static c:DecoratorTypeConverters.ToIcon}}" Fill="{DynamicResource Brush.DecoratorIcon}"/>
|
||||
</Border>
|
||||
<Border Background="{Binding Type, Converter={x:Static c:DecoratorTypeConverters.ToBackground}}">
|
||||
<TextBlock Classes="monospace" Text="{Binding Name}" FontSize="10" Margin="4,0" Foreground="Black"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Messages -->
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Message}" VerticalAlignment="Top" Margin="0,4,0,0" />
|
||||
<ScrollViewer Grid.Row="3" Grid.Column="1" Margin="12,5,0,0" MaxHeight="100" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<SelectableTextBlock Text="{Binding FullMessage}" FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}" TextWrapping="Wrap"/>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- Line -->
|
||||
<Rectangle Height=".65" Margin="8" Fill="{DynamicResource Brush.Border2}" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</UserControl.DataTemplates>
|
||||
</UserControl>
|
22
src/Views/CommitBaseInfo.axaml.cs
Normal file
22
src/Views/CommitBaseInfo.axaml.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CommitBaseInfo : UserControl
|
||||
{
|
||||
public CommitBaseInfo()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnParentSHAPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.CommitDetail detail)
|
||||
{
|
||||
detail.NavigateTo((sender as Control).DataContext as string);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
180
src/Views/CommitChanges.axaml
Normal file
180
src/Views/CommitChanges.axaml
Normal file
|
@ -0,0 +1,180 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CommitChanges"
|
||||
x:DataType="vm:CommitDetail">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="256" MinWidth="200" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0" RowDefinitions="26,*">
|
||||
<!-- Search & Display Mode -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,24">
|
||||
<TextBox Grid.Column="0"
|
||||
Height="26"
|
||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
Background="Transparent"
|
||||
Watermark="{DynamicResource Text.CommitDetail.Changes.Search}"
|
||||
Text="{Binding SearchChangeFilter, Mode=TwoWay}">
|
||||
<TextBox.InnerLeftContent>
|
||||
<Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/>
|
||||
</TextBox.InnerLeftContent>
|
||||
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button"
|
||||
IsVisible="{Binding SearchChangeFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Command="{Binding ClearSearchChangeFilter}">
|
||||
<Path Width="14" Height="14" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Clear}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<v:ChangeViewModeSwitcher Grid.Column="1"
|
||||
Width="18" Height="18"
|
||||
HorizontalAlignment="Right"
|
||||
ViewMode="{Binding Source={x:Static vm:Preference.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Changes -->
|
||||
<Border Grid.Row="1" Margin="0,4,0,0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}">
|
||||
<Grid>
|
||||
<DataGrid Background="Transparent"
|
||||
ItemsSource="{Binding VisibleChanges}"
|
||||
SelectedItem="{Binding SelectedChange, Mode=TwoWay}"
|
||||
SelectionMode="Single"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="None"
|
||||
Focusable="False"
|
||||
RowHeight="26"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
SelectionChanged="OnDataGridSelectionChanged"
|
||||
ContextRequested="OnDataGridContextRequested"
|
||||
IsVisible="{Binding Source={x:Static vm:Preference.Instance}, Path=CommitChangeViewMode, Converter={x:Static c:ChangeViewModeConverters.IsList}}">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Header="ICON">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<v:ChangeStatusIcon Width="14" Height="14" IsWorkingCopyChange="False" Change="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="*" Header="PATH">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Classes="monospace" Text="{Binding Path}" Margin="4,0,0,0"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<DataGrid Background="Transparent"
|
||||
ItemsSource="{Binding VisibleChanges}"
|
||||
SelectedItem="{Binding SelectedChange, Mode=TwoWay}"
|
||||
SelectionMode="Single"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="None"
|
||||
Focusable="False"
|
||||
RowHeight="26"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
SelectionChanged="OnDataGridSelectionChanged"
|
||||
ContextRequested="OnDataGridContextRequested"
|
||||
IsVisible="{Binding Source={x:Static vm:Preference.Instance}, Path=CommitChangeViewMode, Converter={x:Static c:ChangeViewModeConverters.IsGrid}}">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Header="ICON">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<v:ChangeStatusIcon Width="14" Height="14" IsWorkingCopyChange="False" Change="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Header="FILE_NAME">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Classes="monospace" Text="{Binding Path, Converter={x:Static c:PathConverters.PureFileName}}" Margin="4,0,0,0"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Header="FOLDER_PATH">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Classes="monospace" Text="{Binding Path, Converter={x:Static c:PathConverters.PureDirectoryName}}" Margin="4,0,0,0" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<TreeView ItemsSource="{Binding ChangeTree}"
|
||||
SelectedItem="{Binding SelectedChangeNode, Mode=TwoWay}"
|
||||
AutoScrollToSelectedItem="True"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
ContextRequested="OnTreeViewContextRequested"
|
||||
IsVisible="{Binding Source={x:Static vm:Preference.Instance}, Path=CommitChangeViewMode, Converter={x:Static c:ChangeViewModeConverters.IsTree}}">
|
||||
<TreeView.Styles>
|
||||
<Style Selector="TreeViewItem" x:DataType="vm:FileTreeNode">
|
||||
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
|
||||
</Style>
|
||||
</TreeView.Styles>
|
||||
|
||||
<TreeView.ItemTemplate>
|
||||
<TreeDataTemplate ItemsSource="{Binding Children}" x:DataType="{x:Type vm:FileTreeNode}">
|
||||
<Grid Height="24" ColumnDefinitions="Auto,*">
|
||||
<Path Grid.Column="0" Classes="folder_icon" Width="14" Height="14" Margin="0,2,0,0" IsVisible="{Binding IsFolder}" Fill="Goldenrod" VerticalAlignment="Center"/>
|
||||
<v:ChangeStatusIcon Grid.Column="0" Width="14" Height="14" IsWorkingCopyChange="False" Change="{Binding Backend}" IsVisible="{Binding !IsFolder}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding FullPath, Converter={x:Static c:PathConverters.PureFileName}}" Margin="6,0,0,0"/>
|
||||
</Grid>
|
||||
</TreeDataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<GridSplitter Grid.Column="1"
|
||||
MinWidth="1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Background="Transparent"/>
|
||||
|
||||
<Grid Grid.Column="2">
|
||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
|
||||
<Path Width="64" Height="64" Data="{StaticResource Icons.Diff}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<TextBlock Margin="0,16,0,0"
|
||||
Text="{DynamicResource Text.Diff.Welcome}"
|
||||
FontSize="18" FontWeight="Bold"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<ContentControl Content="{Binding DiffContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:DiffContext">
|
||||
<v:DiffView/>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
49
src/Views/CommitChanges.axaml.cs
Normal file
49
src/Views/CommitChanges.axaml.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CommitChanges : UserControl
|
||||
{
|
||||
public CommitChanges()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is DataGrid datagrid && datagrid.IsVisible && datagrid.SelectedItem != null)
|
||||
{
|
||||
datagrid.ScrollIntoView(datagrid.SelectedItem, null);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnDataGridContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (sender is DataGrid datagrid && datagrid.SelectedItem != null)
|
||||
{
|
||||
var detail = DataContext as ViewModels.CommitDetail;
|
||||
var menu = detail.CreateChangeContextMenu(datagrid.SelectedItem as Models.Change);
|
||||
menu.Open(datagrid);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnTreeViewContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (sender is TreeView view && view.SelectedItem != null)
|
||||
{
|
||||
var detail = DataContext as ViewModels.CommitDetail;
|
||||
var node = view.SelectedItem as ViewModels.FileTreeNode;
|
||||
if (node != null && !node.IsFolder)
|
||||
{
|
||||
var menu = detail.CreateChangeContextMenu(node.Backend as Models.Change);
|
||||
menu.Open(view);
|
||||
}
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
76
src/Views/CommitDetail.axaml
Normal file
76
src/Views/CommitDetail.axaml
Normal file
|
@ -0,0 +1,76 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CommitDetail"
|
||||
x:DataType="vm:CommitDetail"
|
||||
Background="{DynamicResource Brush.Window}">
|
||||
<TabControl SelectedIndex="{Binding ActivePageIndex, Mode=TwoWay}" Padding="4">
|
||||
<!-- Information Page -->
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.CommitDetail.Info}"/>
|
||||
</TabItem.Header>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<!-- Base Information -->
|
||||
<v:CommitBaseInfo Grid.Row="0" Content="{Binding Commit}"/>
|
||||
|
||||
<!-- Change List -->
|
||||
<DataGrid Grid.Row="1"
|
||||
Background="Transparent"
|
||||
ItemsSource="{Binding Changes}"
|
||||
SelectionMode="Single"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="None"
|
||||
Focusable="False"
|
||||
RowHeight="26"
|
||||
Margin="80,0,8,0"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
ContextRequested="OnChangeListContextRequested"
|
||||
DoubleTapped="OnChangeListDoubleTapped">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Header="ICON">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<v:ChangeStatusIcon Width="14" Height="14" IsWorkingCopyChange="False" Change="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="*" Header="PATH">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Classes="monospace" Text="{Binding Path}" Margin="8,0,0,0"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.CommitDetail.Changes}"/>
|
||||
</TabItem.Header>
|
||||
<v:CommitChanges/>
|
||||
</TabItem>
|
||||
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.CommitDetail.Files}"/>
|
||||
</TabItem.Header>
|
||||
<v:RevisionFiles/>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</UserControl>
|
41
src/Views/CommitDetail.axaml.cs
Normal file
41
src/Views/CommitDetail.axaml.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CommitDetail : UserControl
|
||||
{
|
||||
public CommitDetail()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnChangeListDoubleTapped(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.CommitDetail detail)
|
||||
{
|
||||
var datagrid = sender as DataGrid;
|
||||
detail.ActivePageIndex = 1;
|
||||
detail.SelectedChange = datagrid.SelectedItem as Models.Change;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnChangeListContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.CommitDetail detail)
|
||||
{
|
||||
var datagrid = sender as DataGrid;
|
||||
if (datagrid.SelectedItem == null)
|
||||
{
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = detail.CreateChangeContextMenu(datagrid.SelectedItem as Models.Change);
|
||||
menu.Open(datagrid);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
76
src/Views/CreateBranch.axaml
Normal file
76
src/Views/CreateBranch.axaml
Normal file
|
@ -0,0 +1,76 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CreateBranch"
|
||||
x:DataType="vm:CreateBranch">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.CreateBranch}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.CreateBranch.BasedOn}"/>
|
||||
<ContentControl Grid.Column="1" Content="{Binding BasedOn}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:Branch">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Converter={x:Static c:BranchConverters.ToName}}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Tag">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Tag}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.CreateBranch.Name}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Text="{Binding Name, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.CreateBranch.LocalChanges}"/>
|
||||
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal">
|
||||
<RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.StashAndReply}"
|
||||
GroupName="LocalChanges"
|
||||
IsChecked="{Binding AutoStash, Mode=TwoWay}"/>
|
||||
<RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.Discard}"
|
||||
GroupName="LocalChanges"
|
||||
Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="1"
|
||||
Content="{DynamicResource Text.CreateBranch.Checkout}"
|
||||
IsChecked="{Binding CheckoutAfterCreated, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/CreateBranch.axaml.cs
Normal file
12
src/Views/CreateBranch.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CreateBranch : UserControl
|
||||
{
|
||||
public CreateBranch()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
18
src/Views/CreateGroup.axaml
Normal file
18
src/Views/CreateGroup.axaml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CreateGroup"
|
||||
x:DataType="vm:CreateGroup">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock Classes="bold" FontSize="18" Text="{DynamicResource Text.Welcome.AddRootFolder}"/>
|
||||
|
||||
<Grid Margin="8,16,0,0" Height="28" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="8,0" Text="{DynamicResource Text.Name}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" v:AutoFocusBehaviour.IsEnabled="True" Text="{Binding Name, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/CreateGroup.axaml.cs
Normal file
12
src/Views/CreateGroup.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CreateGroup : UserControl
|
||||
{
|
||||
public CreateGroup()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
64
src/Views/CreateTag.axaml
Normal file
64
src/Views/CreateTag.axaml
Normal file
|
@ -0,0 +1,64 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.CreateTag"
|
||||
x:DataType="vm:CreateTag">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.CreateTag}"/>
|
||||
<Grid Margin="0,16,8,0" RowDefinitions="32,32,64" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.CreateTag.BasedOn}"/>
|
||||
<ContentControl Grid.Column="1" Content="{Binding BasedOn}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:Branch">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Converter={x:Static c:BranchConverters.ToName}}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.CreateTag.Name}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Text="{Binding TagName, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Margin="0,6,8,0"
|
||||
Text="{DynamicResource Text.CreateTag.Message}"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1"
|
||||
Height="56"
|
||||
AcceptsReturn="True" AcceptsTab="False"
|
||||
VerticalAlignment="Center" VerticalContentAlignment="Top"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.CreateTag.Message.Placeholder}"
|
||||
Text="{Binding Message, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/CreateTag.axaml.cs
Normal file
12
src/Views/CreateTag.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class CreateTag : UserControl
|
||||
{
|
||||
public CreateTag()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
20
src/Views/DeleteBranch.axaml
Normal file
20
src/Views/DeleteBranch.axaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.DeleteBranch"
|
||||
x:DataType="vm:DeleteBranch">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.DeleteBranch}"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,16,0,0">
|
||||
<TextBlock Text="{DynamicResource Text.DeleteBranch.Branch}"/>
|
||||
<Path Width="14" Height="14" Margin="8,0" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Target, Converter={x:Static c:BranchConverters.ToName}}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/DeleteBranch.axaml.cs
Normal file
12
src/Views/DeleteBranch.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class DeleteBranch : UserControl
|
||||
{
|
||||
public DeleteBranch()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
19
src/Views/DeleteRemote.axaml
Normal file
19
src/Views/DeleteRemote.axaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.DeleteRemote"
|
||||
x:DataType="vm:DeleteRemote">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.DeleteRemote}"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,16,0,0">
|
||||
<TextBlock Text="{DynamicResource Text.DeleteRemote.Remote}"/>
|
||||
<Path Width="14" Height="14" Margin="8,6,8,0" Data="{StaticResource Icons.Remote}"/>
|
||||
<TextBlock Text="{Binding Remote.Name}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/DeleteRemote.axaml.cs
Normal file
12
src/Views/DeleteRemote.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class DeleteRemote : UserControl
|
||||
{
|
||||
public DeleteRemote()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
44
src/Views/DeleteRepositoryNode.axaml
Normal file
44
src/Views/DeleteRepositoryNode.axaml
Normal file
|
@ -0,0 +1,44 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:c="using:SourceGit.Converters"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.DeleteRepositoryNode"
|
||||
x:DataType="vm:DeleteRepositoryNode">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.DeleteRepositoryNode.TitleForGroup}"
|
||||
IsVisible="{Binding !Node.IsRepository}"/>
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.DeleteRepositoryNode.TitleForRepository}"
|
||||
IsVisible="{Binding Node.IsRepository}"/>
|
||||
|
||||
<Grid Margin="0,16,8,0" Height="28" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.DeleteRepositoryNode.Target}"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Margin="0,0,8,0"
|
||||
Fill="{Binding Node.Bookmark, Converter={x:Static c:BookmarkConverters.ToBrush}}"
|
||||
StrokeThickness="{Binding Node.Bookmark, Converter={x:Static c:BookmarkConverters.ToStrokeThickness}}"
|
||||
Stroke="{DynamicResource Brush.FG1}"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Bookmark}"
|
||||
IsVisible="{Binding Node.IsRepository}"/>
|
||||
<Path Width="12" Height="12" Margin="0,0,8,0"
|
||||
Fill="{DynamicResource Brush.FG1}"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Folder}"
|
||||
IsVisible="{Binding !Node.IsRepository}"/>
|
||||
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Node.Name}"/>
|
||||
<TextBlock Margin="8,0" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="{DynamicResource Brush.FG2}" Text="{Binding Node.Id}" IsVisible="{Binding Node.IsRepository}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/DeleteRepositoryNode.axaml.cs
Normal file
12
src/Views/DeleteRepositoryNode.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class DeleteRepositoryNode : UserControl
|
||||
{
|
||||
public DeleteRepositoryNode()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
26
src/Views/DeleteSubmodule.axaml
Normal file
26
src/Views/DeleteSubmodule.axaml
Normal file
|
@ -0,0 +1,26 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:c="using:SourceGit.Converters"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.DeleteSubmodule"
|
||||
x:DataType="vm:DeleteSubmodule">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.DeleteSubmodule}"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,16,0,0" Height="28" HorizontalAlignment="Center">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.DeleteSubmodule.Path}"/>
|
||||
<Path Width="12" Height="12"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Submodule}"/>
|
||||
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Submodule}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/DeleteSubmodule.axaml.cs
Normal file
12
src/Views/DeleteSubmodule.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class DeleteSubmodule : UserControl
|
||||
{
|
||||
public DeleteSubmodule()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
29
src/Views/DeleteTag.axaml
Normal file
29
src/Views/DeleteTag.axaml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.DeleteTag"
|
||||
x:DataType="vm:DeleteTag">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.DeleteTag}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.DeleteTag.Tag}"/>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Tag}"/>
|
||||
<TextBlock Text="{Binding Target.Name}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="1"
|
||||
Content="{DynamicResource Text.DeleteTag.WithRemote}"
|
||||
IsChecked="{Binding ShouldPushToRemote, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/DeleteTag.axaml.cs
Normal file
12
src/Views/DeleteTag.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class DeleteTag : UserControl
|
||||
{
|
||||
public DeleteTag()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
179
src/Views/DiffView.axaml
Normal file
179
src/Views/DiffView.axaml
Normal file
|
@ -0,0 +1,179 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.DiffView"
|
||||
x:DataType="vm:DiffContext">
|
||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" Background="{DynamicResource Brush.Window}">
|
||||
<Grid RowDefinitions="26,*">
|
||||
<!-- Toolbar -->
|
||||
<Border Grid.Row="0" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" IsVisible="{Binding IsOrgFilePathVisible}" VerticalAlignment="Center">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.File}" Margin="8,0,0,0"/>
|
||||
<TextBlock Classes="monospace" Margin="4,0,0,0" Text="{Binding OrgFilePath, Converter={x:Static c:PathConverters.TruncateIfTooLong}}" FontSize="11"/>
|
||||
<TextBlock Margin="8,0,0,0" Text="→"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.File}" Margin="8,0,0,0"/>
|
||||
<TextBlock Classes="monospace" Margin="4,0,0,0" Text="{Binding FilePath, Converter={x:Static c:PathConverters.TruncateIfTooLong}}" FontSize="11"/>
|
||||
<Path Classes="rotating" Width="10" Height="10" Margin="8,0" Data="{DynamicResource Icons.Loading}" IsVisible="{Binding IsLoading}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="2" Margin="32,0,0,0" Orientation="Horizontal" IsVisible="{Binding IsTextDiff}" VerticalAlignment="Center">
|
||||
<ToggleButton Classes="line_path"
|
||||
Width="32" Height="18"
|
||||
Background="Transparent"
|
||||
Padding="9,6"
|
||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting, Mode=TwoWay}"
|
||||
ToolTip.Tip="{DynamicResource Text.Diff.SyntaxHighlight}">
|
||||
<Path Width="13" Height="13" Data="{StaticResource Icons.SyntaxHighlight}" Margin="0,3,0,0"/>
|
||||
</ToggleButton>
|
||||
|
||||
<ToggleButton Classes="line_path"
|
||||
Width="32" Height="18"
|
||||
Background="Transparent"
|
||||
Padding="9,6"
|
||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=TwoWay}"
|
||||
ToolTip.Tip="{DynamicResource Text.Diff.SideBySide}">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.LayoutHorizontal}" Margin="0,2,0,0"/>
|
||||
</ToggleButton>
|
||||
|
||||
<Button Classes="icon_button" Width="32" Command="{Binding OpenExternalMergeTool}" ToolTip.Tip="{DynamicResource Text.Diff.UseMerger}">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Data="{StaticResource Icons.OpenWith}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Diff Contents -->
|
||||
<ContentControl Grid.Row="1" Content="{Binding Content}">
|
||||
<ContentControl.DataTemplates>
|
||||
<!-- Binary Diff -->
|
||||
<DataTemplate DataType="m:BinaryDiff">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
|
||||
<TextBlock Text="{DynamicResource Text.Diff.Binary}"
|
||||
Margin="0,0,0,32"
|
||||
FontSize="18" FontWeight="Bold"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
HorizontalAlignment="Center"/>
|
||||
<Path Width="64" Height="64" Data="{StaticResource Icons.Binary}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<Grid Margin="0,16,0,0" HorizontalAlignment="Center" RowDefinitions="32,32" ColumnDefinitions="Auto,Auto,Auto">
|
||||
<Border Grid.Row="0" Grid.Column="0" Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
|
||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Classes="monospace" Text="{Binding OldSize}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right" FontSize="16" Margin="8,0"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="2" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" FontSize="16"/>
|
||||
|
||||
<Border Grid.Row="1" Grid.Column="0" Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center">
|
||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Classes="monospace" Text="{Binding NewSize}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right" FontSize="16" Margin="8,0"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" FontSize="16"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- LFS Diff -->
|
||||
<DataTemplate DataType="m:LFSDiff">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
|
||||
<TextBlock Text="{DynamicResource Text.Diff.LFS}"
|
||||
Margin="0,0,0,32"
|
||||
FontSize="18" FontWeight="Bold"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
HorizontalAlignment="Center"/>
|
||||
<Path Width="64" Height="64" Data="{StaticResource Icons.LFS}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<Grid Margin="0,16,0,0" HorizontalAlignment="Center" RowDefinitions="32,32" ColumnDefinitions="Auto,Auto,Auto">
|
||||
<Border Grid.Row="0" Grid.Column="0" Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
|
||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Classes="monospace" Text="{Binding Old.Size}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right" FontSize="16" Margin="8,0"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="2" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" FontSize="16"/>
|
||||
|
||||
<Border Grid.Row="1" Grid.Column="0" Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center">
|
||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Classes="monospace" Text="{Binding New.Size}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right" FontSize="16" Margin="8,0"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" FontSize="16"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Image Diff -->
|
||||
<DataTemplate DataType="m:ImageDiff">
|
||||
<Grid RowDefinitions="Auto,*,Auto" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="8,8,8,0">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto,Auto">
|
||||
<Border Grid.Column="0" Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
|
||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding OldSize}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
|
||||
|
||||
<Border Grid.Column="3" Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center" Margin="32,0,0,0">
|
||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Column="4" Classes="monospace" Text="{Binding NewSize}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1" Background="{DynamicResource Brush.Window}" Effect="drop-shadow(0 0 8 #A0000000)" Margin="0,8,0,0" HorizontalAlignment="Center">
|
||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
||||
<v:ImageDiffView Alpha="{Binding #ImageDiffSlider.Value}"
|
||||
OldImage="{Binding Old}"
|
||||
NewImage="{Binding New}"
|
||||
RenderOptions.BitmapInterpolationMode="HighQuality"/>
|
||||
</Border>
|
||||
</Border>
|
||||
|
||||
<Slider Grid.Row="2"
|
||||
x:Name="ImageDiffSlider"
|
||||
Minimum="0" Maximum="1"
|
||||
VerticalAlignment="Top"
|
||||
TickPlacement="None"
|
||||
Margin="0,4,0,0"
|
||||
MinHeight="0"
|
||||
Foreground="{DynamicResource Brush.Border1}"
|
||||
Value="0.5">
|
||||
<Slider.Resources>
|
||||
<Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness>
|
||||
<GridLength x:Key="SliderPreContentMargin">0</GridLength>
|
||||
<GridLength x:Key="SliderPostContentMargin">0</GridLength>
|
||||
<CornerRadius x:Key="SliderThumbCornerRadius">8</CornerRadius>
|
||||
<x:Double x:Key="SliderHorizontalThumbWidth">16</x:Double>
|
||||
<x:Double x:Key="SliderHorizontalThumbHeight">16</x:Double>
|
||||
</Slider.Resources>
|
||||
</Slider>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Text Diff -->
|
||||
<DataTemplate DataType="m:TextDiff">
|
||||
<v:TextDiffView TextDiff="{Binding}" UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- No or only EOL changes -->
|
||||
<DataTemplate DataType="m:NoOrEOLChange">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
|
||||
<Path Width="64" Height="64" Data="{StaticResource Icons.Check}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<TextBlock Margin="0,16,0,0"
|
||||
Text="{DynamicResource Text.Diff.NoChange}"
|
||||
FontSize="18" FontWeight="Bold"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
169
src/Views/DiffView.axaml.cs
Normal file
169
src/Views/DiffView.axaml.cs
Normal file
|
@ -0,0 +1,169 @@
|
|||
using System;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class ImageDiffView : Control
|
||||
{
|
||||
public static readonly StyledProperty<double> AlphaProperty =
|
||||
AvaloniaProperty.Register<ImageDiffView, double>(nameof(Alpha), 0.5);
|
||||
|
||||
public double Alpha
|
||||
{
|
||||
get => GetValue(AlphaProperty);
|
||||
set => SetValue(AlphaProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Bitmap> OldImageProperty =
|
||||
AvaloniaProperty.Register<ImageDiffView, Bitmap>(nameof(OldImage), null);
|
||||
|
||||
public Bitmap OldImage
|
||||
{
|
||||
get => GetValue(OldImageProperty);
|
||||
set => SetValue(OldImageProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Bitmap> NewImageProperty =
|
||||
AvaloniaProperty.Register<ImageDiffView, Bitmap>(nameof(NewImage), null);
|
||||
|
||||
public Bitmap NewImage
|
||||
{
|
||||
get => GetValue(NewImageProperty);
|
||||
set => SetValue(NewImageProperty, value);
|
||||
}
|
||||
|
||||
static ImageDiffView()
|
||||
{
|
||||
AffectsMeasure<ImageDiffView>(OldImageProperty, NewImageProperty);
|
||||
AffectsRender<ImageDiffView>(AlphaProperty);
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
if (_bgBrush == null)
|
||||
{
|
||||
var maskBrush = new SolidColorBrush(ActualThemeVariant == ThemeVariant.Dark ? 0xFF404040 : 0xFFBBBBBB);
|
||||
var bg = new DrawingGroup()
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new GeometryDrawing() { Brush = maskBrush, Geometry = new RectangleGeometry(new Rect(0, 0, 12, 12)) },
|
||||
new GeometryDrawing() { Brush = maskBrush, Geometry = new RectangleGeometry(new Rect(12, 12, 12, 12)) },
|
||||
}
|
||||
};
|
||||
|
||||
_bgBrush = new DrawingBrush(bg)
|
||||
{
|
||||
AlignmentX = AlignmentX.Left,
|
||||
AlignmentY = AlignmentY.Top,
|
||||
DestinationRect = new RelativeRect(new Size(24, 24), RelativeUnit.Absolute),
|
||||
Stretch = Stretch.None,
|
||||
TileMode = TileMode.Tile,
|
||||
};
|
||||
}
|
||||
|
||||
context.FillRectangle(_bgBrush, new Rect(Bounds.Size));
|
||||
|
||||
var alpha = Alpha;
|
||||
var w = Bounds.Width - 16;
|
||||
var h = Bounds.Height - 16;
|
||||
var x = w * alpha;
|
||||
var left = OldImage;
|
||||
if (left != null && alpha > 0)
|
||||
{
|
||||
var src = new Rect(0, 0, left.Size.Width * alpha, left.Size.Height);
|
||||
var dst = new Rect(8, 8, x, h);
|
||||
context.DrawImage(left, src, dst);
|
||||
}
|
||||
|
||||
var right = NewImage;
|
||||
if (right != null && alpha < 1)
|
||||
{
|
||||
var src = new Rect(right.Size.Width * alpha, 0, right.Size.Width * (1 - alpha), right.Size.Height);
|
||||
var dst = new Rect(x + 8, 8, w - x, h);
|
||||
context.DrawImage(right, src, dst);
|
||||
}
|
||||
|
||||
context.DrawLine(new Pen(Brushes.DarkGreen, 2), new Point(x + 8, 0), new Point(x + 8, Bounds.Height));
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property.Name == "ActualThemeVariant")
|
||||
{
|
||||
_bgBrush = null;
|
||||
InvalidateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var left = OldImage;
|
||||
var right = NewImage;
|
||||
|
||||
if (left != null)
|
||||
{
|
||||
var lSize = GetDesiredSize(left.Size, availableSize);
|
||||
if (right != null)
|
||||
{
|
||||
var rSize = GetDesiredSize(right.Size, availableSize);
|
||||
if (rSize.Width > lSize.Width)
|
||||
return rSize;
|
||||
return lSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lSize;
|
||||
}
|
||||
}
|
||||
else if (right != null)
|
||||
{
|
||||
return GetDesiredSize(right.Size, availableSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return availableSize;
|
||||
}
|
||||
}
|
||||
|
||||
private Size GetDesiredSize(Size img, Size available)
|
||||
{
|
||||
var w = available.Width - 16;
|
||||
var h = available.Height - 16;
|
||||
|
||||
if (img.Width <= w)
|
||||
{
|
||||
if (img.Height <= h)
|
||||
{
|
||||
return new Size(img.Width + 16, img.Height + 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Size(h * img.Width / img.Height + 16, available.Height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var s = Math.Max(img.Width / w, img.Height / h);
|
||||
return new Size(img.Width / s + 16, img.Height / s + 16);
|
||||
}
|
||||
}
|
||||
|
||||
private DrawingBrush _bgBrush = null;
|
||||
}
|
||||
|
||||
public partial class DiffView : UserControl
|
||||
{
|
||||
public DiffView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
45
src/Views/Discard.axaml
Normal file
45
src/Views/Discard.axaml
Normal file
|
@ -0,0 +1,45 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Discard"
|
||||
x:DataType="vm:Discard">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Discard}"/>
|
||||
|
||||
<Grid Margin="0,16,0,8" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,8,0" HorizontalAlignment="Right" Text="{DynamicResource Text.Discard.Changes}"/>
|
||||
<ContentControl Grid.Row="0" Grid.Column="1" Content="{Binding Mode}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:DiscardModeAll">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Margin="0,2,0,0" Data="{StaticResource Icons.Folder.Open}"/>
|
||||
<TextBlock Text="{DynamicResource Text.Discard.All}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:DiscardModeSingle">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.File}"/>
|
||||
<TextBlock Text="{Binding File}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:DiscardModeMulti">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.File}"/>
|
||||
<TextBlock Text="{Binding Count, Converter={x:Static c:StringConverters.FormatByResourceKey}, ConverterParameter='Discard.Total'}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Text="{DynamicResource Text.Discard.Warning}" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Discard.axaml.cs
Normal file
12
src/Views/Discard.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Discard : UserControl
|
||||
{
|
||||
public Discard()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
29
src/Views/DropStash.axaml
Normal file
29
src/Views/DropStash.axaml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.DropStash"
|
||||
x:DataType="vm:DropStash">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.StashDropConfirm}"/>
|
||||
<Grid Margin="0,16,8,0" Height="28" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.StashDropConfirm.Label}"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Margin="0,0,8,0"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Stashes}"/>
|
||||
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Stash.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Stash.Message}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/DropStash.axaml.cs
Normal file
12
src/Views/DropStash.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class DropStash : UserControl
|
||||
{
|
||||
public DropStash()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
61
src/Views/EditRemote.axaml
Normal file
61
src/Views/EditRemote.axaml
Normal file
|
@ -0,0 +1,61 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.EditRemote"
|
||||
x:DataType="vm:EditRemote">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Remote.AddTitle}"/>
|
||||
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,Auto" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Remote.Name}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.Remote.Name.Placeholder}"
|
||||
Text="{Binding Name, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Remote.URL}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.Remote.URL.Placeholder}"
|
||||
Text="{Binding Url, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.SSHKey}"
|
||||
IsVisible="{Binding UseSSH}"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1"
|
||||
x:Name="txtSSHKey"
|
||||
Height="26"
|
||||
CornerRadius="3"
|
||||
IsVisible="{Binding UseSSH}"
|
||||
Watermark="{DynamicResource Text.SSHKey.Placeholder}"
|
||||
Text="{Binding SSHKey, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectSSHKey">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
27
src/Views/EditRemote.axaml.cs
Normal file
27
src/Views/EditRemote.axaml.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class EditRemote : UserControl
|
||||
{
|
||||
public EditRemote()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void SelectSSHKey(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("SSHKey") { Patterns = ["*.*"] }] };
|
||||
var toplevel = TopLevel.GetTopLevel(this);
|
||||
var selected = await toplevel.StorageProvider.OpenFilePickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
txtSSHKey.Text = selected[0].Path.LocalPath;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
54
src/Views/EditRepositoryNode.axaml
Normal file
54
src/Views/EditRepositoryNode.axaml
Normal file
|
@ -0,0 +1,54 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.EditRepositoryNode"
|
||||
x:DataType="vm:EditRepositoryNode">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.EditRepositoryNode.TitleForGroup}"
|
||||
IsVisible="{Binding !IsRepository}"/>
|
||||
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.EditRepositoryNode.TitleForRepository}"
|
||||
IsVisible="{Binding IsRepository}"/>
|
||||
|
||||
<Grid Height="28" Margin="8,16,0,0" ColumnDefinitions="120,*" >
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,8,0" Text="{DynamicResource Text.EditRepositoryNode.Target}"/>
|
||||
<TextBlock Grid.Column="1" VerticalAlignment="Center" Text="{Binding Name, Mode=OneTime}" IsVisible="{Binding !IsRepository}"/>
|
||||
<TextBlock Grid.Column="1" VerticalAlignment="Center" Text="{Binding Id, Mode=TwoWay}" IsVisible="{Binding IsRepository}"/>
|
||||
</Grid>
|
||||
<Grid Height="28" Margin="8,4,0,0" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.EditRepositoryNode.Name}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" Text="{Binding Name, Mode=TwoWay}" v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
</Grid>
|
||||
<Grid Height="28" Margin="8,4,0,0" ColumnDefinitions="120,*" IsVisible="{Binding IsRepository}">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.EditRepositoryNode.Bookmark}"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
BorderThickness="0"
|
||||
Height="28"
|
||||
ItemsSource="{x:Static m:Bookmarks.Supported}"
|
||||
SelectedIndex="{Binding Bookmark, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Height="20" VerticalAlignment="Center">
|
||||
<Path Width="12" Height="12"
|
||||
Fill="{Binding Converter={x:Static c:BookmarkConverters.ToBrush}}"
|
||||
StrokeThickness="{Binding Converter={x:Static c:BookmarkConverters.ToStrokeThickness}}"
|
||||
Stroke="{DynamicResource Brush.FG1}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Bookmark}"/>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/EditRepositoryNode.axaml.cs
Normal file
12
src/Views/EditRepositoryNode.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class EditRepositoryNode : UserControl
|
||||
{
|
||||
public EditRepositoryNode()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
22
src/Views/FastForwardWithoutCheckout.axaml
Normal file
22
src/Views/FastForwardWithoutCheckout.axaml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.FastForwardWithoutCheckout"
|
||||
x:DataType="vm:FastForwardWithoutCheckout">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.FastForwardWithoutCheck}"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,16,0,0">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Local.Name}" Margin="8,0,0,0"/>
|
||||
<TextBlock Text="→" Margin="8,0"/>
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding To, Converter={x:Static c:BranchConverters.ToName}}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/FastForwardWithoutCheckout.axaml.cs
Normal file
12
src/Views/FastForwardWithoutCheckout.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class FastForwardWithoutCheckout : UserControl
|
||||
{
|
||||
public FastForwardWithoutCheckout()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
45
src/Views/Fetch.axaml
Normal file
45
src/Views/Fetch.axaml
Normal file
|
@ -0,0 +1,45 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Fetch"
|
||||
x:DataType="vm:Fetch">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Fetch.Title}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Fetch.Remote}"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Remotes}"
|
||||
SelectedItem="{Binding SelectedRemote, Mode=TwoWay}"
|
||||
IsEnabled="{Binding !FetchAllRemotes}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Remote}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Remote}"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Fetch.AllRemotes}"
|
||||
IsChecked="{Binding FetchAllRemotes, Mode=TwoWay}"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Fetch.Prune}"
|
||||
IsChecked="{Binding Prune, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Fetch.axaml.cs
Normal file
12
src/Views/Fetch.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Fetch : UserControl
|
||||
{
|
||||
public Fetch()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
208
src/Views/FileHistories.axaml
Normal file
208
src/Views/FileHistories.axaml
Normal file
|
@ -0,0 +1,208 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.FileHistories"
|
||||
x:DataType="vm:FileHistories"
|
||||
x:Name="me"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.FileHistory}"
|
||||
Background="Transparent"
|
||||
MinWidth="1280" MinHeight="720"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid Margin="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToContentMargin}}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
|
||||
<!-- Bottom border -->
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="5"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<!-- Caption Buttons (macOS) -->
|
||||
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<v:CaptionButtonsMacOS/>
|
||||
</Border>
|
||||
|
||||
<!-- Icon -->
|
||||
<Path Grid.Column="1" Margin="8,0,0,0" Width="12" Height="12" Stretch="Uniform" Data="{StaticResource Icons.Histories}"/>
|
||||
|
||||
<!-- Title -->
|
||||
<TextBlock Grid.Column="2" Margin="4,0,0,0" Text="{DynamicResource Text.FileHistory}" FontWeight="Bold" IsHitTestVisible="False" VerticalAlignment="Center"/>
|
||||
|
||||
<!-- Caption Buttons (Windows/Linux) -->
|
||||
<Border Grid.Column="3" IsVisible="{OnPlatform True, macOS=False}">
|
||||
<v:CaptionButtons/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Grid Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" MinWidth="300" MaxWidth="600"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<DataGrid Grid.Column="0"
|
||||
Background="Transparent"
|
||||
ItemsSource="{Binding Commits}"
|
||||
SelectedItem="{Binding SelectedCommit, Mode=TwoWay}"
|
||||
SelectionMode="Single"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="None"
|
||||
Focusable="False"
|
||||
RowHeight="50"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" Classes="monospace" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" Cursor="Hand"/>
|
||||
<TextBlock Grid.Column="3" Classes="monospace" Text="{Binding AuthorTimeShortStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Classes="monospace" Text="{Binding Subject}" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<GridSplitter Grid.Column="1"
|
||||
MinWidth="1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
BorderThickness="1,0,0,0"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"/>
|
||||
|
||||
<Path Grid.Column="2"
|
||||
Classes="rotating"
|
||||
Width="48" Height="48"
|
||||
Data="{DynamicResource Icons.Loading}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsLoading}"/>
|
||||
|
||||
<Grid Grid.Column="2" RowDefinitions="*,3,*" Margin="0,4,4,4" IsVisible="{Binding !IsLoading}">
|
||||
<ContentControl Grid.Row="0" Content="{Binding DiffContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:DiffContext">
|
||||
<v:DiffView/>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
||||
<GridSplitter Grid.Row="1"
|
||||
MinHeight="1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Background="Transparent"/>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Border Background="{DynamicResource Brush.Window}">
|
||||
<Path Width="128" Height="128"
|
||||
Data="{StaticResource Icons.Detail}"
|
||||
HorizontalAlignment="Center"
|
||||
Fill="{DynamicResource Brush.FG2}"/>
|
||||
</Border>
|
||||
|
||||
<ContentControl Content="{Binding DetailContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:CommitDetail">
|
||||
<v:CommitDetail/>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Custom window sizer for Linux -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="2" IsVisible="{OnPlatform False, Linux=True}" IsHitTestVisible="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.IsNormal}}">
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Cursor="TopLeftCorner"
|
||||
Tag="{x:Static WindowEdge.NorthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
Cursor="TopSide"
|
||||
Tag="{x:Static WindowEdge.North}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Cursor="TopRightCorner"
|
||||
Tag="{x:Static WindowEdge.NorthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch"
|
||||
Cursor="LeftSide"
|
||||
Tag="{x:Static WindowEdge.West}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Stretch"
|
||||
Cursor="RightSide"
|
||||
Tag="{x:Static WindowEdge.East}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||
Cursor="BottomLeftCorner"
|
||||
Tag="{x:Static WindowEdge.SouthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
|
||||
Cursor="BottomSide"
|
||||
Tag="{x:Static WindowEdge.South}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Cursor="BottomRightCorner"
|
||||
Tag="{x:Static WindowEdge.SouthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
42
src/Views/FileHistories.axaml.cs
Normal file
42
src/Views/FileHistories.axaml.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class FileHistories : Window
|
||||
{
|
||||
public FileHistories()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = WindowState.Maximized;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void CustomResizeWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
if (border.Tag is WindowEdge edge)
|
||||
{
|
||||
BeginResizeDrag(edge, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
}
|
||||
}
|
39
src/Views/GitFlowFinish.axaml
Normal file
39
src/Views/GitFlowFinish.axaml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.GitFlowFinish"
|
||||
x:DataType="vm:GitFlowFinish">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.GitFlow.FinishFeature}"
|
||||
IsVisible="{Binding IsFeature}"/>
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.GitFlow.FinishRelease}"
|
||||
IsVisible="{Binding IsRelease}"/>
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.GitFlow.FinishHotfix}"
|
||||
IsVisible="{Binding IsHotfix}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.GitFlow.FinishTarget}"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Branch.Name}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="1"
|
||||
Content="{DynamicResource Text.GitFlow.KeepBranchAfterFinish}"
|
||||
IsChecked="{Binding KeepBranch, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/GitFlowFinish.axaml.cs
Normal file
12
src/Views/GitFlowFinish.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class GitFlowFinish : UserControl
|
||||
{
|
||||
public GitFlowFinish()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
39
src/Views/GitFlowStart.axaml
Normal file
39
src/Views/GitFlowStart.axaml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.GitFlowStart"
|
||||
x:DataType="vm:GitFlowStart">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.GitFlow.StartFeatureTitle}"
|
||||
IsVisible="{Binding IsFeature}"/>
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.GitFlow.StartReleaseTitle}"
|
||||
IsVisible="{Binding IsRelease}"/>
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.GitFlow.StartHotfixTitle}"
|
||||
IsVisible="{Binding IsHotfix}"/>
|
||||
<Grid Margin="0,16,0,0" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{Binding Prefix}"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.GitFlow.StartPlaceholder}"
|
||||
Text="{Binding Name, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/GitFlowStart.axaml.cs
Normal file
12
src/Views/GitFlowStart.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class GitFlowStart : UserControl
|
||||
{
|
||||
public GitFlowStart()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
184
src/Views/Histories.axaml
Normal file
184
src/Views/Histories.axaml
Normal file
|
@ -0,0 +1,184 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Histories"
|
||||
x:DataType="vm:Histories">
|
||||
<v:LayoutableGrid RowDefinitions="*,3,*" ColumnDefinitions="*,3,*"
|
||||
UseHorizontal="{Binding Source={x:Static vm:Preference.Instance}, Path=UseTwoColumnsLayoutInHistories}">
|
||||
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
|
||||
<DataGrid x:Name="commitDataGrid"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
ItemsSource="{Binding Commits}"
|
||||
SelectionMode="Extended"
|
||||
SelectedItem="{Binding AutoSelectedCommit, Mode=OneWay}"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="None"
|
||||
Focusable="False"
|
||||
RowHeight="{Binding DataGridRowHeight}"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
LayoutUpdated="OnCommitDataGridLayoutUpdated"
|
||||
SelectionChanged="OnCommitDataGridSelectionChanged"
|
||||
ContextRequested="OnCommitDataGridContextRequested">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="*" Header="GRAPH">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Commit}">
|
||||
<Border Margin="{Binding Margin}">
|
||||
<StackPanel Orientation="Horizontal" Margin="2,0,0,0">
|
||||
<ItemsControl ItemsSource="{Binding Decorators}" IsVisible="{Binding HasDecorators}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" VerticalAlignment="Center"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type m:Decorator}">
|
||||
<Border Height="16" Margin="0,0,4,0" CornerRadius="2" ClipToBounds="True">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Background="{DynamicResource Brush.Decorator}" Width="16">
|
||||
<Path Width="8" Height="8"
|
||||
Stretch="Uniform"
|
||||
Data="{Binding Type, Converter={x:Static c:DecoratorTypeConverters.ToIcon}}"
|
||||
Fill="{DynamicResource Brush.DecoratorIcon}"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<Border Background="{Binding Type, Converter={x:Static c:DecoratorTypeConverters.ToBackground}}">
|
||||
<TextBlock Classes="monospace" Text="{Binding Name}" FontSize="10" Margin="4,0" Foreground="Black"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<TextBlock Classes="monospace"
|
||||
Text="{Binding Subject}"
|
||||
Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.ToCommitOpacity}}"
|
||||
FontWeight="{Binding IsCurrentHead, Converter={x:Static c:BoolConverters.ToCommitFontWeight}}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Header="AVATAR">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Commit}">
|
||||
<v:Avatar Width="16" Height="16"
|
||||
Margin="16,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"
|
||||
User="{Binding Author}"
|
||||
Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.ToCommitOpacity}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn MaxWidth="100" Header="AUTHOR">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Commit}">
|
||||
<TextBlock Classes="monospace"
|
||||
Text="{Binding Author.Name}"
|
||||
Margin="0,0,8,0"
|
||||
Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.ToCommitOpacity}}"
|
||||
FontWeight="{Binding IsCurrentHead, Converter={x:Static c:BoolConverters.ToCommitFontWeight}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Header="SHA">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Commit}">
|
||||
<TextBlock Classes="monospace"
|
||||
Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
|
||||
Margin="12,0"
|
||||
Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.ToCommitOpacity}}"
|
||||
FontWeight="{Binding IsCurrentHead, Converter={x:Static c:BoolConverters.ToCommitFontWeight}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Header="TIME">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Commit}">
|
||||
<TextBlock Classes="monospace"
|
||||
Text="{Binding CommitterTimeStr}"
|
||||
Margin="8,0"
|
||||
Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.ToCommitOpacity}}"
|
||||
FontWeight="{Binding IsCurrentHead, Converter={x:Static c:BoolConverters.ToCommitFontWeight}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<v:CommitGraph x:Name="commitGraph"
|
||||
BindingDataGrid="{Binding #commitDataGrid}"
|
||||
Graph="{Binding Graph}"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
IsHitTestVisible="False"
|
||||
ClipToBounds="True"/>
|
||||
|
||||
<Path Classes="rotating"
|
||||
Width="48" Height="48"
|
||||
Data="{DynamicResource Icons.Loading}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsLoading}"/>
|
||||
</Grid>
|
||||
|
||||
<GridSplitter Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"
|
||||
MinWidth="1" MinHeight="1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
BorderBrush="{DynamicResource Brush.Border0}"/>
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3">
|
||||
<Border Background="{DynamicResource Brush.Window}">
|
||||
<Path Width="128" Height="128"
|
||||
Data="{StaticResource Icons.Detail}"
|
||||
HorizontalAlignment="Center"
|
||||
Fill="{DynamicResource Brush.FG2}"/>
|
||||
</Border>
|
||||
|
||||
<ContentControl Content="{Binding DetailContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:CommitDetail">
|
||||
<v:CommitDetail/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:RevisionCompare">
|
||||
<v:RevisionCompare/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:CountSelectedCommits">
|
||||
<Grid Background="{DynamicResource Brush.Window}">
|
||||
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Path Width="128" Height="128"
|
||||
Data="{StaticResource Icons.Detail}"
|
||||
HorizontalAlignment="Center"
|
||||
Fill="{DynamicResource Brush.FG2}"/>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Margin="0,16"
|
||||
FontSize="24" FontWeight="Bold"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
Text="{Binding Count, Converter={x:Static c:StringConverters.FormatByResourceKey}, ConverterParameter='Histories.Selected'}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</v:LayoutableGrid>
|
||||
</UserControl>
|
297
src/Views/Histories.axaml.cs
Normal file
297
src/Views/Histories.axaml.cs
Normal file
|
@ -0,0 +1,297 @@
|
|||
using System;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class LayoutableGrid : Grid
|
||||
{
|
||||
public static readonly StyledProperty<bool> UseHorizontalProperty =
|
||||
AvaloniaProperty.Register<LayoutableGrid, bool>(nameof(UseHorizontal), false);
|
||||
|
||||
public bool UseHorizontal
|
||||
{
|
||||
get => GetValue(UseHorizontalProperty);
|
||||
set => SetValue(UseHorizontalProperty, value);
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(Grid);
|
||||
|
||||
static LayoutableGrid()
|
||||
{
|
||||
UseHorizontalProperty.Changed.AddClassHandler<LayoutableGrid>((o, _) => o.RefreshLayout());
|
||||
}
|
||||
|
||||
public override void ApplyTemplate()
|
||||
{
|
||||
base.ApplyTemplate();
|
||||
RefreshLayout();
|
||||
}
|
||||
|
||||
private void RefreshLayout()
|
||||
{
|
||||
if (UseHorizontal)
|
||||
{
|
||||
var rowSpan = RowDefinitions.Count;
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
var child = Children[i];
|
||||
child.SetValue(RowProperty, 0);
|
||||
child.SetValue(RowSpanProperty, rowSpan);
|
||||
child.SetValue(ColumnProperty, i);
|
||||
child.SetValue(ColumnSpanProperty, 1);
|
||||
|
||||
if (child is GridSplitter splitter)
|
||||
splitter.BorderThickness = new Thickness(1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var colSpan = ColumnDefinitions.Count;
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
var child = Children[i];
|
||||
child.SetValue(RowProperty, i);
|
||||
child.SetValue(RowSpanProperty, 1);
|
||||
child.SetValue(ColumnProperty, 0);
|
||||
child.SetValue(ColumnSpanProperty, colSpan);
|
||||
|
||||
if (child is GridSplitter splitter)
|
||||
splitter.BorderThickness = new Thickness(0, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CommitGraph : Control
|
||||
{
|
||||
public static readonly Pen[] Pens = [
|
||||
new Pen(Brushes.Orange, 2),
|
||||
new Pen(Brushes.ForestGreen, 2),
|
||||
new Pen(Brushes.Gold, 2),
|
||||
new Pen(Brushes.Magenta, 2),
|
||||
new Pen(Brushes.Red, 2),
|
||||
new Pen(Brushes.Gray, 2),
|
||||
new Pen(Brushes.Turquoise, 2),
|
||||
new Pen(Brushes.Olive, 2),
|
||||
];
|
||||
|
||||
public static readonly StyledProperty<Models.CommitGraph> GraphProperty =
|
||||
AvaloniaProperty.Register<CommitGraph, Models.CommitGraph>(nameof(Graph));
|
||||
|
||||
public Models.CommitGraph Graph
|
||||
{
|
||||
get => GetValue(GraphProperty);
|
||||
set => SetValue(GraphProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<DataGrid> BindingDataGridProperty =
|
||||
AvaloniaProperty.Register<CommitGraph, DataGrid>(nameof(BindingDataGrid));
|
||||
|
||||
public DataGrid BindingDataGrid
|
||||
{
|
||||
get => GetValue(BindingDataGridProperty);
|
||||
set => SetValue(BindingDataGridProperty, value);
|
||||
}
|
||||
|
||||
static CommitGraph()
|
||||
{
|
||||
AffectsRender<CommitGraph>(BindingDataGridProperty, GraphProperty);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property.Name == "ActualThemeVariant")
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
base.Render(context);
|
||||
|
||||
var graph = Graph;
|
||||
var grid = BindingDataGrid;
|
||||
if (graph == null || grid == null)
|
||||
return;
|
||||
|
||||
var rowsPresenter = grid.FindDescendantOfType<DataGridRowsPresenter>();
|
||||
if (rowsPresenter == null)
|
||||
return;
|
||||
|
||||
// Find the content display offset Y of binding DataGrid.
|
||||
double rowHeight = grid.RowHeight;
|
||||
double startY = 0;
|
||||
foreach (var child in rowsPresenter.Children)
|
||||
{
|
||||
var row = child as DataGridRow;
|
||||
if (row.IsVisible && row.Bounds.Top <= 0 && row.Bounds.Top > -rowHeight)
|
||||
{
|
||||
var test = rowHeight * row.GetIndex() - row.Bounds.Top;
|
||||
if (startY < test)
|
||||
startY = test;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply scroll offset.
|
||||
context.PushClip(new Rect(Bounds.Left, Bounds.Top, grid.Columns[0].ActualWidth, Bounds.Height));
|
||||
context.PushTransform(Matrix.CreateTranslation(0, -startY));
|
||||
|
||||
// Calculate bounds.
|
||||
var top = startY;
|
||||
var bottom = startY + grid.Bounds.Height + rowHeight * 2;
|
||||
|
||||
// Draw all curves
|
||||
DrawCurves(context, top, bottom);
|
||||
|
||||
// Draw connect dots
|
||||
Brush dotFill = null;
|
||||
if (App.Current.TryGetResource("Brush.Contents", App.Current.ActualThemeVariant, out object res) && res is SolidColorBrush)
|
||||
{
|
||||
dotFill = res as SolidColorBrush;
|
||||
}
|
||||
foreach (var dot in graph.Dots)
|
||||
{
|
||||
if (dot.Center.Y < top)
|
||||
continue;
|
||||
if (dot.Center.Y > bottom)
|
||||
break;
|
||||
|
||||
context.DrawEllipse(dotFill, Pens[dot.Color], dot.Center, 3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCurves(DrawingContext context, double top, double bottom)
|
||||
{
|
||||
foreach (var line in Graph.Paths)
|
||||
{
|
||||
var last = line.Points[0];
|
||||
var size = line.Points.Count;
|
||||
|
||||
if (line.Points[size - 1].Y < top)
|
||||
continue;
|
||||
if (last.Y > bottom)
|
||||
continue;
|
||||
|
||||
var geo = new StreamGeometry();
|
||||
var pen = Pens[line.Color];
|
||||
using (var ctx = geo.Open())
|
||||
{
|
||||
var started = false;
|
||||
var ended = false;
|
||||
for (int i = 1; i < size; i++)
|
||||
{
|
||||
var cur = line.Points[i];
|
||||
if (cur.Y < top)
|
||||
{
|
||||
last = cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!started)
|
||||
{
|
||||
ctx.BeginFigure(last, false);
|
||||
started = true;
|
||||
}
|
||||
|
||||
if (cur.Y > bottom)
|
||||
{
|
||||
cur = new Point(cur.X, bottom);
|
||||
ended = true;
|
||||
}
|
||||
|
||||
if (cur.X > last.X)
|
||||
{
|
||||
ctx.QuadraticBezierTo(new Point(cur.X, last.Y), cur);
|
||||
}
|
||||
else if (cur.X < last.X)
|
||||
{
|
||||
if (i < size - 1)
|
||||
{
|
||||
var midY = (last.Y + cur.Y) / 2;
|
||||
var midX = (last.X + cur.X) / 2;
|
||||
ctx.QuadraticBezierTo(new Point(last.X, midY), new Point(midX, midY));
|
||||
ctx.QuadraticBezierTo(new Point(cur.X, midY), cur);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.QuadraticBezierTo(new Point(last.X, cur.Y), cur);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.LineTo(cur);
|
||||
}
|
||||
|
||||
if (ended)
|
||||
break;
|
||||
last = cur;
|
||||
}
|
||||
}
|
||||
|
||||
context.DrawGeometry(null, pen, geo);
|
||||
}
|
||||
|
||||
foreach (var link in Graph.Links)
|
||||
{
|
||||
if (link.End.Y < top)
|
||||
continue;
|
||||
if (link.Start.Y > bottom)
|
||||
break;
|
||||
|
||||
var geo = new StreamGeometry();
|
||||
using (var ctx = geo.Open())
|
||||
{
|
||||
ctx.BeginFigure(link.Start, false);
|
||||
ctx.QuadraticBezierTo(link.Control, link.End);
|
||||
}
|
||||
|
||||
context.DrawGeometry(null, Pens[link.Color], geo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Histories : UserControl
|
||||
{
|
||||
public Histories()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnCommitDataGridLayoutUpdated(object sender, EventArgs e)
|
||||
{
|
||||
commitGraph.InvalidateVisual();
|
||||
}
|
||||
|
||||
private void OnCommitDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.Histories histories)
|
||||
{
|
||||
histories.Select(commitDataGrid.SelectedItems);
|
||||
|
||||
if (histories.DetailContext is ViewModels.CommitDetail detail)
|
||||
{
|
||||
commitDataGrid.ScrollIntoView(detail.Commit, null);
|
||||
}
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnCommitDataGridContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.Histories histories)
|
||||
{
|
||||
var menu = histories.MakeContextMenu();
|
||||
menu?.Open(sender as Control);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
129
src/Views/Hotkeys.axaml
Normal file
129
src/Views/Hotkeys.axaml
Normal file
|
@ -0,0 +1,129 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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:c="using:SourceGit.Converters"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Hotkeys"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.Hotkeys}"
|
||||
Background="Transparent"
|
||||
SizeToContent="WidthAndHeight"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<Path Grid.Column="0"
|
||||
Width="14" Height="14"
|
||||
Margin="10,0,0,0"
|
||||
Data="{StaticResource Icons.Hotkeys}"
|
||||
IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
|
||||
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<Button Classes="caption_button_macos" Click="CloseWindow">
|
||||
<Grid>
|
||||
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
|
||||
<Path Height="6" Width="6" Stretch="Fill" Fill="#404040" Stroke="#404040" StrokeThickness="1" Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Hotkeys}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"/>
|
||||
|
||||
<Button Grid.Column="2"
|
||||
Classes="caption_button"
|
||||
Click="CloseWindow"
|
||||
IsVisible="{OnPlatform True, macOS=False}">
|
||||
<Path Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Border Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<StackPanel Orientation="Vertical" Margin="16,8,16,16">
|
||||
<TextBlock Text="{DynamicResource Text.Hotkeys.Global}"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
FontWeight="Bold"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<Grid RowDefinitions="20,20,20,20" ColumnDefinitions="80,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="Ctrl+T"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.NewTab}" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="Ctrl+W" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.CloseTab}" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="Ctrl+Tab"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.GotoNextTab}" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="ESC"/>
|
||||
<TextBlock Grid.Row="3" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.CancelPopup}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Text="{DynamicResource Text.Hotkeys.Repo}"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
FontWeight="Bold"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
|
||||
Margin="0,8"/>
|
||||
|
||||
<Grid RowDefinitions="20,20,20,20,20" ColumnDefinitions="80,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="Ctrl+F"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ToggleSearch}" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="Ctrl+1"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewHistories}" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="Ctrl+2"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewChanges}" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="Ctrl+3"/>
|
||||
<TextBlock Grid.Row="3" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewStashes}" />
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Classes="monospace bold" Text="SPACE"/>
|
||||
<TextBlock Grid.Row="4" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.StageOrUnstageSelected}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Text="{DynamicResource Text.Hotkeys.TextEditor}"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
FontWeight="Bold"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
|
||||
Margin="0,8"/>
|
||||
|
||||
<Grid RowDefinitions="20,20,20,20" ColumnDefinitions="80,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="Ctrl+F"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.Search}" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="Shift+F3"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.GotoPrevMatch}" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="F3"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.GotoNextMatch}" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="ESC"/>
|
||||
<TextBlock Grid.Row="3" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.CloseSearch}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
24
src/Views/Hotkeys.axaml.cs
Normal file
24
src/Views/Hotkeys.axaml.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Hotkeys : Window
|
||||
{
|
||||
public Hotkeys()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
|
||||
private void CloseWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
25
src/Views/Init.axaml
Normal file
25
src/Views/Init.axaml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Init"
|
||||
x:DataType="vm:Init">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Init}"/>
|
||||
<Grid Margin="0,16,8,0" RowDefinitions="28,28" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Init.Path}"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1"
|
||||
Text="{Binding TargetPath}"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1"
|
||||
Text="{DynamicResource Text.Init.Tip}"
|
||||
Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Init.axaml.cs
Normal file
12
src/Views/Init.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Init : UserControl
|
||||
{
|
||||
public Init()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
85
src/Views/InitGitFlow.axaml
Normal file
85
src/Views/InitGitFlow.axaml
Normal file
|
@ -0,0 +1,85 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.InitGitFlow"
|
||||
x:DataType="vm:InitGitFlow">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.GitFlow.Init}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,8,32,32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.GitFlow.ProductionBranch}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Text="{Binding Master, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.GitFlow.DevelopBranch}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Text="{Binding Develop, Mode=TwoWay}"/>
|
||||
|
||||
<Rectangle Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
|
||||
Height="1"
|
||||
Fill="{DynamicResource Brush.Border2}"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.GitFlow.FeaturePrefix}"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Text="{Binding FeturePrefix, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.GitFlow.ReleasePrefix}"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Text="{Binding ReleasePrefix, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.GitFlow.HotfixPrefix}"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Text="{Binding HotfixPrefix, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="6" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.GitFlow.TagPrefix}"/>
|
||||
<TextBox Grid.Row="6" Grid.Column="1"
|
||||
Height="26"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="2"
|
||||
Watermark="{DynamicResource Text.Optional}"
|
||||
Text="{Binding TagPrefix, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/InitGitFlow.axaml.cs
Normal file
12
src/Views/InitGitFlow.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class InitGitFlow : UserControl
|
||||
{
|
||||
public InitGitFlow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
427
src/Views/Launcher.axaml
Normal file
427
src/Views/Launcher.axaml
Normal file
|
@ -0,0 +1,427 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
xmlns:m="using:SourceGit.Models"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Launcher"
|
||||
x:DataType="vm:Launcher"
|
||||
x:Name="me"
|
||||
Icon="/App.ico"
|
||||
Title="SourceGit"
|
||||
Background="Transparent"
|
||||
MinWidth="1280" MinHeight="720"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Window.Resources>
|
||||
<SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="Red"/>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToContentMargin}}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToTitleBarHeight}}"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- Custom TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto">
|
||||
<!-- Bottom border -->
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<!-- Caption Buttons (macOS) -->
|
||||
<Border Grid.Column="0" VerticalAlignment="Stretch" Margin="2,0,8,3" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<v:CaptionButtonsMacOS VerticalAlignment="Bottom"/>
|
||||
</Border>
|
||||
|
||||
<!-- Menu -->
|
||||
<Button Grid.Column="{OnPlatform 0, macOS=2}"
|
||||
Classes="icon_button"
|
||||
Margin="4,0,2,3"
|
||||
VerticalAlignment="Bottom">
|
||||
<Button.Flyout>
|
||||
<MenuFlyout Placement="BottomEdgeAlignedLeft" VerticalOffset="-8">
|
||||
<MenuItem Header="{DynamicResource Text.Preference}" Click="OpenPreference">
|
||||
<MenuItem.Icon>
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Settings2}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{DynamicResource Text.Hotkeys}" Click="OpenHotkeys">
|
||||
<MenuItem.Icon>
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Hotkeys}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="-"/>
|
||||
<MenuItem Header="{DynamicResource Text.SelfUpdate}" Click="Check4Update">
|
||||
<MenuItem.Icon>
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.SoftwareUpdate}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="-"/>
|
||||
<MenuItem Header="{DynamicResource Text.About}" Click="OpenAboutDialog">
|
||||
<MenuItem.Icon>
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Info}"/>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.Menu}"/>
|
||||
</Button>
|
||||
|
||||
<!-- Pages Tabs-->
|
||||
<Grid x:Name="launcherTabsContainer" Grid.Column="1" Height="30" ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Bottom" SizeChanged="UpdateScrollIndicator">
|
||||
<Button x:Name="leftScrollIndicator" Grid.Column="0" Classes="icon_button" Width="18" Height="30" Click="ScrollTabsLeft">
|
||||
<Path Width="8" Height="14" Stretch="Fill" Data="{StaticResource Icons.TriangleLeft}"/>
|
||||
</Button>
|
||||
|
||||
<ScrollViewer Grid.Column="1"
|
||||
x:Name="launcherTabsScroller"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Disabled"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"
|
||||
PointerWheelChanged="ScrollTabs">
|
||||
<StackPanel x:Name="launcherTabsBar" Orientation="Horizontal" SizeChanged="UpdateScrollIndicator">
|
||||
<ListBox Classes="launcher_page_tabbar"
|
||||
ItemsSource="{Binding Pages}"
|
||||
SelectedItem="{Binding ActivePage, Mode=TwoWay}">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel Orientation="Horizontal" Height="30"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:LauncherPage}">
|
||||
<Border Classes="launcher_pagetab"
|
||||
Height="30"
|
||||
BorderThickness="1,1,1,0"
|
||||
CornerRadius="6,6,0,0"
|
||||
PointerPressed="OnPointerPressedTab"
|
||||
PointerMoved="OnPointerMovedOverTab"
|
||||
PointerReleased="OnPointerReleasedTab"
|
||||
Loaded="SetupDragAndDrop">
|
||||
<Border.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{DynamicResource Text.PageTabBar.Tab.Close}"
|
||||
Command="{Binding #me.DataContext.(vm:Launcher).CloseTab}"
|
||||
CommandParameter="{Binding}"
|
||||
InputGesture="Ctrl+W"/>
|
||||
<MenuItem Header="{DynamicResource Text.PageTabBar.Tab.CloseOther}"
|
||||
Command="{Binding #me.DataContext.(vm:Launcher).CloseOtherTabs}"
|
||||
CommandParameter="{Binding}"/>
|
||||
<MenuItem Header="{DynamicResource Text.PageTabBar.Tab.CloseRight}"
|
||||
Command="{Binding #me.DataContext.(vm:Launcher).CloseRightTabs}"
|
||||
CommandParameter="{Binding}"/>
|
||||
<MenuItem Header="-" IsVisible="{Binding Node.IsRepository}"/>
|
||||
<MenuItem IsVisible="{Binding Node.IsRepository}">
|
||||
<MenuItem.Header>
|
||||
<Grid Height="20" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Column="0" Text="{DynamicResource Text.PageTabBar.Tab.Bookmark}"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
BorderThickness=".5" Margin="8,0,0,0"
|
||||
ItemsSource="{x:Static m:Bookmarks.Supported}"
|
||||
SelectedIndex="{Binding Node.Bookmark, Mode=TwoWay}">
|
||||
<ComboBox.Resources>
|
||||
<Thickness x:Key="ComboBoxPadding">12,2,0,2</Thickness>
|
||||
<Thickness x:Key="ComboBoxEditableTextPadding">11,2,32,2</Thickness>
|
||||
<x:Double x:Key="ComboBoxMinHeight">22</x:Double>
|
||||
</ComboBox.Resources>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Height="20" VerticalAlignment="Center">
|
||||
<Path Width="12" Height="12"
|
||||
Fill="{Binding Converter={x:Static c:BookmarkConverters.ToBrush}}"
|
||||
StrokeThickness="{Binding Converter={x:Static c:BookmarkConverters.ToStrokeThickness}}"
|
||||
Stroke="{DynamicResource Brush.FG1}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Bookmark}"/>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
<MenuItem Header="-" IsVisible="{Binding Node.IsRepository}"/>
|
||||
<MenuItem Header="{DynamicResource Text.PageTabBar.Tab.CopyPath}" Command="{Binding CopyPath}" IsVisible="{Binding Node.IsRepository}"/>
|
||||
</ContextMenu>
|
||||
</Border.ContextMenu>
|
||||
|
||||
<v:LauncherTab UseFixedTabWidth="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth}" Height="30" ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center">
|
||||
<Path Grid.Column="0"
|
||||
Width="12" Height="12" Margin="12,0"
|
||||
Fill="{Binding Node.Bookmark, Converter={x:Static c:BookmarkConverters.ToBrush}}"
|
||||
StrokeThickness="{Binding Node.Bookmark, Converter={x:Static c:BookmarkConverters.ToStrokeThickness}}"
|
||||
Stroke="{DynamicResource Brush.FG1}"
|
||||
Data="{StaticResource Icons.Bookmark}"
|
||||
IsVisible="{Binding Node.IsRepository}"
|
||||
IsHitTestVisible="False"/>
|
||||
<Path Grid.Column="0"
|
||||
Width="12" Height="12" Margin="12,0"
|
||||
Fill="{DynamicResource Brush.FG1}"
|
||||
Data="{StaticResource Icons.Repositories}"
|
||||
IsVisible="{Binding !Node.IsRepository}"
|
||||
IsHitTestVisible="False"/>
|
||||
<TextBlock Grid.Column="1"
|
||||
Classes="monospace"
|
||||
FontSize="12"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
Text="{Binding Node.Name}"
|
||||
IsVisible="{Binding Node.IsRepository}"
|
||||
IsHitTestVisible="False"/>
|
||||
<TextBlock Grid.Column="1"
|
||||
Classes="monospace"
|
||||
FontSize="12"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
Text="{DynamicResource Text.PageTabBar.Welcome.Title}"
|
||||
IsVisible="{Binding !Node.IsRepository}"
|
||||
IsHitTestVisible="False"/>
|
||||
<Button Grid.Column="2"
|
||||
Classes="icon_button"
|
||||
Width="16" Height="16" Margin="12,0"
|
||||
Command="{Binding #me.DataContext.(vm:Launcher).CloseTab}"
|
||||
CommandParameter="{Binding}"
|
||||
ToolTip.Tip="{DynamicResource Text.PageTabBar.Tab.Close}">
|
||||
<Path Width="8" Height="8" Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Button>
|
||||
<Rectangle Grid.Column="2" Width=".5" Height="20" HorizontalAlignment="Right" VerticalAlignment="Center" Fill="{DynamicResource Brush.FG2}">
|
||||
<Rectangle.IsVisible>
|
||||
<MultiBinding Converter="{x:Static c:LauncherPageConverters.ToTabSeperatorVisible}">
|
||||
<Binding/>
|
||||
<Binding Path="$parent[ListBox].SelectedItem"/>
|
||||
<Binding Path="#me.DataContext.(vm:Launcher).Pages"/>
|
||||
</MultiBinding>
|
||||
</Rectangle.IsVisible>
|
||||
</Rectangle>
|
||||
</v:LauncherTab>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<Button Classes="icon_button"
|
||||
Width="16" Height="16"
|
||||
Margin="8,0"
|
||||
Command="{Binding AddNewTab}"
|
||||
HotKey="Ctrl+T"
|
||||
ToolTip.Tip="{DynamicResource Text.PageTabBar.New}">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.Plus}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Button x:Name="rightScrollIndicator" Grid.Column="2" Classes="icon_button" Width="18" Height="30" Click="ScrollTabsRight">
|
||||
<Path Width="8" Height="14" Stretch="Fill" Data="{StaticResource Icons.TriangleRight}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- Caption Buttons (Windows/Linux)-->
|
||||
<Border Grid.Column="2" Margin="32,0,0,0" IsVisible="{OnPlatform True, macOS=False}">
|
||||
<v:CaptionButtons Height="30" VerticalAlignment="Top"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Page body -->
|
||||
<v:LauncherBody Grid.Row="1" Background="{DynamicResource Brush.ToolBar}" Data="{Binding ActivePage.Data}"/>
|
||||
|
||||
<!-- Popup container -->
|
||||
<Grid Grid.Row="1" Margin="0,36,0,0" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<Border Background="Transparent" PointerPressed="OnPopupCancelByClickMask"/>
|
||||
|
||||
<Grid Width="500" HorizontalAlignment="Center" VerticalAlignment="Top">
|
||||
<ContentControl Content="{Binding ActivePage.Popup}" ClipToBounds="True">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:Popup">
|
||||
<Border Margin="8,0,8,8"
|
||||
Background="{DynamicResource Brush.Popup}"
|
||||
BorderBrush="{DynamicResource Brush.Border0}">
|
||||
<Border.CornerRadius>
|
||||
<OnPlatform Default="0,0,4,4" Linux="0"/>
|
||||
</Border.CornerRadius>
|
||||
|
||||
<Border.BorderThickness>
|
||||
<OnPlatform Default="0" Linux="1,0,1,1"/>
|
||||
</Border.BorderThickness>
|
||||
|
||||
<Border.Effect>
|
||||
<OnPlatform>
|
||||
<On Options="Windows, macOS">
|
||||
<DropShadowEffect BlurRadius="8" OffsetX="0" OffsetY="0" Color="Black" Opacity=".5"/>
|
||||
</On>
|
||||
</OnPlatform>
|
||||
</Border.Effect>
|
||||
|
||||
<StackPanel Margin="8" Orientation="Vertical">
|
||||
<!-- Popup Widget -->
|
||||
<ContentPresenter Margin="0,8"
|
||||
Content="{Binding View}"
|
||||
IsHitTestVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}"/>
|
||||
|
||||
<!-- Options -->
|
||||
<StackPanel Margin="0,8,0,0"
|
||||
Height="32"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}">
|
||||
<Button Classes="flat primary"
|
||||
Width="80"
|
||||
Content="{DynamicResource Text.Sure}"
|
||||
Click="OnPopupSure"
|
||||
HotKey="Enter"/>
|
||||
<Button Classes="flat"
|
||||
Width="80"
|
||||
Margin="8,0,0,0"
|
||||
Content="{DynamicResource Text.Cancel}"
|
||||
Click="OnPopupCancel"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Running -->
|
||||
<StackPanel Orientation="Vertical" Margin="8" IsVisible="{Binding InProgress}">
|
||||
<Rectangle Height="1" Margin="-8,0" HorizontalAlignment="Stretch" Fill="{DynamicResource Brush.Border1}" />
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8">
|
||||
<Path Width="12" Height="12" Classes="waiting" Data="{StaticResource Icons.Waiting}" IsVisible="{Binding InProgress}"/>
|
||||
<TextBlock Margin="6,0,0,0" FontSize="14" FontWeight="Bold" Text="{DynamicResource Text.Running}"/>
|
||||
</StackPanel>
|
||||
<TextBlock HorizontalAlignment="Stretch"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
|
||||
FontStyle="Italic"
|
||||
Text="{Binding ProgressDescription}"/>
|
||||
<ProgressBar Margin="0,8,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
IsIndeterminate="True"
|
||||
Background="{DynamicResource Brush.FG2}" Foreground="{DynamicResource Brush.Accent1}"
|
||||
Minimum="0" Maximum="100"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Notification container -->
|
||||
<Grid Grid.Row="1" Width="360" Margin="0,36,0,0" HorizontalAlignment="Right" VerticalAlignment="Top">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding ActivePage.Notifications}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="m:Notification">
|
||||
<Grid Width="320" Margin="8">
|
||||
<Border Background="{DynamicResource Brush.Window}" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="1" CornerRadius="4" Effect="drop-shadow(0 0 8 #40000000)"/>
|
||||
|
||||
<Grid Margin="8" RowDefinitions="26,Auto,Auto">
|
||||
<StackPanel Grid.Row="0" Margin="8,0,0,0" Orientation="Horizontal" IsVisible="{Binding IsError}">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Error}" Fill="Red"/>
|
||||
<TextBlock Margin="8,0,0,0" FontWeight="Bold" FontSize="14" Text="{DynamicResource Text.Launcher.Error}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Margin="8,0,0,0" Orientation="Horizontal" IsVisible="{Binding !IsError}">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Info}" Fill="Green"/>
|
||||
<TextBlock Margin="8,0,0,0" FontWeight="Bold" FontSize="14" Text="{DynamicResource Text.Launcher.Info}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBox Grid.Row="1"
|
||||
Classes="no_background no_border"
|
||||
IsReadOnly="True"
|
||||
TextWrapping="Wrap"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
MaxHeight="100"
|
||||
Margin="8" Padding="0"
|
||||
VerticalContentAlignment="Top"
|
||||
Text="{Binding Message}"/>
|
||||
<Button Grid.Row="3"
|
||||
Classes="flat primary"
|
||||
Height="30"
|
||||
Margin="4,0"
|
||||
Command="{Binding #me.DataContext.(vm:Launcher).ActivePage.DismissNotification}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="{DynamicResource Text.Close}"
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- Custom window sizer for Linux -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="2" IsVisible="{OnPlatform False, Linux=True}" IsHitTestVisible="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.IsNormal}}">
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Cursor="TopLeftCorner"
|
||||
Tag="{x:Static WindowEdge.NorthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
Cursor="TopSide"
|
||||
Tag="{x:Static WindowEdge.North}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Cursor="TopRightCorner"
|
||||
Tag="{x:Static WindowEdge.NorthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch"
|
||||
Cursor="LeftSide"
|
||||
Tag="{x:Static WindowEdge.West}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Stretch"
|
||||
Cursor="RightSide"
|
||||
Tag="{x:Static WindowEdge.East}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||
Cursor="BottomLeftCorner"
|
||||
Tag="{x:Static WindowEdge.SouthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
|
||||
Cursor="BottomSide"
|
||||
Tag="{x:Static WindowEdge.South}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Cursor="BottomRightCorner"
|
||||
Tag="{x:Static WindowEdge.SouthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
341
src/Views/Launcher.axaml.cs
Normal file
341
src/Views/Launcher.axaml.cs
Normal file
|
@ -0,0 +1,341 @@
|
|||
using System;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class LauncherTab : Grid
|
||||
{
|
||||
public static readonly StyledProperty<bool> UseFixedTabWidthProperty =
|
||||
AvaloniaProperty.Register<LauncherTab, bool>(nameof(UseFixedTabWidth), false);
|
||||
|
||||
public bool UseFixedTabWidth
|
||||
{
|
||||
get => GetValue(UseFixedTabWidthProperty);
|
||||
set => SetValue(UseFixedTabWidthProperty, value);
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(Grid);
|
||||
|
||||
static LauncherTab()
|
||||
{
|
||||
UseFixedTabWidthProperty.Changed.AddClassHandler<LauncherTab>((tab, ev) =>
|
||||
{
|
||||
tab.Width = tab.UseFixedTabWidth ? 200.0 : double.NaN;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class LauncherBody : Border
|
||||
{
|
||||
public static readonly StyledProperty<object> DataProperty =
|
||||
AvaloniaProperty.Register<LauncherBody, object>(nameof(Data), false);
|
||||
|
||||
public object Data
|
||||
{
|
||||
get => GetValue(DataProperty);
|
||||
set => SetValue(DataProperty, value);
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(Border);
|
||||
|
||||
static LauncherBody()
|
||||
{
|
||||
DataProperty.Changed.AddClassHandler<LauncherBody>((body, ev) =>
|
||||
{
|
||||
var data = body.Data;
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
body.Child = null;
|
||||
}
|
||||
else if (data is ViewModels.Welcome)
|
||||
{
|
||||
body.Child = new Welcome { DataContext = data };
|
||||
}
|
||||
else if (data is ViewModels.Repository)
|
||||
{
|
||||
body.Child = new Repository { DataContext = data };
|
||||
}
|
||||
else
|
||||
{
|
||||
body.Child = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Launcher : Window, Models.INotificationReceiver
|
||||
{
|
||||
public Launcher()
|
||||
{
|
||||
DataContext = new ViewModels.Launcher();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void OnReceiveNotification(string ctx, Models.Notification notice)
|
||||
{
|
||||
if (DataContext is ViewModels.Launcher vm)
|
||||
{
|
||||
foreach (var page in vm.Pages)
|
||||
{
|
||||
var pageId = page.Node.Id.Replace("\\", "/");
|
||||
if (pageId == ctx)
|
||||
{
|
||||
page.Notifications.Add(notice);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (vm.ActivePage != null)
|
||||
vm.ActivePage.Notifications.Add(notice);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
var vm = DataContext as ViewModels.Launcher;
|
||||
if (e.KeyModifiers.HasFlag(KeyModifiers.Control))
|
||||
{
|
||||
if (e.Key == Key.W)
|
||||
{
|
||||
vm.CloseTab(null);
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
else if (e.Key == Key.Tab)
|
||||
{
|
||||
vm.GotoNextTab();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
else if (vm.ActivePage.Data is ViewModels.Repository repo)
|
||||
{
|
||||
if (e.Key == Key.D1 || e.Key == Key.NumPad1)
|
||||
{
|
||||
repo.SelectedViewIndex = 0;
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
else if (e.Key == Key.D2 || e.Key == Key.NumPad2)
|
||||
{
|
||||
repo.SelectedViewIndex = 1;
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
else if (e.Key == Key.D3 || e.Key == Key.NumPad3)
|
||||
{
|
||||
repo.SelectedViewIndex = 2;
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
else if (e.Key == Key.F)
|
||||
{
|
||||
repo.IsSearching = !repo.IsSearching;
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Escape)
|
||||
{
|
||||
vm.ActivePage.CancelPopup();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
protected override void OnClosing(WindowClosingEventArgs e)
|
||||
{
|
||||
var vm = DataContext as ViewModels.Launcher;
|
||||
vm.Quit();
|
||||
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = WindowState.Maximized;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void CustomResizeWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
if (border.Tag is WindowEdge edge)
|
||||
{
|
||||
BeginResizeDrag(edge, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
|
||||
private void ScrollTabs(object sender, PointerWheelEventArgs e)
|
||||
{
|
||||
if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift))
|
||||
{
|
||||
if (e.Delta.Y < 0)
|
||||
launcherTabsScroller.LineRight();
|
||||
else
|
||||
launcherTabsScroller.LineLeft();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ScrollTabsLeft(object sender, RoutedEventArgs e)
|
||||
{
|
||||
launcherTabsScroller.LineLeft();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void ScrollTabsRight(object sender, RoutedEventArgs e)
|
||||
{
|
||||
launcherTabsScroller.LineRight();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void UpdateScrollIndicator(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (launcherTabsBar.Bounds.Width > launcherTabsContainer.Bounds.Width)
|
||||
{
|
||||
leftScrollIndicator.IsVisible = true;
|
||||
rightScrollIndicator.IsVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftScrollIndicator.IsVisible = false;
|
||||
rightScrollIndicator.IsVisible = false;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void SetupDragAndDrop(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
DragDrop.SetAllowDrop(border, true);
|
||||
border.AddHandler(DragDrop.DropEvent, DropTab);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnPointerPressedTab(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
_pressedTab = true;
|
||||
_startDrag = false;
|
||||
_pressedTabPosition = e.GetPosition(sender as Border);
|
||||
}
|
||||
|
||||
private void OnPointerReleasedTab(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
_pressedTab = false;
|
||||
_startDrag = false;
|
||||
}
|
||||
|
||||
private void OnPointerMovedOverTab(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (_pressedTab && !_startDrag && sender is Border border)
|
||||
{
|
||||
var delta = e.GetPosition(border) - _pressedTabPosition;
|
||||
var sizeSquired = delta.X * delta.X + delta.Y * delta.Y;
|
||||
if (sizeSquired < 64)
|
||||
return;
|
||||
|
||||
_startDrag = true;
|
||||
|
||||
var data = new DataObject();
|
||||
data.Set("MovedTab", border.DataContext);
|
||||
DragDrop.DoDragDrop(e, data, DragDropEffects.Move);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void DropTab(object sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data.Contains("MovedTab") && sender is Border border)
|
||||
{
|
||||
var to = border.DataContext as ViewModels.LauncherPage;
|
||||
var moved = e.Data.Get("MovedTab") as ViewModels.LauncherPage;
|
||||
if (to != null && moved != null && to != moved && DataContext is ViewModels.Launcher vm)
|
||||
{
|
||||
vm.MoveTab(moved, to);
|
||||
}
|
||||
}
|
||||
|
||||
_pressedTab = false;
|
||||
_startDrag = false;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnPopupSure(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.Launcher vm)
|
||||
{
|
||||
vm.ActivePage.ProcessPopup();
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnPopupCancel(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.Launcher vm)
|
||||
{
|
||||
vm.ActivePage.CancelPopup();
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnPopupCancelByClickMask(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
OnPopupCancel(sender, e);
|
||||
}
|
||||
|
||||
private async void OpenPreference(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new Preference();
|
||||
await dialog.ShowDialog(this);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void OpenHotkeys(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new Hotkeys();
|
||||
await dialog.ShowDialog(this);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void Check4Update(object sender, RoutedEventArgs e)
|
||||
{
|
||||
App.Check4Update(true);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void OpenAboutDialog(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new About();
|
||||
await dialog.ShowDialog(this);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private bool _pressedTab = false;
|
||||
private Point _pressedTabPosition = new Point();
|
||||
private bool _startDrag = false;
|
||||
}
|
||||
}
|
52
src/Views/Merge.axaml
Normal file
52
src/Views/Merge.axaml
Normal file
|
@ -0,0 +1,52 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Merge"
|
||||
x:DataType="vm:Merge">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Merge}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Merge.Source}"/>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,0,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Source}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Merge.Into}"/>
|
||||
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,0,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Into}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Merge.Mode}"/>
|
||||
<ComboBox Grid.Row="2" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Modes}"
|
||||
SelectedItem="{Binding SelectedMode, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="vm:MergeMode">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
<TextBlock Text="{Binding Desc}" Margin="8,0,0,0" FontSize="11" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Merge.axaml.cs
Normal file
12
src/Views/Merge.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Merge : UserControl
|
||||
{
|
||||
public Merge()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
125
src/Views/NameHighlightedTextBlock.cs
Normal file
125
src/Views/NameHighlightedTextBlock.cs
Normal file
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class NameHighlightedTextBlock : Control
|
||||
{
|
||||
public static readonly StyledProperty<string> TextProperty =
|
||||
AvaloniaProperty.Register<NameHighlightedTextBlock, string>(nameof(Text));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<FontFamily> FontFamilyProperty =
|
||||
TextBlock.FontFamilyProperty.AddOwner<NameHighlightedTextBlock>();
|
||||
|
||||
public FontFamily FontFamily
|
||||
{
|
||||
get => GetValue(FontFamilyProperty);
|
||||
set => SetValue(FontFamilyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<double> FontSizeProperty =
|
||||
TextBlock.FontSizeProperty.AddOwner<NameHighlightedTextBlock>();
|
||||
|
||||
public double FontSize
|
||||
{
|
||||
get => GetValue(FontSizeProperty);
|
||||
set => SetValue(FontSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> ForegroundProperty =
|
||||
TextBlock.ForegroundProperty.AddOwner<NameHighlightedTextBlock>();
|
||||
|
||||
public IBrush Foreground
|
||||
{
|
||||
get => GetValue(ForegroundProperty);
|
||||
set => SetValue(ForegroundProperty, value);
|
||||
}
|
||||
|
||||
static NameHighlightedTextBlock()
|
||||
{
|
||||
AffectsMeasure<NameHighlightedTextBlock>(TextProperty);
|
||||
}
|
||||
|
||||
public NameHighlightedTextBlock(string nameKey, params object[] args)
|
||||
{
|
||||
SetCurrentValue(TextProperty, App.Text(nameKey, args));
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var text = Text;
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return base.MeasureOverride(availableSize);
|
||||
|
||||
var typeface = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Normal, FontStretch.Normal);
|
||||
var formatted = new FormattedText(
|
||||
Text,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
FontSize,
|
||||
Foreground);
|
||||
|
||||
return new Size(formatted.Width - 16, formatted.Height);
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var text = Text;
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return;
|
||||
|
||||
var normalTypeface = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Normal, FontStretch.Normal);
|
||||
//var highlightTypeface = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Bold, FontStretch.Normal);
|
||||
var underlinePen = new Pen(Foreground, 1);
|
||||
var offsetX = 0.0;
|
||||
|
||||
var parts = text.Split('$', StringSplitOptions.None);
|
||||
var isName = false;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (string.IsNullOrEmpty(part))
|
||||
{
|
||||
isName = !isName;
|
||||
continue;
|
||||
}
|
||||
|
||||
var formatted = new FormattedText(
|
||||
part,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
//isName ? highlightTypeface : normalTypeface,
|
||||
normalTypeface,
|
||||
FontSize,
|
||||
Foreground);
|
||||
|
||||
if (isName)
|
||||
{
|
||||
var lineY = formatted.Baseline + 2;
|
||||
offsetX += 4;
|
||||
context.DrawText(formatted, new Point(offsetX, 0));
|
||||
context.DrawLine(underlinePen, new Point(offsetX, lineY), new Point(offsetX + formatted.Width, lineY));
|
||||
offsetX += formatted.Width + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.DrawText(formatted, new Point(offsetX, 0));
|
||||
offsetX += formatted.Width;
|
||||
}
|
||||
|
||||
isName = !isName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
418
src/Views/Preference.axaml
Normal file
418
src/Views/Preference.axaml
Normal file
|
@ -0,0 +1,418 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:m="using:SourceGit.Models"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Preference"
|
||||
x:DataType="vm:Preference"
|
||||
x:Name="me"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.Preference}"
|
||||
Background="Transparent"
|
||||
Width="600" SizeToContent="Height"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,Auto" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<Path Grid.Column="0"
|
||||
Width="14" Height="14"
|
||||
Data="{StaticResource Icons.Settings2}"
|
||||
Margin="10,0,0,0"
|
||||
IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
|
||||
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<Button Classes="caption_button_macos" Click="CloseWindow">
|
||||
<Grid>
|
||||
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
|
||||
<Path Height="6" Width="6" Stretch="Fill" Fill="#404040" Stroke="#404040" StrokeThickness="1" Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Preference}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"/>
|
||||
|
||||
<Button Grid.Column="2" Classes="caption_button" Click="CloseWindow" IsVisible="{OnPlatform True, macOS=False}">
|
||||
<Path Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Border Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<TabControl>
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.General}"/>
|
||||
</TabItem.Header>
|
||||
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.General.Locale}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<ComboBox Grid.Row="0" Grid.Column="1"
|
||||
MinHeight="28"
|
||||
Padding="8,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Source={x:Static m:Locale.Supported}}"
|
||||
DisplayMemberBinding="{Binding Name, x:DataType=m:Locale}"
|
||||
SelectedItem="{Binding Locale, Mode=TwoWay, Converter={x:Static c:StringConverters.ToLocale}}"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.General.AvatarServer}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
MinHeight="28"
|
||||
Padding="8,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectedItem="{Binding AvatarServer, Mode=TwoWay}">
|
||||
<ComboBox.Items>
|
||||
<sys:String>https://www.gravatar.com/avatar/</sys:String>
|
||||
<sys:String>https://cravatar.cn/avatar/</sys:String>
|
||||
</ComboBox.Items>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.General.MaxHistoryCommits}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<Grid Grid.Row="2" Grid.Column="1" ColumnDefinitions="*,64">
|
||||
<Slider Grid.Column="0"
|
||||
Minimum="20000" Maximum="100000"
|
||||
TickPlacement="BottomRight" TickFrequency="5000"
|
||||
IsSnapToTickEnabled="True"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Brush.Border1}"
|
||||
Value="{Binding MaxHistoryCommits, Mode=TwoWay}">
|
||||
<Slider.Resources>
|
||||
<Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness>
|
||||
<GridLength x:Key="SliderPreContentMargin">0</GridLength>
|
||||
<GridLength x:Key="SliderPostContentMargin">0</GridLength>
|
||||
<CornerRadius x:Key="SliderThumbCornerRadius">8</CornerRadius>
|
||||
<x:Double x:Key="SliderHorizontalThumbWidth">16</x:Double>
|
||||
<x:Double x:Key="SliderHorizontalThumbHeight">16</x:Double>
|
||||
</Slider.Resources>
|
||||
</Slider>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
Text="{Binding MaxHistoryCommits}"/>
|
||||
</Grid>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Preference.General.RestoreTabs}"
|
||||
IsChecked="{Binding RestoreTabs, Mode=TwoWay}"/>
|
||||
|
||||
<CheckBox Grid.Row="4" Grid.Column="1"
|
||||
Height="32"
|
||||
Content="{DynamicResource Text.Preference.General.UseFixedTabWidth}"
|
||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth, Mode=TwoWay}"/>
|
||||
|
||||
<CheckBox Grid.Row="5" Grid.Column="1"
|
||||
Height="32"
|
||||
Content="{DynamicResource Text.Preference.General.Check4UpdatesOnStartup}"
|
||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=Check4UpdatesOnStartup, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Appearance}"/>
|
||||
</TabItem.Header>
|
||||
<Grid Margin="8" RowDefinitions="32,32,32,32" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Appearance.Theme}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<ComboBox Grid.Row="0" Grid.Column="1"
|
||||
MinHeight="28"
|
||||
Padding="8,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberBinding="{Binding Key, x:DataType=ThemeVariant}"
|
||||
SelectedItem="{Binding Theme, Mode=TwoWay, Converter={x:Static c:StringConverters.ToTheme}}">
|
||||
<ComboBox.Items>
|
||||
<ThemeVariant>Default</ThemeVariant>
|
||||
<ThemeVariant>Dark</ThemeVariant>
|
||||
<ThemeVariant>Light</ThemeVariant>
|
||||
</ComboBox.Items>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Appearance.DefaultFont}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
MinHeight="28"
|
||||
Padding="8,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding #me.InstalledFonts}"
|
||||
SelectedItem="{Binding DefaultFont, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="FontFamily">
|
||||
<Border Height="24">
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontFamily="{Binding}"/>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Appearance.MonospaceFont}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<ComboBox Grid.Row="2" Grid.Column="1"
|
||||
MinHeight="28"
|
||||
Padding="8,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding #me.InstalledMonospaceFonts}"
|
||||
SelectedItem="{Binding MonospaceFont, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="FontFamily">
|
||||
<Border Height="24">
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontFamily="{Binding}"/>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Appearance.DefaultFontSize}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<NumericUpDown Grid.Row="3" Grid.Column="1"
|
||||
Minimum="10" Maximum="16" Increment="0.5"
|
||||
Height="28"
|
||||
Padding="4"
|
||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
|
||||
CornerRadius="3"
|
||||
Value="{Binding DefaultFontSize, Mode=TwoWay}">
|
||||
<NumericUpDown.Styles>
|
||||
<Style Selector="NumericUpDown /template/ ButtonSpinner#PART_Spinner">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
</Style>
|
||||
<Style Selector="NumericUpDown /template/ TextBox#PART_TextBox">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="CornerRadius" Value="3,0,0,3"/>
|
||||
</Style>
|
||||
</NumericUpDown.Styles>
|
||||
</NumericUpDown>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Git}"/>
|
||||
</TabItem.Header>
|
||||
|
||||
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Git.Path}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding GitInstallPath, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectGitExecutable">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Git.Version}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1"
|
||||
x:Name="txtVersion"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Git.DefaultCloneDir}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding GitDefaultCloneDir, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectDefaultCloneDir">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Git.User}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding #me.DefaultUser, Mode=TwoWay}"
|
||||
Watermark="{DynamicResource Text.Preference.Git.User.Placeholder}"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Git.Email}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding #me.DefaultEmail, Mode=TwoWay}"
|
||||
Watermark="{DynamicResource Text.Preference.Git.Email.Placeholder}"/>
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Git.CRLF}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<ComboBox Grid.Row="5" Grid.Column="1"
|
||||
MinHeight="28"
|
||||
Padding="8,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Source={x:Static m:CRLFMode.Supported}}"
|
||||
SelectedItem="{Binding #me.CRLFMode, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:CRLFMode}">
|
||||
<Grid ColumnDefinitions="64,*">
|
||||
<TextBlock Grid.Column="0" Text="{Binding Name}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Desc}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<CheckBox Grid.Row="6" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Preference.Git.AutoFetch}"
|
||||
IsChecked="{Binding GitAutoFetch, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.GPG}"/>
|
||||
</TabItem.Header>
|
||||
|
||||
<Grid Margin="8" RowDefinitions="32,32,32" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.GPG.Enabled}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="1"
|
||||
IsChecked="{Binding #me.EnableGPGSigning, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.GPG.Path}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
x:Name="txtGPGExecutable"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding #me.GPGExecutableFile, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectGPGExecutable">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.GPG.UserKey}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding #me.GPGUserKey, Mode=TwoWay}"
|
||||
Watermark="{DynamicResource Text.Preference.GPG.UserKey.Placeholder}"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Merger}"/>
|
||||
</TabItem.Header>
|
||||
|
||||
<Grid Margin="8" RowDefinitions="32,32,Auto,Auto" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Merger.Type}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<ComboBox Grid.Row="0" Grid.Column="1"
|
||||
MinHeight="28"
|
||||
Padding="8,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Source={x:Static m:ExternalMergeTools.Supported}}"
|
||||
DisplayMemberBinding="{Binding Name, x:DataType=m:ExternalMergeTools}"
|
||||
SelectedIndex="{Binding ExternalMergeToolType, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Merger.Path}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding ExternalMergeToolPath, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectExternalMergeTool">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Merger.CustomMergeCmd}"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,16,0"
|
||||
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1"
|
||||
Height="28" Margin="0,2"
|
||||
CornerRadius="3"
|
||||
Text="{Binding ExternalMergeToolCmd, Mode=TwoWay}"
|
||||
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Merger.CustomDiffCmd}"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,16,0"
|
||||
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1"
|
||||
Height="28" Margin="0,2"
|
||||
CornerRadius="3"
|
||||
Text="{Binding ExternalMergeToolDiffCmd, Mode=TwoWay}"
|
||||
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
246
src/Views/Preference.axaml.cs
Normal file
246
src/Views/Preference.axaml.cs
Normal file
|
@ -0,0 +1,246 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Preference : Window
|
||||
{
|
||||
public AvaloniaList<FontFamily> InstalledFonts
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public AvaloniaList<FontFamily> InstalledMonospaceFonts
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string DefaultUser
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string DefaultEmail
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Models.CRLFMode CRLFMode
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool EnableGPGSigning
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string GPGExecutableFile
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string GPGUserKey
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Preference()
|
||||
{
|
||||
var pref = ViewModels.Preference.Instance;
|
||||
DataContext = pref;
|
||||
|
||||
var builtInMono = new FontFamily("fonts:SourceGit#JetBrains Mono");
|
||||
|
||||
InstalledFonts = new AvaloniaList<FontFamily>();
|
||||
InstalledFonts.Add(builtInMono);
|
||||
InstalledFonts.AddRange(FontManager.Current.SystemFonts);
|
||||
|
||||
InstalledMonospaceFonts = new AvaloniaList<FontFamily>();
|
||||
InstalledMonospaceFonts.Add(builtInMono);
|
||||
|
||||
var curMonoFont = pref.MonospaceFont;
|
||||
if (curMonoFont != builtInMono)
|
||||
{
|
||||
InstalledMonospaceFonts.Add(curMonoFont);
|
||||
}
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
var sysMonoFonts = new List<FontFamily>();
|
||||
foreach (var font in FontManager.Current.SystemFonts)
|
||||
{
|
||||
if (font == curMonoFont)
|
||||
continue;
|
||||
|
||||
var typeface = new Typeface(font);
|
||||
var testI = new FormattedText(
|
||||
"i",
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
12,
|
||||
Brushes.White);
|
||||
var testW = new FormattedText(
|
||||
"W",
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
12,
|
||||
Brushes.White);
|
||||
if (testI.Width == testW.Width)
|
||||
{
|
||||
sysMonoFonts.Add(font);
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() => InstalledMonospaceFonts.AddRange(sysMonoFonts));
|
||||
});
|
||||
|
||||
var ver = string.Empty;
|
||||
if (pref.IsGitConfigured)
|
||||
{
|
||||
var config = new Commands.Config(null).ListAll();
|
||||
|
||||
if (config.TryGetValue("user.name", out var name))
|
||||
DefaultUser = name;
|
||||
if (config.TryGetValue("user.email", out var email))
|
||||
DefaultEmail = email;
|
||||
if (config.TryGetValue("user.signingkey", out var signingKey))
|
||||
GPGUserKey = signingKey;
|
||||
if (config.TryGetValue("core.autocrlf", out var crlf))
|
||||
CRLFMode = Models.CRLFMode.Supported.Find(x => x.Value == crlf);
|
||||
if (config.TryGetValue("commit.gpgsign", out var gpgsign))
|
||||
EnableGPGSigning = (gpgsign == "true");
|
||||
if (config.TryGetValue("gpg.program", out var gpgProgram))
|
||||
GPGExecutableFile = gpgProgram;
|
||||
|
||||
ver = new Commands.Version().Query();
|
||||
}
|
||||
|
||||
InitializeComponent();
|
||||
txtVersion.Text = ver;
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
|
||||
private void CloseWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cmd = new Commands.Config(null);
|
||||
|
||||
var config = cmd.ListAll();
|
||||
var oldUser = config.TryGetValue("user.name", out var user) ? user : string.Empty;
|
||||
var oldEmail = config.TryGetValue("user.email", out var email) ? email : string.Empty;
|
||||
var oldGPGSignKey = config.TryGetValue("user.signingkey", out var signingKey) ? signingKey : string.Empty;
|
||||
var oldCRLF = config.TryGetValue("core.autocrlf", out var crlf) ? crlf : string.Empty;
|
||||
var oldGPGSignEnable = config.TryGetValue("commit.gpgsign", out var gpgsign) ? gpgsign : "false";
|
||||
var oldGPGExec = config.TryGetValue("gpg.program", out var program) ? program : string.Empty;
|
||||
|
||||
if (DefaultUser != oldUser)
|
||||
cmd.Set("user.name", DefaultUser);
|
||||
if (DefaultEmail != oldEmail)
|
||||
cmd.Set("user.email", DefaultEmail);
|
||||
if (GPGUserKey != oldGPGSignKey)
|
||||
cmd.Set("user.signingkey", GPGUserKey);
|
||||
if (CRLFMode != null && CRLFMode.Value != oldCRLF)
|
||||
cmd.Set("core.autocrlf", CRLFMode.Value);
|
||||
if (EnableGPGSigning != (oldGPGSignEnable == "true"))
|
||||
cmd.Set("commit.gpgsign", EnableGPGSigning ? "true" : "false");
|
||||
if (GPGExecutableFile != oldGPGExec)
|
||||
cmd.Set("gpg.program", GPGExecutableFile);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private async void SelectGitExecutable(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var pattern = OperatingSystem.IsWindows() ? "git.exe" : "git";
|
||||
var options = new FilePickerOpenOptions()
|
||||
{
|
||||
FileTypeFilter = [new FilePickerFileType("Git Executable") { Patterns = [pattern] }],
|
||||
AllowMultiple = false,
|
||||
};
|
||||
|
||||
var selected = await StorageProvider.OpenFilePickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
ViewModels.Preference.Instance.GitInstallPath = selected[0].Path.LocalPath;
|
||||
txtVersion.Text = new Commands.Version().Query();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void SelectDefaultCloneDir(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
|
||||
var selected = await StorageProvider.OpenFolderPickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
ViewModels.Preference.Instance.GitDefaultCloneDir = selected[0].Path.LocalPath;
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectGPGExecutable(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var pattern = OperatingSystem.IsWindows() ? "gpg.exe" : "gpg";
|
||||
var options = new FilePickerOpenOptions()
|
||||
{
|
||||
FileTypeFilter = [new FilePickerFileType("GPG Executable") { Patterns = [pattern] }],
|
||||
AllowMultiple = false,
|
||||
};
|
||||
|
||||
var selected = await StorageProvider.OpenFilePickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
GPGExecutableFile = selected[0].Path.LocalPath;
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectExternalMergeTool(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var type = ViewModels.Preference.Instance.ExternalMergeToolType;
|
||||
if (type < 0 || type >= Models.ExternalMergeTools.Supported.Count)
|
||||
{
|
||||
ViewModels.Preference.Instance.ExternalMergeToolType = 0;
|
||||
type = 0;
|
||||
}
|
||||
|
||||
var tool = Models.ExternalMergeTools.Supported[type];
|
||||
var pattern = Path.GetFileName(tool.Exec);
|
||||
var options = new FilePickerOpenOptions()
|
||||
{
|
||||
FileTypeFilter = [new FilePickerFileType(tool.Name) { Patterns = [pattern] }],
|
||||
AllowMultiple = false,
|
||||
};
|
||||
|
||||
var selected = await StorageProvider.OpenFilePickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
ViewModels.Preference.Instance.ExternalMergeToolPath = selected[0].Path.LocalPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
src/Views/PruneRemote.axaml
Normal file
19
src/Views/PruneRemote.axaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.PruneRemote"
|
||||
x:DataType="vm:PruneRemote">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.RemoteCM.Prune}"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,16,0,0">
|
||||
<TextBlock Text="{DynamicResource Text.RemoteCM.Prune.Target}"/>
|
||||
<Path Width="14" Height="14" Margin="8,6,8,0" Data="{StaticResource Icons.Remote}"/>
|
||||
<TextBlock Text="{Binding Remote.Name}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/PruneRemote.axaml.cs
Normal file
12
src/Views/PruneRemote.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class PruneRemote : UserControl
|
||||
{
|
||||
public PruneRemote()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
74
src/Views/Pull.axaml
Normal file
74
src/Views/Pull.axaml
Normal file
|
@ -0,0 +1,74 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Pull"
|
||||
x:DataType="vm:Pull">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Pull.Title}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Pull.Remote}"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Remotes}"
|
||||
SelectedItem="{Binding SelectedRemote, Mode=TwoWay}"
|
||||
IsEnabled="{Binding !HasSpecifiedRemoteBranch}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Remote}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Remote}"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Pull.Branch}"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding RemoteBranches}"
|
||||
SelectedItem="{Binding SelectedBranch, Mode=TwoWay}"
|
||||
IsEnabled="{Binding !HasSpecifiedRemoteBranch}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Branch}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,0,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Converter={x:Static c:BranchConverters.ToName}}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Pull.Into}"/>
|
||||
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,0,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Current.Name}"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Pull.UseRebase}"
|
||||
IsChecked="{Binding UseRebase, Mode=TwoWay}"/>
|
||||
|
||||
<CheckBox Grid.Row="4" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Pull.AutoStash}"
|
||||
IsChecked="{Binding AutoStash, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Pull.axaml.cs
Normal file
12
src/Views/Pull.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Pull : UserControl
|
||||
{
|
||||
public Pull()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
84
src/Views/Push.axaml
Normal file
84
src/Views/Push.axaml
Normal file
|
@ -0,0 +1,84 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Push"
|
||||
x:DataType="vm:Push">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Push.Title}"/>
|
||||
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Push.Local}"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding LocalBranches}"
|
||||
SelectedItem="{Binding SelectedLocalBranch, Mode=TwoWay}"
|
||||
IsEnabled="{Binding !HasSpecifiedLocalBranch}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Branch}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,0,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Push.Remote}"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Remotes}"
|
||||
SelectedItem="{Binding SelectedRemote, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Remote}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Remote}"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Push.To}"/>
|
||||
<ComboBox Grid.Row="2" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding RemoteBranches}"
|
||||
SelectedItem="{Binding SelectedRemoteBranch, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Branch}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,0,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Push.WithAllTags}"
|
||||
IsChecked="{Binding PushAllTags, Mode=TwoWay}"/>
|
||||
|
||||
<CheckBox Grid.Row="4" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Push.Force}"
|
||||
IsChecked="{Binding ForcePush, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Push.axaml.cs
Normal file
12
src/Views/Push.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Push : UserControl
|
||||
{
|
||||
public Push()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
46
src/Views/PushTag.axaml
Normal file
46
src/Views/PushTag.axaml
Normal file
|
@ -0,0 +1,46 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.PushTag"
|
||||
x:DataType="vm:PushTag">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.PushTag}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.PushTag.Tag}"/>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Tag}"/>
|
||||
<TextBlock Text="{Binding Target.Name}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.PushTag.Remote}"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Remotes}"
|
||||
SelectedItem="{Binding SelectedRemote, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="{x:Type m:Remote}">
|
||||
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Remote}"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/PushTag.axaml.cs
Normal file
12
src/Views/PushTag.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class PushTag : UserControl
|
||||
{
|
||||
public PushTag()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
53
src/Views/Rebase.axaml
Normal file
53
src/Views/Rebase.axaml
Normal file
|
@ -0,0 +1,53 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Rebase"
|
||||
x:DataType="vm:Rebase">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Rebase}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Reset.Target}"/>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,0,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock Text="{Binding Current.Name}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Rebase.On}"/>
|
||||
<ContentControl Grid.Row="1" Grid.Column="1" Content="{Binding On}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:Branch">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch}"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Converter={x:Static c:BranchConverters.ToName}}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Rebase.AutoStash}"
|
||||
IsChecked="{Binding AutoStash, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
12
src/Views/Rebase.axaml.cs
Normal file
12
src/Views/Rebase.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Rebase : UserControl
|
||||
{
|
||||
public Rebase()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue