refactor: rewrite & redesign the ux for AddWorktree popup (#205)

This commit is contained in:
leo 2024-06-28 12:07:33 +08:00
parent a260c89c0d
commit db8e534a0a
No known key found for this signature in database
5 changed files with 100 additions and 54 deletions

View file

@ -8,6 +8,9 @@
<x:String x:Key="Text.About.SourceCode" xml:space="preserve">• Source code can be found at </x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Opensource &amp; Free Git GUI Client</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">Add Worktree</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">What to Checkout:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Existing Branch</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Create New Branch</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">Location:</x:String>
<x:String x:Key="Text.AddWorktree.Location.Placeholder" xml:space="preserve">Path for this worktree. Relative path is supported.</x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">Branch Name:</x:String>

View file

@ -11,9 +11,12 @@
<x:String x:Key="Text.About.SourceCode" xml:space="preserve">• 项目源代码地址 </x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">开源免费的Git客户端</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">新增工作树</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">检出分支方式 </x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">已有分支</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">创建新分支</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">工作树路径 </x:String>
<x:String x:Key="Text.AddWorktree.Location.Placeholder" xml:space="preserve">填写该工作树的路径。支持相对路径。</x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">自定义分支名 </x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">分支名 </x:String>
<x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">选填。默认使用目标文件夹名称。</x:String>
<x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">跟踪分支</x:String>
<x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">设置上游跟踪分支</x:String>

View file

@ -11,9 +11,12 @@
<x:String x:Key="Text.About.SourceCode" xml:space="preserve">• 專案原始碼地址 </x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">開源免費的Git客戶端</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">新增工作樹</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">檢出分支方式 </x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">已有分支</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">創建新分支</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">工作樹路徑 </x:String>
<x:String x:Key="Text.AddWorktree.Location.Placeholder" xml:space="preserve">填寫該工作樹的路徑。支援相對路徑。</x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">自定义分支名 </x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">分支名 </x:String>
<x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">選填。 預設使用目標資料夾名稱。</x:String>
<x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">跟蹤分支</x:String>
<x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">設置上游跟蹤分支</x:String>

View file

@ -1,29 +1,51 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace SourceGit.ViewModels
{
public partial class AddWorktree : Popup
public class AddWorktree : Popup
{
[GeneratedRegex(@"^[\w\-/\.]+$")]
private static partial Regex REG_NAME();
[Required(ErrorMessage = "Worktree path is required!")]
[CustomValidation(typeof(AddWorktree), nameof(ValidateWorktreePath))]
public string Path
{
get => _path;
set => SetProperty(ref _path, value, true);
set => SetProperty(ref _path, value);
}
[CustomValidation(typeof(AddWorktree), nameof(ValidateBranchName))]
public string CustomName
public bool UseExistingBranch
{
get => _customName;
set => SetProperty(ref _customName, value, true);
get => _useExistingBranch;
set
{
if (SetProperty(ref _useExistingBranch, value, true))
{
if (value)
SelectedBranch = LocalBranches.Count > 0 ? LocalBranches[0] : string.Empty;
else
SelectedBranch = string.Empty;
}
}
}
public List<string> LocalBranches
{
get;
private set;
}
public List<string> RemoteBranches
{
get;
private set;
}
public string SelectedBranch
{
get => _selectedBranch;
set => SetProperty(ref _selectedBranch, value);
}
public bool SetTrackingBranch
@ -32,12 +54,6 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _setTrackingBranch, value);
}
public List<string> TrackingBranches
{
get;
private set;
}
public string SelectedTrackingBranch
{
get;
@ -48,15 +64,23 @@ namespace SourceGit.ViewModels
{
_repo = repo;
TrackingBranches = new List<string>();
LocalBranches = new List<string>();
RemoteBranches = new List<string>();
foreach (var branch in repo.Branches)
{
if (!branch.IsLocal)
TrackingBranches.Add($"{branch.Remote}/{branch.Name}");
if (branch.IsLocal)
LocalBranches.Add(branch.Name);
else
RemoteBranches.Add($"{branch.Remote}/{branch.Name}");
}
if (TrackingBranches.Count > 0)
SelectedTrackingBranch = TrackingBranches[0];
if (LocalBranches.Count > 0)
SelectedBranch = LocalBranches[0];
else
SelectedBranch = string.Empty;
if (RemoteBranches.Count > 0)
SelectedTrackingBranch = RemoteBranches[0];
else
SelectedTrackingBranch = string.Empty;
@ -85,25 +109,6 @@ namespace SourceGit.ViewModels
return ValidationResult.Success;
}
public static ValidationResult ValidateBranchName(string name, ValidationContext ctx)
{
if (string.IsNullOrEmpty(name))
return ValidationResult.Success;
var creator = ctx.ObjectInstance as AddWorktree;
if (creator == null)
return new ValidationResult("Missing runtime context to create branch!");
foreach (var b in creator._repo.Branches)
{
var test = b.IsLocal ? b.Name : $"{b.Remote}/{b.Name}";
if (test == name)
return new ValidationResult("A branch with same name already exists!");
}
return ValidationResult.Success;
}
public override Task<bool> Sure()
{
_repo.SetWatcherEnabled(false);
@ -113,7 +118,7 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
var succ = new Commands.Worktree(_repo.FullPath).Add(_path, _customName, tracking, SetProgressDescription);
var succ = new Commands.Worktree(_repo.FullPath).Add(_path, _selectedBranch, tracking, SetProgressDescription);
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});
@ -121,7 +126,8 @@ namespace SourceGit.ViewModels
private Repository _repo = null;
private string _path = string.Empty;
private string _customName = string.Empty;
private bool _useExistingBranch = true;
private string _selectedBranch = string.Empty;
private bool _setTrackingBranch = false;
}
}

