feature: supports to switch between HTTPS and SSH protocol (#1734)

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo
2026-03-17 18:23:39 +08:00
parent 668439a17d
commit 6f16791f51
5 changed files with 181 additions and 5 deletions

View File

@@ -29,7 +29,14 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.Remote.Name.Placeholder}"
Text="{Binding Name, Mode=TwoWay}"/>
Text="{Binding Name, Mode=TwoWay}">
<TextBox.InnerLeftContent>
<Path Width="12" Height="12"
Margin="4,0,2,0"
Data="{StaticResource Icons.Remote}"
Fill="{DynamicResource Brush.FG1}"/>
</TextBox.InnerLeftContent>
</TextBox>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
@@ -40,7 +47,18 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.Remote.URL.Placeholder}"
Text="{Binding Url, Mode=TwoWay}"/>
Text="{Binding Url, Mode=TwoWay}">
<TextBox.InnerLeftContent>
<Path Width="12" Height="12"
Margin="4,0,2,0"
Data="{StaticResource Icons.Link}"
Fill="{DynamicResource Brush.FG1}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<v:RemoteProtocolSwitcher Url="{Binding Url, Mode=TwoWay}"/>
</TextBox.InnerRightContent>
</TextBox>
<TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
@@ -54,6 +72,12 @@
CornerRadius="3"
Watermark="{DynamicResource Text.SSHKey.Placeholder}"
Text="{Binding SSHKey, Mode=TwoWay}">
<TextBox.InnerLeftContent>
<Path Width="12" Height="12"
Margin="4,0,2,0"
Data="{StaticResource Icons.Password}"
Fill="{DynamicResource Brush.FG1}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<Button Classes="icon_button" Width="30" Height="30" Click="SelectSSHKey">
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>

View File

@@ -3,6 +3,7 @@
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.Clone"
x:DataType="vm:Clone">
@@ -26,7 +27,11 @@
<TextBox Grid.Row="0" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding Remote, Mode=TwoWay}"/>
Text="{Binding Remote, Mode=TwoWay}">
<TextBox.InnerRightContent>
<v:RemoteProtocolSwitcher Url="{Binding Remote, Mode=TwoWay}"/>
</TextBox.InnerRightContent>
</TextBox>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right"

View File

@@ -3,6 +3,7 @@
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="500" d:DesignHeight="450"
x:Class="SourceGit.Views.EditRemote"
x:DataType="vm:EditRemote">
@@ -27,7 +28,14 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.Remote.Name.Placeholder}"
Text="{Binding Name, Mode=TwoWay}"/>
Text="{Binding Name, Mode=TwoWay}">
<TextBox.InnerLeftContent>
<Path Width="12" Height="12"
Margin="4,0,2,0"
Data="{StaticResource Icons.Remote}"
Fill="{DynamicResource Brush.FG1}"/>
</TextBox.InnerLeftContent>
</TextBox>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
@@ -38,7 +46,18 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.Remote.URL.Placeholder}"
Text="{Binding Url, Mode=TwoWay}"/>
Text="{Binding Url, Mode=TwoWay}">
<TextBox.InnerLeftContent>
<Path Width="12" Height="12"
Margin="4,0,2,0"
Data="{StaticResource Icons.Link}"
Fill="{DynamicResource Brush.FG1}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<v:RemoteProtocolSwitcher Url="{Binding Url, Mode=TwoWay}"/>
</TextBox.InnerRightContent>
</TextBox>
<TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
@@ -52,6 +71,12 @@
CornerRadius="3"
Watermark="{DynamicResource Text.SSHKey.Placeholder}"
Text="{Binding SSHKey, Mode=TwoWay}">
<TextBox.InnerLeftContent>
<Path Width="12" Height="12"
Margin="4,0,2,0"
Data="{StaticResource Icons.Password}"
Fill="{DynamicResource Brush.FG1}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<Button Classes="icon_button" Width="30" Height="30" Click="SelectSSHKey">
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>

View 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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.RemoteProtocolSwitcher"
x:Name="ThisControl">
<Button Classes="icon_button" Click="OnOpenDropdownMenu">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12"
Text="{Binding #ThisControl.ActiveProtocol, Mode=OneWay}"
Foreground="{DynamicResource Brush.Link}"/>
<Path Width="10" Height="10"
Margin="4,0,0,0"
VerticalAlignment="Center"
Data="M0 0M1939 486L2029 576L1024 1581L19 576L109 486L1024 1401L1939 486Z"
Fill="{DynamicResource Brush.Link}"/>
</StackPanel>
</Button>
</UserControl>

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
public partial class RemoteProtocolSwitcher : UserControl
{
public static readonly StyledProperty<string> UrlProperty =
AvaloniaProperty.Register<RemoteProtocolSwitcher, string>(nameof(Url));
public string Url
{
get => GetValue(UrlProperty);
set => SetValue(UrlProperty, value);
}
public static readonly StyledProperty<string> ActiveProtocolProperty =
AvaloniaProperty.Register<RemoteProtocolSwitcher, string>(nameof(ActiveProtocol));
public string ActiveProtocol
{
get => GetValue(ActiveProtocolProperty);
set => SetValue(ActiveProtocolProperty, value);
}
public RemoteProtocolSwitcher()
{
InitializeComponent();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == UrlProperty)
{
_protocols.Clear();
var url = Url ?? string.Empty;
if (url.StartsWith("https://", StringComparison.Ordinal) && Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
var host = uri.Host;
var serverName = uri.Port == 443 ? host : $"{host}:{uri.Port}";
var route = uri.AbsolutePath.TrimStart('/');
_protocols.Add(url);
_protocols.Add($"git@{serverName}:{route}");
SetCurrentValue(ActiveProtocolProperty, "HTTPS");
SetCurrentValue(IsVisibleProperty, true);
return;
}
var match = REG_SSH_FORMAT().Match(url);
if (match.Success)
{
var host = match.Groups[1].Value;
var repo = match.Groups[2].Value;
_protocols.Add($"https://{host}/{repo}");
_protocols.Add(url);
SetCurrentValue(ActiveProtocolProperty, "SSH");
SetCurrentValue(IsVisibleProperty, true);
return;
}
SetCurrentValue(IsVisibleProperty, false);
}
}
private void OnOpenDropdownMenu(object sender, RoutedEventArgs e)
{
if (sender is Button btn && _protocols.Count > 0)
{
var menu = new ContextMenu();
menu.Placement = PlacementMode.BottomEdgeAlignedLeft;
foreach (var protocol in _protocols)
{
var dup = protocol;
var item = new MenuItem() { Header = dup };
item.Click += (_, _) => Url = protocol;
menu.Items.Add(item);
}
menu.Open(btn);
}
e.Handled = true;
}
[GeneratedRegex(@"^git@([\w\.\-]+):(.+)$")]
private static partial Regex REG_SSH_FORMAT();
private List<string> _protocols = [];
}
}