View file

@ -13,7 +13,7 @@
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.AddWorktree}"/>
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,Auto" ColumnDefinitions="120,*">
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,Auto,32" ColumnDefinitions="150,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
@ -32,18 +32,45 @@
</TextBox>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.AddWorktree.WhatToCheckout}"/>
<StackPanel Grid.Row="1" Grid.Column="1" Height="32" Orientation="Horizontal">
<RadioButton Content="{DynamicResource Text.AddWorktree.WhatToCheckout.Existing}"
GroupName="LocalChanges"
IsChecked="{Binding UseExistingBranch, Mode=TwoWay}" />
<RadioButton Content="{DynamicResource Text.AddWorktree.WhatToCheckout.CreateNew}"
GroupName="LocalChanges"
Margin="8,0,0,0" />
</StackPanel>
<TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.AddWorktree.Name}"/>
<TextBox Grid.Row="1" Grid.Column="1"
<ComboBox Grid.Row="2" Grid.Column="1"
Height="28" Padding="8,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch"
ItemsSource="{Binding LocalBranches}"
SelectedItem="{Binding SelectedBranch, Mode=TwoWay}"
IsEnabled="{Binding UseExistingBranch, Mode=OneWay}"
IsVisible="{Binding UseExistingBranch, Mode=OneWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<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}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBox Grid.Row="2" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding CustomName, Mode=TwoWay}"
Watermark="{DynamicResource Text.AddWorktree.Name.Placeholder}"/>
<CheckBox Grid.Row="2" Grid.Column="1"
Content="{DynamicResource Text.AddWorktree.Tracking.Toggle}"
IsChecked="{Binding SetTrackingBranch, Mode=TwoWay}"/>
Text="{Binding SelectedBranch, Mode=TwoWay}"
Watermark="{DynamicResource Text.AddWorktree.Name.Placeholder}"
IsEnabled="{Binding !UseExistingBranch, Mode=OneWay}"
IsVisible="{Binding !UseExistingBranch, Mode=OneWay}"/>
<Border Grid.Row="3" Grid.Column="0"
Height="32"
@ -55,7 +82,7 @@
<ComboBox Grid.Row="3" Grid.Column="1"
Height="28" Padding="8,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch"
ItemsSource="{Binding TrackingBranches}"
ItemsSource="{Binding RemoteBranches}"
SelectedItem="{Binding SelectedTrackingBranch, Mode=TwoWay}"
IsVisible="{Binding SetTrackingBranch, Mode=OneWay}">
<ComboBox.ItemTemplate>
@ -67,6 +94,10 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<CheckBox Grid.Row="4" Grid.Column="1"
Content="{DynamicResource Text.AddWorktree.Tracking.Toggle}"
IsChecked="{Binding SetTrackingBranch, Mode=TwoWay}"/>
</Grid>
</StackPanel>
</UserControl>