mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-06-17 00:14:59 +00:00
Merge branch 'release/v2025.22'
This commit is contained in:
commit
74d77ab704
119 changed files with 974 additions and 534 deletions
|
@ -6,13 +6,15 @@ This document shows the translation status of each locale file in the repository
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing keys in de_DE.axaml</summary>
|
<summary>Missing keys in de_DE.axaml</summary>
|
||||||
|
|
||||||
- Text.Avatar.Load
|
- Text.Avatar.Load
|
||||||
- Text.BranchCM.ResetToSelectedCommit
|
- Text.BranchCM.ResetToSelectedCommit
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
- Text.CommitDetail.Changes.Count
|
- Text.CommitDetail.Changes.Count
|
||||||
- Text.CreateBranch.OverwriteExisting
|
- Text.CreateBranch.OverwriteExisting
|
||||||
- Text.DeinitSubmodule
|
- Text.DeinitSubmodule
|
||||||
|
@ -43,16 +45,9 @@ This document shows the translation status of each locale file in the repository
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
<details>
|
### 
|
||||||
<summary>Missing keys in es_ES.axaml</summary>
|
|
||||||
|
|
||||||
- Text.Avatar.Load
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing keys in fr_FR.axaml</summary>
|
<summary>Missing keys in fr_FR.axaml</summary>
|
||||||
|
@ -67,6 +62,8 @@ This document shows the translation status of each locale file in the repository
|
||||||
- Text.Bisect.WaitingForRange
|
- Text.Bisect.WaitingForRange
|
||||||
- Text.BranchCM.ResetToSelectedCommit
|
- Text.BranchCM.ResetToSelectedCommit
|
||||||
- Text.Checkout.RecurseSubmodules
|
- Text.Checkout.RecurseSubmodules
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
- Text.CommitCM.CopyAuthor
|
- Text.CommitCM.CopyAuthor
|
||||||
- Text.CommitCM.CopyCommitter
|
- Text.CommitCM.CopyCommitter
|
||||||
- Text.CommitCM.CopySubject
|
- Text.CommitCM.CopySubject
|
||||||
|
@ -122,13 +119,15 @@ This document shows the translation status of each locale file in the repository
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing keys in it_IT.axaml</summary>
|
<summary>Missing keys in it_IT.axaml</summary>
|
||||||
|
|
||||||
- Text.Avatar.Load
|
- Text.Avatar.Load
|
||||||
- Text.BranchCM.ResetToSelectedCommit
|
- Text.BranchCM.ResetToSelectedCommit
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
- Text.CommitDetail.Changes.Count
|
- Text.CommitDetail.Changes.Count
|
||||||
- Text.CreateBranch.OverwriteExisting
|
- Text.CreateBranch.OverwriteExisting
|
||||||
- Text.DeinitSubmodule
|
- Text.DeinitSubmodule
|
||||||
|
@ -149,7 +148,7 @@ This document shows the translation status of each locale file in the repository
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing keys in ja_JP.axaml</summary>
|
<summary>Missing keys in ja_JP.axaml</summary>
|
||||||
|
@ -165,6 +164,8 @@ This document shows the translation status of each locale file in the repository
|
||||||
- Text.BranchCM.CompareWithCurrent
|
- Text.BranchCM.CompareWithCurrent
|
||||||
- Text.BranchCM.ResetToSelectedCommit
|
- Text.BranchCM.ResetToSelectedCommit
|
||||||
- Text.Checkout.RecurseSubmodules
|
- Text.Checkout.RecurseSubmodules
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
- Text.CommitCM.CopyAuthor
|
- Text.CommitCM.CopyAuthor
|
||||||
- Text.CommitCM.CopyCommitter
|
- Text.CommitCM.CopyCommitter
|
||||||
- Text.CommitCM.CopySubject
|
- Text.CommitCM.CopySubject
|
||||||
|
@ -221,7 +222,7 @@ This document shows the translation status of each locale file in the repository
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing keys in pt_BR.axaml</summary>
|
<summary>Missing keys in pt_BR.axaml</summary>
|
||||||
|
@ -245,6 +246,8 @@ This document shows the translation status of each locale file in the repository
|
||||||
- Text.BranchCM.ResetToSelectedCommit
|
- Text.BranchCM.ResetToSelectedCommit
|
||||||
- Text.BranchUpstreamInvalid
|
- Text.BranchUpstreamInvalid
|
||||||
- Text.Checkout.RecurseSubmodules
|
- Text.Checkout.RecurseSubmodules
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
- Text.Clone.RecurseSubmodules
|
- Text.Clone.RecurseSubmodules
|
||||||
- Text.CommitCM.CopyAuthor
|
- Text.CommitCM.CopyAuthor
|
||||||
- Text.CommitCM.CopyCommitter
|
- Text.CommitCM.CopyCommitter
|
||||||
|
@ -357,9 +360,17 @@ This document shows the translation status of each locale file in the repository
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
### 
|
<details>
|
||||||
|
<summary>Missing keys in ru_RU.axaml</summary>
|
||||||
|
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### 
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing keys in ta_IN.axaml</summary>
|
<summary>Missing keys in ta_IN.axaml</summary>
|
||||||
|
@ -375,6 +386,8 @@ This document shows the translation status of each locale file in the repository
|
||||||
- Text.BranchCM.CompareWithCurrent
|
- Text.BranchCM.CompareWithCurrent
|
||||||
- Text.BranchCM.ResetToSelectedCommit
|
- Text.BranchCM.ResetToSelectedCommit
|
||||||
- Text.Checkout.RecurseSubmodules
|
- Text.Checkout.RecurseSubmodules
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
- Text.CommitCM.CopyAuthor
|
- Text.CommitCM.CopyAuthor
|
||||||
- Text.CommitCM.CopyCommitter
|
- Text.CommitCM.CopyCommitter
|
||||||
- Text.CommitCM.CopySubject
|
- Text.CommitCM.CopySubject
|
||||||
|
@ -430,7 +443,7 @@ This document shows the translation status of each locale file in the repository
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 
|
### 
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing keys in uk_UA.axaml</summary>
|
<summary>Missing keys in uk_UA.axaml</summary>
|
||||||
|
@ -445,6 +458,8 @@ This document shows the translation status of each locale file in the repository
|
||||||
- Text.Bisect.WaitingForRange
|
- Text.Bisect.WaitingForRange
|
||||||
- Text.BranchCM.ResetToSelectedCommit
|
- Text.BranchCM.ResetToSelectedCommit
|
||||||
- Text.Checkout.RecurseSubmodules
|
- Text.Checkout.RecurseSubmodules
|
||||||
|
- Text.Checkout.WithFastForward
|
||||||
|
- Text.Checkout.WithFastForward.Upstream
|
||||||
- Text.CommitCM.CopyAuthor
|
- Text.CommitCM.CopyAuthor
|
||||||
- Text.CommitCM.CopyCommitter
|
- Text.CommitCM.CopyCommitter
|
||||||
- Text.CommitCM.CopySubject
|
- Text.CommitCM.CopySubject
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
2025.21
|
2025.22
|
|
@ -301,7 +301,7 @@ namespace SourceGit
|
||||||
return await clipboard.GetTextAsync();
|
return await clipboard.GetTextAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return default;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Text(string key, params object[] args)
|
public static string Text(string key, params object[] args)
|
||||||
|
@ -323,8 +323,7 @@ namespace SourceGit
|
||||||
icon.Height = 12;
|
icon.Height = 12;
|
||||||
icon.Stretch = Stretch.Uniform;
|
icon.Stretch = Stretch.Uniform;
|
||||||
|
|
||||||
var geo = Current?.FindResource(key) as StreamGeometry;
|
if (Current?.FindResource(key) is StreamGeometry geo)
|
||||||
if (geo != null)
|
|
||||||
icon.Data = geo;
|
icon.Data = geo;
|
||||||
|
|
||||||
return icon;
|
return icon;
|
||||||
|
@ -682,8 +681,7 @@ namespace SourceGit
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = sb.ToString();
|
var name = sb.ToString();
|
||||||
var idx = name.IndexOf('#');
|
if (name.Contains('#', StringComparison.Ordinal))
|
||||||
if (idx >= 0)
|
|
||||||
{
|
{
|
||||||
if (!name.Equals("fonts:Inter#Inter", StringComparison.Ordinal) &&
|
if (!name.Equals("fonts:Inter#Inter", StringComparison.Ordinal) &&
|
||||||
!name.Equals("fonts:SourceGit#JetBrains Mono", StringComparison.Ordinal))
|
!name.Equals("fonts:SourceGit#JetBrains Mono", StringComparison.Ordinal))
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace SourceGit.Commands
|
||||||
|
|
||||||
private void ParseLine(string line)
|
private void ParseLine(string line)
|
||||||
{
|
{
|
||||||
if (line.IndexOf('\0', StringComparison.Ordinal) >= 0)
|
if (line.Contains('\0', StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
_result.IsBinary = true;
|
_result.IsBinary = true;
|
||||||
_result.LineInfos.Clear();
|
_result.LineInfos.Clear();
|
||||||
|
|
|
@ -194,7 +194,7 @@ namespace SourceGit.Commands
|
||||||
|
|
||||||
private void HandleOutput(string line, List<string> errs)
|
private void HandleOutput(string line, List<string> errs)
|
||||||
{
|
{
|
||||||
line = line ?? string.Empty;
|
line ??= string.Empty;
|
||||||
Log?.AppendLine(line);
|
Log?.AppendLine(line);
|
||||||
|
|
||||||
// Lines to hide in error message.
|
// Lines to hide in error message.
|
||||||
|
|
|
@ -34,6 +34,6 @@ namespace SourceGit.Commands
|
||||||
return succ;
|
return succ;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _tmpFile = string.Empty;
|
private readonly string _tmpFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace SourceGit.Commands
|
||||||
foreach (var line in lines)
|
foreach (var line in lines)
|
||||||
ParseLine(line);
|
ParseLine(line);
|
||||||
|
|
||||||
_changes.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal));
|
_changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
|
||||||
return _changes;
|
return _changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace SourceGit.Commands
|
||||||
[GeneratedRegex(@"^(.+)\s+([\w.]+)\s+\w+:(\d+)$")]
|
[GeneratedRegex(@"^(.+)\s+([\w.]+)\s+\w+:(\d+)$")]
|
||||||
private static partial Regex REG_LOCK();
|
private static partial Regex REG_LOCK();
|
||||||
|
|
||||||
class SubCmd : Command
|
private class SubCmd : Command
|
||||||
{
|
{
|
||||||
public SubCmd(string repo, string args, Models.ICommandLog log)
|
public SubCmd(string repo, string args, Models.ICommandLog log)
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,6 +90,6 @@ namespace SourceGit.Commands
|
||||||
|
|
||||||
private List<Models.InteractiveCommit> _commits = [];
|
private List<Models.InteractiveCommit> _commits = [];
|
||||||
private Models.InteractiveCommit _current = null;
|
private Models.InteractiveCommit _current = null;
|
||||||
private string _boundary = "";
|
private readonly string _boundary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,6 @@ namespace SourceGit.Commands
|
||||||
|
|
||||||
public long Result()
|
public long Result()
|
||||||
{
|
{
|
||||||
if (_result != 0)
|
|
||||||
return _result;
|
|
||||||
|
|
||||||
var rs = ReadToEnd();
|
var rs = ReadToEnd();
|
||||||
if (rs.IsSuccess)
|
if (rs.IsSuccess)
|
||||||
{
|
{
|
||||||
|
@ -29,7 +26,5 @@ namespace SourceGit.Commands
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly long _result = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,11 @@ namespace SourceGit.Commands
|
||||||
_patchBuilder.Append(c.DataForAmend.ObjectHash);
|
_patchBuilder.Append(c.DataForAmend.ObjectHash);
|
||||||
_patchBuilder.Append("\t");
|
_patchBuilder.Append("\t");
|
||||||
_patchBuilder.Append(c.OriginalPath);
|
_patchBuilder.Append(c.OriginalPath);
|
||||||
_patchBuilder.Append("\n");
|
|
||||||
}
|
}
|
||||||
else if (c.Index == Models.ChangeState.Added)
|
else if (c.Index == Models.ChangeState.Added)
|
||||||
{
|
{
|
||||||
_patchBuilder.Append("0 0000000000000000000000000000000000000000\t");
|
_patchBuilder.Append("0 0000000000000000000000000000000000000000\t");
|
||||||
_patchBuilder.Append(c.Path);
|
_patchBuilder.Append(c.Path);
|
||||||
_patchBuilder.Append("\n");
|
|
||||||
}
|
}
|
||||||
else if (c.Index == Models.ChangeState.Deleted)
|
else if (c.Index == Models.ChangeState.Deleted)
|
||||||
{
|
{
|
||||||
|
@ -37,7 +35,6 @@ namespace SourceGit.Commands
|
||||||
_patchBuilder.Append(c.DataForAmend.ObjectHash);
|
_patchBuilder.Append(c.DataForAmend.ObjectHash);
|
||||||
_patchBuilder.Append("\t");
|
_patchBuilder.Append("\t");
|
||||||
_patchBuilder.Append(c.Path);
|
_patchBuilder.Append(c.Path);
|
||||||
_patchBuilder.Append("\n");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -46,8 +43,9 @@ namespace SourceGit.Commands
|
||||||
_patchBuilder.Append(c.DataForAmend.ObjectHash);
|
_patchBuilder.Append(c.DataForAmend.ObjectHash);
|
||||||
_patchBuilder.Append("\t");
|
_patchBuilder.Append("\t");
|
||||||
_patchBuilder.Append(c.Path);
|
_patchBuilder.Append(c.Path);
|
||||||
_patchBuilder.Append("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_patchBuilder.Append("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace SourceGit.Models
|
||||||
[GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@.+\.github\.com$")]
|
[GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@.+\.github\.com$")]
|
||||||
private static partial Regex REG_GITHUB_USER_EMAIL();
|
private static partial Regex REG_GITHUB_USER_EMAIL();
|
||||||
|
|
||||||
private object _synclock = new object();
|
private readonly Lock _synclock = new();
|
||||||
private string _storePath;
|
private string _storePath;
|
||||||
private List<IAvatarHost> _avatars = new List<IAvatarHost>();
|
private List<IAvatarHost> _avatars = new List<IAvatarHost>();
|
||||||
private Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>();
|
private Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>();
|
||||||
|
@ -144,7 +144,6 @@ namespace SourceGit.Models
|
||||||
if (_defaultAvatars.Contains(email))
|
if (_defaultAvatars.Contains(email))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (_resources.ContainsKey(email))
|
|
||||||
_resources.Remove(email);
|
_resources.Remove(email);
|
||||||
|
|
||||||
var localFile = Path.Combine(_storePath, GetEmailHash(email));
|
var localFile = Path.Combine(_storePath, GetEmailHash(email));
|
||||||
|
@ -179,7 +178,6 @@ namespace SourceGit.Models
|
||||||
|
|
||||||
lock (_synclock)
|
lock (_synclock)
|
||||||
{
|
{
|
||||||
if (!_requesting.Contains(email))
|
|
||||||
_requesting.Add(email);
|
_requesting.Add(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,10 +198,7 @@ namespace SourceGit.Models
|
||||||
if (image == null)
|
if (image == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_resources.ContainsKey(email))
|
|
||||||
_resources[email] = image;
|
_resources[email] = image;
|
||||||
else
|
|
||||||
_resources.Add(email, image);
|
|
||||||
|
|
||||||
_requesting.Remove(email);
|
_requesting.Remove(email);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace SourceGit.Models
|
||||||
public class Commit
|
public class Commit
|
||||||
{
|
{
|
||||||
// As retrieved by: git mktree </dev/null
|
// As retrieved by: git mktree </dev/null
|
||||||
public static readonly string EmptyTreeSHA1 = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
public const string EmptyTreeSHA1 = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
||||||
|
|
||||||
public static double OpacityForNotMerged
|
public static double OpacityForNotMerged
|
||||||
{
|
{
|
||||||
|
@ -113,7 +113,7 @@ namespace SourceGit.Models
|
||||||
if (l.Type != r.Type)
|
if (l.Type != r.Type)
|
||||||
return (int)l.Type - (int)r.Type;
|
return (int)l.Type - (int)r.Type;
|
||||||
else
|
else
|
||||||
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
|
return NumericSort.Compare(l.Name, r.Name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace SourceGit.Models
|
namespace SourceGit.Models
|
||||||
{
|
{
|
||||||
public partial class CommitTemplate : ObservableObject
|
public class CommitTemplate : ObservableObject
|
||||||
{
|
{
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
Builtin,
|
Builtin,
|
||||||
Pfim
|
Pfim,
|
||||||
|
Tiff,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace SourceGit.Models
|
using System;
|
||||||
|
|
||||||
|
namespace SourceGit.Models
|
||||||
{
|
{
|
||||||
public static class NumericSort
|
public static class NumericSort
|
||||||
{
|
{
|
||||||
|
@ -10,52 +12,35 @@
|
||||||
int marker1 = 0;
|
int marker1 = 0;
|
||||||
int marker2 = 0;
|
int marker2 = 0;
|
||||||
|
|
||||||
char[] tmp1 = new char[len1];
|
|
||||||
char[] tmp2 = new char[len2];
|
|
||||||
|
|
||||||
while (marker1 < len1 && marker2 < len2)
|
while (marker1 < len1 && marker2 < len2)
|
||||||
{
|
{
|
||||||
char c1 = s1[marker1];
|
char c1 = s1[marker1];
|
||||||
char c2 = s2[marker2];
|
char c2 = s2[marker2];
|
||||||
int loc1 = 0;
|
|
||||||
int loc2 = 0;
|
|
||||||
|
|
||||||
bool isDigit1 = char.IsDigit(c1);
|
bool isDigit1 = char.IsDigit(c1);
|
||||||
bool isDigit2 = char.IsDigit(c2);
|
bool isDigit2 = char.IsDigit(c2);
|
||||||
if (isDigit1 != isDigit2)
|
if (isDigit1 != isDigit2)
|
||||||
return c1.CompareTo(c2);
|
return c1.CompareTo(c2);
|
||||||
|
|
||||||
do
|
int subLen1 = 1;
|
||||||
{
|
while (marker1 + subLen1 < len1 && char.IsDigit(s1[marker1 + subLen1]) == isDigit1)
|
||||||
tmp1[loc1] = c1;
|
subLen1++;
|
||||||
loc1++;
|
|
||||||
marker1++;
|
|
||||||
|
|
||||||
if (marker1 < len1)
|
int subLen2 = 1;
|
||||||
c1 = s1[marker1];
|
while (marker2 + subLen2 < len2 && char.IsDigit(s2[marker2 + subLen2]) == isDigit2)
|
||||||
else
|
subLen2++;
|
||||||
break;
|
|
||||||
} while (char.IsDigit(c1) == isDigit1);
|
|
||||||
|
|
||||||
do
|
string sub1 = s1.Substring(marker1, subLen1);
|
||||||
{
|
string sub2 = s2.Substring(marker2, subLen2);
|
||||||
tmp2[loc2] = c2;
|
|
||||||
loc2++;
|
|
||||||
marker2++;
|
|
||||||
|
|
||||||
if (marker2 < len2)
|
marker1 += subLen1;
|
||||||
c2 = s2[marker2];
|
marker2 += subLen2;
|
||||||
else
|
|
||||||
break;
|
|
||||||
} while (char.IsDigit(c2) == isDigit2);
|
|
||||||
|
|
||||||
string sub1 = new string(tmp1, 0, loc1);
|
|
||||||
string sub2 = new string(tmp2, 0, loc2);
|
|
||||||
int result;
|
int result;
|
||||||
if (isDigit1)
|
if (isDigit1)
|
||||||
result = loc1 == loc2 ? string.CompareOrdinal(sub1, sub2) : loc1 - loc2;
|
result = (subLen1 == subLen2) ? string.CompareOrdinal(sub1, sub2) : (subLen1 - subLen2);
|
||||||
else
|
else
|
||||||
result = string.CompareOrdinal(sub1, sub2);
|
result = string.Compare(sub1, sub2, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -287,9 +287,8 @@ namespace SourceGit.Models
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < HistoriesFilters.Count; i++)
|
foreach (var filter in HistoriesFilters)
|
||||||
{
|
{
|
||||||
var filter = HistoriesFilters[i];
|
|
||||||
if (filter.Type != type)
|
if (filter.Type != type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -402,7 +402,7 @@ namespace SourceGit.Models
|
||||||
|
|
||||||
sb.AppendJoin(", ", paths);
|
sb.AppendJoin(", ", paths);
|
||||||
if (max < context.changes.Count)
|
if (max < context.changes.Count)
|
||||||
sb.AppendFormat(" and {0} other files", context.changes.Count - max);
|
sb.Append($" and {context.changes.Count - max} other files");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace SourceGit.Models
|
||||||
public int AddedStart { get; set; }
|
public int AddedStart { get; set; }
|
||||||
public int AddedCount { get; set; }
|
public int AddedCount { get; set; }
|
||||||
|
|
||||||
class Chunk
|
private class Chunk
|
||||||
{
|
{
|
||||||
public int Hash;
|
public int Hash;
|
||||||
public bool Modified;
|
public bool Modified;
|
||||||
|
@ -25,7 +25,7 @@ namespace SourceGit.Models
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Edit
|
private enum Edit
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
DeletedRight,
|
DeletedRight,
|
||||||
|
@ -34,7 +34,7 @@ namespace SourceGit.Models
|
||||||
AddedLeft,
|
AddedLeft,
|
||||||
}
|
}
|
||||||
|
|
||||||
class EditResult
|
private class EditResult
|
||||||
{
|
{
|
||||||
public Edit State;
|
public Edit State;
|
||||||
public int DeleteStart;
|
public int DeleteStart;
|
||||||
|
@ -204,11 +204,10 @@ namespace SourceGit.Models
|
||||||
|
|
||||||
for (int i = 0; i <= half; i++)
|
for (int i = 0; i <= half; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int j = -i; j <= i; j += 2)
|
for (int j = -i; j <= i; j += 2)
|
||||||
{
|
{
|
||||||
var idx = j + half;
|
var idx = j + half;
|
||||||
int o, n;
|
int o;
|
||||||
if (j == -i || (j != i && forward[idx - 1] < forward[idx + 1]))
|
if (j == -i || (j != i && forward[idx - 1] < forward[idx + 1]))
|
||||||
{
|
{
|
||||||
o = forward[idx + 1];
|
o = forward[idx + 1];
|
||||||
|
@ -220,7 +219,7 @@ namespace SourceGit.Models
|
||||||
rs.State = Edit.DeletedRight;
|
rs.State = Edit.DeletedRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = o - j;
|
var n = o - j;
|
||||||
|
|
||||||
var startX = o;
|
var startX = o;
|
||||||
var startY = n;
|
var startY = n;
|
||||||
|
@ -258,7 +257,7 @@ namespace SourceGit.Models
|
||||||
for (int j = -i; j <= i; j += 2)
|
for (int j = -i; j <= i; j += 2)
|
||||||
{
|
{
|
||||||
var idx = j + half;
|
var idx = j + half;
|
||||||
int o, n;
|
int o;
|
||||||
if (j == -i || (j != i && reverse[idx + 1] <= reverse[idx - 1]))
|
if (j == -i || (j != i && reverse[idx + 1] <= reverse[idx - 1]))
|
||||||
{
|
{
|
||||||
o = reverse[idx + 1] - 1;
|
o = reverse[idx + 1] - 1;
|
||||||
|
@ -270,7 +269,7 @@ namespace SourceGit.Models
|
||||||
rs.State = Edit.AddedLeft;
|
rs.State = Edit.AddedLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = o - (j + delta);
|
var n = o - (j + delta);
|
||||||
|
|
||||||
var endX = o;
|
var endX = o;
|
||||||
var endY = n;
|
var endY = n;
|
||||||
|
@ -312,8 +311,7 @@ namespace SourceGit.Models
|
||||||
|
|
||||||
private static void AddChunk(List<Chunk> chunks, Dictionary<string, int> hashes, string data, int start)
|
private static void AddChunk(List<Chunk> chunks, Dictionary<string, int> hashes, string data, int start)
|
||||||
{
|
{
|
||||||
int hash;
|
if (hashes.TryGetValue(data, out var hash))
|
||||||
if (hashes.TryGetValue(data, out hash))
|
|
||||||
{
|
{
|
||||||
chunks.Add(new Chunk(hash, start, data.Length));
|
chunks.Add(new Chunk(hash, start, data.Length));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,7 @@ namespace SourceGit.Models
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (obj == null || !(obj is User))
|
return obj is User other && Name == other.Name && Email == other.Email;
|
||||||
return false;
|
|
||||||
|
|
||||||
var other = obj as User;
|
|
||||||
return Name == other.Name && Email == other.Email;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
|
|
|
@ -246,7 +246,7 @@ namespace SourceGit.Models
|
||||||
private long _updateStashes = 0;
|
private long _updateStashes = 0;
|
||||||
private long _updateTags = 0;
|
private long _updateTags = 0;
|
||||||
|
|
||||||
private object _lockSubmodule = new object();
|
private readonly Lock _lockSubmodule = new();
|
||||||
private List<string> _submodules = new List<string>();
|
private List<string> _submodules = new List<string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,23 +127,17 @@ namespace SourceGit.Native
|
||||||
Microsoft.Win32.RegistryHive.LocalMachine,
|
Microsoft.Win32.RegistryHive.LocalMachine,
|
||||||
Microsoft.Win32.RegistryView.Registry64);
|
Microsoft.Win32.RegistryView.Registry64);
|
||||||
|
|
||||||
var git = reg.OpenSubKey("SOFTWARE\\GitForWindows");
|
var git = reg.OpenSubKey(@"SOFTWARE\GitForWindows");
|
||||||
if (git != null && git.GetValue("InstallPath") is string installPath)
|
if (git?.GetValue("InstallPath") is string installPath)
|
||||||
{
|
|
||||||
return Path.Combine(installPath, "bin", "git.exe");
|
return Path.Combine(installPath, "bin", "git.exe");
|
||||||
}
|
|
||||||
|
|
||||||
var builder = new StringBuilder("git.exe", 259);
|
var builder = new StringBuilder("git.exe", 259);
|
||||||
if (!PathFindOnPath(builder, null))
|
if (!PathFindOnPath(builder, null))
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
var exePath = builder.ToString();
|
var exePath = builder.ToString();
|
||||||
if (!string.IsNullOrEmpty(exePath))
|
if (!string.IsNullOrEmpty(exePath))
|
||||||
{
|
|
||||||
return exePath;
|
return exePath;
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +175,7 @@ namespace SourceGit.Native
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "cmd":
|
case "cmd":
|
||||||
return "C:\\Windows\\System32\\cmd.exe";
|
return @"C:\Windows\System32\cmd.exe";
|
||||||
case "wt":
|
case "wt":
|
||||||
var wtFinder = new StringBuilder("wt.exe", 512);
|
var wtFinder = new StringBuilder("wt.exe", 512);
|
||||||
if (PathFindOnPath(wtFinder, null))
|
if (PathFindOnPath(wtFinder, null))
|
||||||
|
@ -199,8 +193,8 @@ namespace SourceGit.Native
|
||||||
finder.VSCode(FindVSCode);
|
finder.VSCode(FindVSCode);
|
||||||
finder.VSCodeInsiders(FindVSCodeInsiders);
|
finder.VSCodeInsiders(FindVSCodeInsiders);
|
||||||
finder.VSCodium(FindVSCodium);
|
finder.VSCodium(FindVSCodium);
|
||||||
finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\Programs\\Fleet\\Fleet.exe");
|
finder.Fleet(() => $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\Programs\Fleet\Fleet.exe");
|
||||||
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\JetBrains\\Toolbox");
|
finder.FindJetBrainsFromToolbox(() => $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\JetBrains\Toolbox");
|
||||||
finder.SublimeText(FindSublimeText);
|
finder.SublimeText(FindSublimeText);
|
||||||
finder.TryAdd("Visual Studio", "vs", FindVisualStudio, GenerateCommandlineArgsForVisualStudio);
|
finder.TryAdd("Visual Studio", "vs", FindVisualStudio, GenerateCommandlineArgsForVisualStudio);
|
||||||
return finder.Founded;
|
return finder.Founded;
|
||||||
|
@ -299,9 +293,7 @@ namespace SourceGit.Native
|
||||||
// VSCode (system)
|
// VSCode (system)
|
||||||
var systemVScode = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{EA457B21-F73E-494C-ACAB-524FDE069978}_is1");
|
var systemVScode = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{EA457B21-F73E-494C-ACAB-524FDE069978}_is1");
|
||||||
if (systemVScode != null)
|
if (systemVScode != null)
|
||||||
{
|
|
||||||
return systemVScode.GetValue("DisplayIcon") as string;
|
return systemVScode.GetValue("DisplayIcon") as string;
|
||||||
}
|
|
||||||
|
|
||||||
var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
|
var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
|
||||||
Microsoft.Win32.RegistryHive.CurrentUser,
|
Microsoft.Win32.RegistryHive.CurrentUser,
|
||||||
|
@ -310,9 +302,7 @@ namespace SourceGit.Native
|
||||||
// VSCode (user)
|
// VSCode (user)
|
||||||
var vscode = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1");
|
var vscode = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1");
|
||||||
if (vscode != null)
|
if (vscode != null)
|
||||||
{
|
|
||||||
return vscode.GetValue("DisplayIcon") as string;
|
return vscode.GetValue("DisplayIcon") as string;
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -326,9 +316,7 @@ namespace SourceGit.Native
|
||||||
// VSCode - Insiders (system)
|
// VSCode - Insiders (system)
|
||||||
var systemVScodeInsiders = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1287CAD5-7C8D-410D-88B9-0D1EE4A83FF2}_is1");
|
var systemVScodeInsiders = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1287CAD5-7C8D-410D-88B9-0D1EE4A83FF2}_is1");
|
||||||
if (systemVScodeInsiders != null)
|
if (systemVScodeInsiders != null)
|
||||||
{
|
|
||||||
return systemVScodeInsiders.GetValue("DisplayIcon") as string;
|
return systemVScodeInsiders.GetValue("DisplayIcon") as string;
|
||||||
}
|
|
||||||
|
|
||||||
var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
|
var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
|
||||||
Microsoft.Win32.RegistryHive.CurrentUser,
|
Microsoft.Win32.RegistryHive.CurrentUser,
|
||||||
|
@ -337,9 +325,7 @@ namespace SourceGit.Native
|
||||||
// VSCode - Insiders (user)
|
// VSCode - Insiders (user)
|
||||||
var vscodeInsiders = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1");
|
var vscodeInsiders = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1");
|
||||||
if (vscodeInsiders != null)
|
if (vscodeInsiders != null)
|
||||||
{
|
|
||||||
return vscodeInsiders.GetValue("DisplayIcon") as string;
|
return vscodeInsiders.GetValue("DisplayIcon") as string;
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -353,9 +339,7 @@ namespace SourceGit.Native
|
||||||
// VSCodium (system)
|
// VSCodium (system)
|
||||||
var systemVSCodium = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{88DA3577-054F-4CA1-8122-7D820494CFFB}_is1");
|
var systemVSCodium = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{88DA3577-054F-4CA1-8122-7D820494CFFB}_is1");
|
||||||
if (systemVSCodium != null)
|
if (systemVSCodium != null)
|
||||||
{
|
|
||||||
return systemVSCodium.GetValue("DisplayIcon") as string;
|
return systemVSCodium.GetValue("DisplayIcon") as string;
|
||||||
}
|
|
||||||
|
|
||||||
var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
|
var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
|
||||||
Microsoft.Win32.RegistryHive.CurrentUser,
|
Microsoft.Win32.RegistryHive.CurrentUser,
|
||||||
|
@ -364,9 +348,7 @@ namespace SourceGit.Native
|
||||||
// VSCodium (user)
|
// VSCodium (user)
|
||||||
var vscodium = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2E1F05D1-C245-4562-81EE-28188DB6FD17}_is1");
|
var vscodium = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2E1F05D1-C245-4562-81EE-28188DB6FD17}_is1");
|
||||||
if (vscodium != null)
|
if (vscodium != null)
|
||||||
{
|
|
||||||
return vscodium.GetValue("DisplayIcon") as string;
|
return vscodium.GetValue("DisplayIcon") as string;
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -409,10 +391,8 @@ namespace SourceGit.Native
|
||||||
if (launcher.GetValue(string.Empty) is string CLSID &&
|
if (launcher.GetValue(string.Empty) is string CLSID &&
|
||||||
localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is Microsoft.Win32.RegistryKey devenv &&
|
localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is Microsoft.Win32.RegistryKey devenv &&
|
||||||
devenv.GetValue(string.Empty) is string localServer32)
|
devenv.GetValue(string.Empty) is string localServer32)
|
||||||
{
|
|
||||||
return localServer32!.Trim('\"');
|
return localServer32!.Trim('\"');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 4 KiB After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 3.2 KiB |
|
@ -86,6 +86,8 @@
|
||||||
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash & Reapply</x:String>
|
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash & Reapply</x:String>
|
||||||
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">Update all submodules</x:String>
|
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">Update all submodules</x:String>
|
||||||
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch:</x:String>
|
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch:</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward" xml:space="preserve">Checkout & Fast-Forward</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward.Upstream" xml:space="preserve">Fast-Forward to:</x:String>
|
||||||
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
|
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">Append source to commit message</x:String>
|
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">Append source to commit message</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
|
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
<x:String x:Key="Text.AssumeUnchanged" xml:space="preserve">ARCHIVOS ASUMIDOS COMO SIN CAMBIOS</x:String>
|
<x:String x:Key="Text.AssumeUnchanged" xml:space="preserve">ARCHIVOS ASUMIDOS COMO SIN CAMBIOS</x:String>
|
||||||
<x:String x:Key="Text.AssumeUnchanged.Empty" xml:space="preserve">NO HAY ARCHIVOS ASUMIDOS COMO SIN CAMBIOS</x:String>
|
<x:String x:Key="Text.AssumeUnchanged.Empty" xml:space="preserve">NO HAY ARCHIVOS ASUMIDOS COMO SIN CAMBIOS</x:String>
|
||||||
<x:String x:Key="Text.AssumeUnchanged.Remove" xml:space="preserve">REMOVER</x:String>
|
<x:String x:Key="Text.AssumeUnchanged.Remove" xml:space="preserve">REMOVER</x:String>
|
||||||
|
<x:String x:Key="Text.Avatar.Load" xml:space="preserve">Cargar Imagen...</x:String>
|
||||||
<x:String x:Key="Text.Avatar.Refetch" xml:space="preserve">Refrescar</x:String>
|
<x:String x:Key="Text.Avatar.Refetch" xml:space="preserve">Refrescar</x:String>
|
||||||
<x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">¡ARCHIVO BINARIO NO SOPORTADO!</x:String>
|
<x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">¡ARCHIVO BINARIO NO SOPORTADO!</x:String>
|
||||||
<x:String x:Key="Text.Bisect">Bisect</x:String>
|
<x:String x:Key="Text.Bisect">Bisect</x:String>
|
||||||
|
@ -89,6 +90,8 @@
|
||||||
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash & Reaplicar</x:String>
|
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash & Reaplicar</x:String>
|
||||||
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">Actualizar todos los submódulos</x:String>
|
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">Actualizar todos los submódulos</x:String>
|
||||||
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Rama:</x:String>
|
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Rama:</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward" xml:space="preserve">Checkout & Fast-Forward</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward.Upstream" xml:space="preserve">Fast-Forward a:</x:String>
|
||||||
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
|
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">Añadir fuente al mensaje de commit</x:String>
|
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">Añadir fuente al mensaje de commit</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
|
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
|
||||||
|
|
|
@ -90,6 +90,8 @@
|
||||||
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">贮藏并自动恢复</x:String>
|
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">贮藏并自动恢复</x:String>
|
||||||
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">同时更新所有子模块</x:String>
|
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">同时更新所有子模块</x:String>
|
||||||
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">目标分支 :</x:String>
|
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">目标分支 :</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward" xml:space="preserve">检出分支并快进</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward.Upstream" xml:space="preserve">上游分支 :</x:String>
|
||||||
<x:String x:Key="Text.CherryPick" xml:space="preserve">挑选提交</x:String>
|
<x:String x:Key="Text.CherryPick" xml:space="preserve">挑选提交</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">提交信息中追加来源信息</x:String>
|
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">提交信息中追加来源信息</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表 :</x:String>
|
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表 :</x:String>
|
||||||
|
|
|
@ -90,6 +90,8 @@
|
||||||
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">擱置變更並自動復原</x:String>
|
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">擱置變更並自動復原</x:String>
|
||||||
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">同時更新所有子模組</x:String>
|
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">同時更新所有子模組</x:String>
|
||||||
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">目標分支:</x:String>
|
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">目標分支:</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward" xml:space="preserve">簽出分支並快轉</x:String>
|
||||||
|
<x:String x:Key="Text.Checkout.WithFastForward.Upstream" xml:space="preserve">上游分支 :</x:String>
|
||||||
<x:String x:Key="Text.CherryPick" xml:space="preserve">揀選提交</x:String>
|
<x:String x:Key="Text.CherryPick" xml:space="preserve">揀選提交</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">提交資訊中追加來源資訊</x:String>
|
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">提交資訊中追加來源資訊</x:String>
|
||||||
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表:</x:String>
|
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表:</x:String>
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.2.0" />
|
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.2.0" />
|
||||||
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.2.0" />
|
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.2.0" />
|
||||||
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.4" />
|
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.4" />
|
||||||
|
<PackageReference Include="BitMiracle.LibTiff.NET" Version="2.4.660" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5.4" />
|
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5.4" />
|
||||||
<PackageReference Include="OpenAI" Version="2.2.0-beta.4" />
|
<PackageReference Include="OpenAI" Version="2.2.0-beta.4" />
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
@ -10,10 +11,25 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
public class Blame : ObservableObject
|
public class Blame : ObservableObject
|
||||||
{
|
{
|
||||||
public string Title
|
public string FilePath
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
}
|
||||||
|
|
||||||
|
public Models.Commit Revision
|
||||||
|
{
|
||||||
|
get => _revision;
|
||||||
|
private set => SetProperty(ref _revision, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Models.BlameData Data
|
||||||
|
{
|
||||||
|
get => _data;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _data, value))
|
||||||
|
OnPropertyChanged(nameof(IsBinary));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsBinary
|
public bool IsBinary
|
||||||
|
@ -21,42 +37,27 @@ namespace SourceGit.ViewModels
|
||||||
get => _data != null && _data.IsBinary;
|
get => _data != null && _data.IsBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Models.BlameData Data
|
public bool CanBack
|
||||||
{
|
{
|
||||||
get => _data;
|
get => _navigationActiveIndex > 0;
|
||||||
private set => SetProperty(ref _data, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Blame(string repo, string file, string revision)
|
public bool CanForward
|
||||||
{
|
{
|
||||||
|
get => _navigationActiveIndex < _navigationHistory.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Blame(string repo, string file, Models.Commit commit)
|
||||||
|
{
|
||||||
|
var sha = commit.SHA.Substring(0, 10);
|
||||||
|
|
||||||
|
FilePath = file;
|
||||||
|
Revision = commit;
|
||||||
|
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
|
_navigationHistory.Add(sha);
|
||||||
Title = $"{file} @ {revision.AsSpan(0, 10)}";
|
_commits.Add(sha, commit);
|
||||||
Task.Run(() =>
|
SetBlameData(sha);
|
||||||
{
|
|
||||||
var result = new Commands.Blame(repo, file, revision).Result();
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
|
||||||
{
|
|
||||||
Data = result;
|
|
||||||
OnPropertyChanged(nameof(IsBinary));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NavigateToCommit(string commitSHA)
|
|
||||||
{
|
|
||||||
var launcher = App.GetLauncher();
|
|
||||||
if (launcher == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var page in launcher.Pages)
|
|
||||||
{
|
|
||||||
if (page.Data is Repository repo && repo.FullPath.Equals(_repo))
|
|
||||||
{
|
|
||||||
repo.NavigateToCommit(commitSHA);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetCommitMessage(string sha)
|
public string GetCommitMessage(string sha)
|
||||||
|
@ -69,8 +70,102 @@ namespace SourceGit.ViewModels
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly string _repo;
|
public void Back()
|
||||||
|
{
|
||||||
|
if (_navigationActiveIndex <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_navigationActiveIndex--;
|
||||||
|
OnPropertyChanged(nameof(CanBack));
|
||||||
|
OnPropertyChanged(nameof(CanForward));
|
||||||
|
NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Forward()
|
||||||
|
{
|
||||||
|
if (_navigationActiveIndex >= _navigationHistory.Count - 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_navigationActiveIndex++;
|
||||||
|
OnPropertyChanged(nameof(CanBack));
|
||||||
|
OnPropertyChanged(nameof(CanForward));
|
||||||
|
NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateToCommit(string commitSHA)
|
||||||
|
{
|
||||||
|
if (!_navigationHistory[_navigationActiveIndex].Equals(commitSHA, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_navigationHistory.Add(commitSHA);
|
||||||
|
_navigationActiveIndex = _navigationHistory.Count - 1;
|
||||||
|
OnPropertyChanged(nameof(CanBack));
|
||||||
|
OnPropertyChanged(nameof(CanForward));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Revision.SHA.StartsWith(commitSHA, StringComparison.Ordinal))
|
||||||
|
SetBlameData(commitSHA);
|
||||||
|
|
||||||
|
if (App.GetLauncher() is { Pages: { } pages })
|
||||||
|
{
|
||||||
|
foreach (var page in pages)
|
||||||
|
{
|
||||||
|
if (page.Data is Repository repo && repo.FullPath.Equals(_repo))
|
||||||
|
{
|
||||||
|
repo.NavigateToCommit(commitSHA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetBlameData(string commitSHA)
|
||||||
|
{
|
||||||
|
if (_cancellationSource is { IsCancellationRequested: false })
|
||||||
|
_cancellationSource.Cancel();
|
||||||
|
|
||||||
|
_cancellationSource = new CancellationTokenSource();
|
||||||
|
var token = _cancellationSource.Token;
|
||||||
|
|
||||||
|
if (_commits.TryGetValue(commitSHA, out var c))
|
||||||
|
{
|
||||||
|
Revision = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var result = new Commands.QuerySingleCommit(_repo, commitSHA).Result();
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
_commits.Add(commitSHA, result);
|
||||||
|
Revision = result ?? new Models.Commit() { SHA = commitSHA };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var result = new Commands.Blame(_repo, FilePath, commitSHA).Result();
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (!token.IsCancellationRequested)
|
||||||
|
Data = result;
|
||||||
|
});
|
||||||
|
}, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _repo;
|
||||||
|
private Models.Commit _revision;
|
||||||
|
private CancellationTokenSource _cancellationSource = null;
|
||||||
|
private int _navigationActiveIndex = 0;
|
||||||
|
private List<string> _navigationHistory = [];
|
||||||
private Models.BlameData _data = null;
|
private Models.BlameData _data = null;
|
||||||
private Dictionary<string, string> _commitMessages = new Dictionary<string, string>();
|
private Dictionary<string, Models.Commit> _commits = new();
|
||||||
|
private Dictionary<string, string> _commitMessages = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
111
src/ViewModels/CheckoutAndFastForward.cs
Normal file
111
src/ViewModels/CheckoutAndFastForward.cs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SourceGit.ViewModels
|
||||||
|
{
|
||||||
|
public class CheckoutAndFastForward : Popup
|
||||||
|
{
|
||||||
|
public Models.Branch LocalBranch
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Models.Branch RemoteBranch
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DiscardLocalChanges
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRecurseSubmoduleVisible
|
||||||
|
{
|
||||||
|
get => _repo.Submodules.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RecurseSubmodules
|
||||||
|
{
|
||||||
|
get => _repo.Settings.UpdateSubmodulesOnCheckoutBranch;
|
||||||
|
set => _repo.Settings.UpdateSubmodulesOnCheckoutBranch = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckoutAndFastForward(Repository repo, Models.Branch localBranch, Models.Branch remoteBranch)
|
||||||
|
{
|
||||||
|
_repo = repo;
|
||||||
|
LocalBranch = localBranch;
|
||||||
|
RemoteBranch = remoteBranch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<bool> Sure()
|
||||||
|
{
|
||||||
|
_repo.SetWatcherEnabled(false);
|
||||||
|
ProgressDescription = $"Checkout and Fast-Forward '{LocalBranch.Name}' ...";
|
||||||
|
|
||||||
|
var log = _repo.CreateLog($"Checkout and Fast-Forward '{LocalBranch.Name}' ...");
|
||||||
|
Use(log);
|
||||||
|
|
||||||
|
var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules;
|
||||||
|
return Task.Run(() =>
|
||||||
|
{
|
||||||
|
var succ = false;
|
||||||
|
var needPopStash = false;
|
||||||
|
|
||||||
|
if (DiscardLocalChanges)
|
||||||
|
{
|
||||||
|
succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBranch.Head, true, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
|
||||||
|
if (changes > 0)
|
||||||
|
{
|
||||||
|
succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AND_FASTFORWARD_AUTO_STASH");
|
||||||
|
if (!succ)
|
||||||
|
{
|
||||||
|
log.Complete();
|
||||||
|
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
needPopStash = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBranch.Head, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (succ)
|
||||||
|
{
|
||||||
|
if (updateSubmodules)
|
||||||
|
{
|
||||||
|
var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result();
|
||||||
|
if (submodules.Count > 0)
|
||||||
|
new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needPopStash)
|
||||||
|
new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Complete();
|
||||||
|
|
||||||
|
CallUIThread(() =>
|
||||||
|
{
|
||||||
|
ProgressDescription = "Waiting for branch updated...";
|
||||||
|
|
||||||
|
if (_repo.HistoriesFilterMode == Models.FilterMode.Included)
|
||||||
|
_repo.SetBranchFilterMode(LocalBranch, Models.FilterMode.Included, true, false);
|
||||||
|
|
||||||
|
_repo.MarkBranchesDirtyManually();
|
||||||
|
_repo.SetWatcherEnabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
Task.Delay(400).Wait();
|
||||||
|
return succ;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Repository _repo;
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,7 @@ namespace SourceGit.ViewModels
|
||||||
public override Task<bool> Sure()
|
public override Task<bool> Sure()
|
||||||
{
|
{
|
||||||
_repo.SetWatcherEnabled(false);
|
_repo.SetWatcherEnabled(false);
|
||||||
|
_repo.ClearCommitMessage();
|
||||||
ProgressDescription = $"Cherry-Pick commit(s) ...";
|
ProgressDescription = $"Cherry-Pick commit(s) ...";
|
||||||
|
|
||||||
var log = _repo.CreateLog("Cherry-Pick");
|
var log = _repo.CreateLog("Cherry-Pick");
|
||||||
|
|
|
@ -313,7 +313,7 @@ namespace SourceGit.ViewModels
|
||||||
blame.IsEnabled = change.Index != Models.ChangeState.Deleted;
|
blame.IsEnabled = change.Index != Models.ChangeState.Deleted;
|
||||||
blame.Click += (_, ev) =>
|
blame.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
App.ShowWindow(new Blame(_repo.FullPath, change.Path, _commit.SHA), false);
|
App.ShowWindow(new Blame(_repo.FullPath, change.Path, _commit), false);
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -481,7 +481,7 @@ namespace SourceGit.ViewModels
|
||||||
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
|
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
|
||||||
blame.Click += (_, ev) =>
|
blame.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
App.ShowWindow(new Blame(_repo.FullPath, file.Path, _commit.SHA), false);
|
App.ShowWindow(new Blame(_repo.FullPath, file.Path, _commit), false);
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -569,14 +569,14 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
if (!token.IsCancellationRequested)
|
if (!token.IsCancellationRequested)
|
||||||
Dispatcher.UIThread.Invoke(() => FullMessage = new Models.CommitFullMessage { Message = message, Inlines = inlines });
|
Dispatcher.UIThread.Invoke(() => FullMessage = new Models.CommitFullMessage { Message = message, Inlines = inlines });
|
||||||
});
|
}, token);
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var signInfo = new Commands.QueryCommitSignInfo(_repo.FullPath, _commit.SHA, !_repo.HasAllowedSignersFile).Result();
|
var signInfo = new Commands.QueryCommitSignInfo(_repo.FullPath, _commit.SHA, !_repo.HasAllowedSignersFile).Result();
|
||||||
if (!token.IsCancellationRequested)
|
if (!token.IsCancellationRequested)
|
||||||
Dispatcher.UIThread.Invoke(() => SignInfo = signInfo);
|
Dispatcher.UIThread.Invoke(() => SignInfo = signInfo);
|
||||||
});
|
}, token);
|
||||||
|
|
||||||
if (Preferences.Instance.ShowChildren)
|
if (Preferences.Instance.ShowChildren)
|
||||||
{
|
{
|
||||||
|
@ -587,7 +587,7 @@ namespace SourceGit.ViewModels
|
||||||
var children = cmd.Result();
|
var children = cmd.Result();
|
||||||
if (!token.IsCancellationRequested)
|
if (!token.IsCancellationRequested)
|
||||||
Dispatcher.UIThread.Post(() => Children = children);
|
Dispatcher.UIThread.Post(() => Children = children);
|
||||||
});
|
}, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
|
@ -617,7 +617,7 @@ namespace SourceGit.ViewModels
|
||||||
SelectedChanges = null;
|
SelectedChanges = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Models.InlineElementCollector ParseInlinesInMessage(string message)
|
private Models.InlineElementCollector ParseInlinesInMessage(string message)
|
||||||
|
|
|
@ -29,8 +29,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
public ConfigureWorkspace()
|
public ConfigureWorkspace()
|
||||||
{
|
{
|
||||||
Workspaces = new AvaloniaList<Workspace>();
|
Workspaces = new(Preferences.Instance.Workspaces);
|
||||||
Workspaces.AddRange(Preferences.Instance.Workspaces);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add()
|
public void Add()
|
||||||
|
|
|
@ -65,8 +65,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
public static ValidationResult ValidateTagName(string name, ValidationContext ctx)
|
public static ValidationResult ValidateTagName(string name, ValidationContext ctx)
|
||||||
{
|
{
|
||||||
var creator = ctx.ObjectInstance as CreateTag;
|
if (ctx.ObjectInstance is CreateTag creator)
|
||||||
if (creator != null)
|
|
||||||
{
|
{
|
||||||
var found = creator._repo.Tags.Find(x => x.Name == name);
|
var found = creator._repo.Tags.Find(x => x.Name == name);
|
||||||
if (found != null)
|
if (found != null)
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace SourceGit.ViewModels
|
||||||
CallUIThread(() =>
|
CallUIThread(() =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(upstreamHead))
|
if (!string.IsNullOrEmpty(upstreamHead))
|
||||||
_repo.NavigateToCommitDelayed(upstreamHead);
|
_repo.NavigateToCommit(upstreamHead, true);
|
||||||
|
|
||||||
_repo.MarkFetched();
|
_repo.MarkFetched();
|
||||||
_repo.SetWatcherEnabled(true);
|
_repo.SetWatcherEnabled(true);
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace SourceGit.ViewModels
|
||||||
var changedLocalBranchHead = new Commands.QueryRevisionByRefName(_repo.FullPath, Local.Name).Result();
|
var changedLocalBranchHead = new Commands.QueryRevisionByRefName(_repo.FullPath, Local.Name).Result();
|
||||||
CallUIThread(() =>
|
CallUIThread(() =>
|
||||||
{
|
{
|
||||||
_repo.NavigateToCommitDelayed(changedLocalBranchHead);
|
_repo.NavigateToCommit(changedLocalBranchHead, true);
|
||||||
_repo.SetWatcherEnabled(true);
|
_repo.SetWatcherEnabled(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -231,9 +231,22 @@ namespace SourceGit.ViewModels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d.Type == Models.DecoratorType.RemoteBranchHead && firstRemoteBranch == null)
|
else if (d.Type == Models.DecoratorType.RemoteBranchHead)
|
||||||
{
|
{
|
||||||
firstRemoteBranch = _repo.Branches.Find(x => x.FriendlyName == d.Name);
|
var remoteBranch = _repo.Branches.Find(x => x.FriendlyName == d.Name);
|
||||||
|
if (remoteBranch != null)
|
||||||
|
{
|
||||||
|
var localBranch = _repo.Branches.Find(x => x.IsLocal && x.Upstream == remoteBranch.FullName);
|
||||||
|
if (localBranch is { TrackStatus.Ahead.Count: 0 })
|
||||||
|
{
|
||||||
|
if (_repo.CanCreatePopup())
|
||||||
|
_repo.ShowPopup(new CheckoutAndFastForward(_repo, localBranch, remoteBranch));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstRemoteBranch == null)
|
||||||
|
firstRemoteBranch = remoteBranch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +347,7 @@ namespace SourceGit.ViewModels
|
||||||
log = _repo.CreateLog("Save as Patch");
|
log = _repo.CreateLog("Save as Patch");
|
||||||
|
|
||||||
var folder = picker[0];
|
var folder = picker[0];
|
||||||
var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder?.Path.ToString();
|
var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder.Path.ToString();
|
||||||
var succ = false;
|
var succ = false;
|
||||||
for (var i = 0; i < selected.Count; i++)
|
for (var i = 0; i < selected.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -694,7 +707,7 @@ namespace SourceGit.ViewModels
|
||||||
log = _repo.CreateLog("Save as Patch");
|
log = _repo.CreateLog("Save as Patch");
|
||||||
|
|
||||||
var folder = selected[0];
|
var folder = selected[0];
|
||||||
var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder?.Path.ToString();
|
var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder.Path.ToString();
|
||||||
var saveTo = GetPatchFileName(folderPath, commit);
|
var saveTo = GetPatchFileName(folderPath, commit);
|
||||||
var succ = await Task.Run(() => new Commands.FormatPatch(_repo.FullPath, commit.SHA, saveTo).Use(log).Exec());
|
var succ = await Task.Run(() => new Commands.FormatPatch(_repo.FullPath, commit.SHA, saveTo).Use(log).Exec());
|
||||||
if (succ)
|
if (succ)
|
||||||
|
|
|
@ -7,6 +7,7 @@ using Avalonia;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
|
|
||||||
|
using BitMiracle.LibTiff.Classic;
|
||||||
using Pfim;
|
using Pfim;
|
||||||
|
|
||||||
namespace SourceGit.ViewModels
|
namespace SourceGit.ViewModels
|
||||||
|
@ -30,6 +31,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
case ".ico":
|
case ".ico":
|
||||||
case ".bmp":
|
case ".bmp":
|
||||||
|
case ".gif":
|
||||||
case ".jpg":
|
case ".jpg":
|
||||||
case ".jpeg":
|
case ".jpeg":
|
||||||
case ".png":
|
case ".png":
|
||||||
|
@ -38,6 +40,9 @@ namespace SourceGit.ViewModels
|
||||||
case ".tga":
|
case ".tga":
|
||||||
case ".dds":
|
case ".dds":
|
||||||
return Models.ImageDecoder.Pfim;
|
return Models.ImageDecoder.Pfim;
|
||||||
|
case ".tif":
|
||||||
|
case ".tiff":
|
||||||
|
return Models.ImageDecoder.Tiff;
|
||||||
default:
|
default:
|
||||||
return Models.ImageDecoder.None;
|
return Models.ImageDecoder.None;
|
||||||
}
|
}
|
||||||
|
@ -69,31 +74,34 @@ namespace SourceGit.ViewModels
|
||||||
var size = stream.Length;
|
var size = stream.Length;
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
if (decoder == Models.ImageDecoder.Builtin)
|
try
|
||||||
|
{
|
||||||
|
switch (decoder)
|
||||||
|
{
|
||||||
|
case Models.ImageDecoder.Builtin:
|
||||||
return DecodeWithAvalonia(stream, size);
|
return DecodeWithAvalonia(stream, size);
|
||||||
else if (decoder == Models.ImageDecoder.Pfim)
|
case Models.ImageDecoder.Pfim:
|
||||||
return DecodeWithPfim(stream, size);
|
return DecodeWithPfim(stream, size);
|
||||||
|
case Models.ImageDecoder.Tiff:
|
||||||
|
return DecodeWithTiff(stream, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.Out.WriteLine(e.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ImageSource(null, 0);
|
return new ImageSource(null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ImageSource DecodeWithAvalonia(Stream stream, long size)
|
private static ImageSource DecodeWithAvalonia(Stream stream, long size)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var bitmap = new Bitmap(stream);
|
var bitmap = new Bitmap(stream);
|
||||||
return new ImageSource(bitmap, size);
|
return new ImageSource(bitmap, size);
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
|
||||||
return new ImageSource(null, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ImageSource DecodeWithPfim(Stream stream, long size)
|
private static ImageSource DecodeWithPfim(Stream stream, long size)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
using (var pfiImage = Pfimage.FromStream(stream))
|
using (var pfiImage = Pfimage.FromStream(stream))
|
||||||
{
|
{
|
||||||
|
@ -146,9 +154,26 @@ namespace SourceGit.ViewModels
|
||||||
return new ImageSource(bitmap, size);
|
return new ImageSource(bitmap, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
|
private static ImageSource DecodeWithTiff(Stream stream, long size)
|
||||||
{
|
{
|
||||||
|
using (var tiff = Tiff.ClientOpen($"{Guid.NewGuid()}.tif", "r", stream, new TiffStream()))
|
||||||
|
{
|
||||||
|
if (tiff == null)
|
||||||
return new ImageSource(null, 0);
|
return new ImageSource(null, 0);
|
||||||
|
|
||||||
|
var width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
|
||||||
|
var height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
|
||||||
|
var pixels = new int[width * height];
|
||||||
|
|
||||||
|
// Currently only supports image when its `BITSPERSAMPLE` is one in [1,2,4,8,16]
|
||||||
|
tiff.ReadRGBAImageOriented(width, height, pixels, Orientation.TOPLEFT);
|
||||||
|
|
||||||
|
var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(pixels, 0);
|
||||||
|
var pixelSize = new PixelSize(width, height);
|
||||||
|
var dpi = new Vector(96, 96);
|
||||||
|
var bitmap = new Bitmap(PixelFormats.Rgba8888, AlphaFormat.Premul, ptr, pixelSize, dpi, width * 4);
|
||||||
|
return new ImageSource(bitmap, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
public abstract class InProgressContext
|
public abstract class InProgressContext
|
||||||
{
|
{
|
||||||
public InProgressContext(string repo, string cmd)
|
protected InProgressContext(string repo, string cmd)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_cmd = cmd;
|
_cmd = cmd;
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace SourceGit.ViewModels
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (SetProperty(ref _selectedItem, value))
|
if (SetProperty(ref _selectedItem, value))
|
||||||
DetailContext.Commit = value != null ? value.Commit : null;
|
DetailContext.Commit = value?.Commit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -296,17 +296,10 @@ namespace SourceGit.ViewModels
|
||||||
var removeIdx = Pages.IndexOf(page);
|
var removeIdx = Pages.IndexOf(page);
|
||||||
var activeIdx = Pages.IndexOf(_activePage);
|
var activeIdx = Pages.IndexOf(_activePage);
|
||||||
if (removeIdx == activeIdx)
|
if (removeIdx == activeIdx)
|
||||||
{
|
|
||||||
ActivePage = Pages[removeIdx > 0 ? removeIdx - 1 : removeIdx + 1];
|
ActivePage = Pages[removeIdx > 0 ? removeIdx - 1 : removeIdx + 1];
|
||||||
CloseRepositoryInTab(page);
|
|
||||||
Pages.RemoveAt(removeIdx);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CloseRepositoryInTab(page);
|
|
||||||
Pages.RemoveAt(removeIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
CloseRepositoryInTab(page);
|
||||||
|
Pages.RemoveAt(removeIdx);
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace SourceGit.ViewModels
|
||||||
public override Task<bool> Sure()
|
public override Task<bool> Sure()
|
||||||
{
|
{
|
||||||
_repo.SetWatcherEnabled(false);
|
_repo.SetWatcherEnabled(false);
|
||||||
|
_repo.ClearCommitMessage();
|
||||||
ProgressDescription = $"Merging '{_sourceName}' into '{Into}' ...";
|
ProgressDescription = $"Merging '{_sourceName}' into '{Into}' ...";
|
||||||
|
|
||||||
var log = _repo.CreateLog($"Merging '{_sourceName}' into '{Into}'");
|
var log = _repo.CreateLog($"Merging '{_sourceName}' into '{Into}'");
|
||||||
|
@ -67,7 +68,7 @@ namespace SourceGit.ViewModels
|
||||||
var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result();
|
var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result();
|
||||||
CallUIThread(() =>
|
CallUIThread(() =>
|
||||||
{
|
{
|
||||||
_repo.NavigateToCommitDelayed(head);
|
_repo.NavigateToCommit(head, true);
|
||||||
_repo.SetWatcherEnabled(true);
|
_repo.SetWatcherEnabled(true);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace SourceGit.ViewModels
|
||||||
public override Task<bool> Sure()
|
public override Task<bool> Sure()
|
||||||
{
|
{
|
||||||
_repo.SetWatcherEnabled(false);
|
_repo.SetWatcherEnabled(false);
|
||||||
|
_repo.ClearCommitMessage();
|
||||||
ProgressDescription = "Merge head(s) ...";
|
ProgressDescription = "Merge head(s) ...";
|
||||||
|
|
||||||
var log = _repo.CreateLog("Merge Multiple Heads");
|
var log = _repo.CreateLog("Merge Multiple Heads");
|
||||||
|
@ -48,7 +49,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
return Task.Run(() =>
|
return Task.Run(() =>
|
||||||
{
|
{
|
||||||
var succ = new Commands.Merge(
|
new Commands.Merge(
|
||||||
_repo.FullPath,
|
_repo.FullPath,
|
||||||
ConvertTargetToMergeSources(),
|
ConvertTargetToMergeSources(),
|
||||||
AutoCommit,
|
AutoCommit,
|
||||||
|
@ -56,7 +57,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
log.Complete();
|
log.Complete();
|
||||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||||
return succ;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,12 +72,10 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
else if (t is Models.Commit commit)
|
else if (t is Models.Commit commit)
|
||||||
{
|
{
|
||||||
var d = commit.Decorators.Find(x =>
|
var d = commit.Decorators.Find(x => x.Type is
|
||||||
{
|
Models.DecoratorType.LocalBranchHead or
|
||||||
return x.Type == Models.DecoratorType.LocalBranchHead ||
|
Models.DecoratorType.RemoteBranchHead or
|
||||||
x.Type == Models.DecoratorType.RemoteBranchHead ||
|
Models.DecoratorType.Tag);
|
||||||
x.Type == Models.DecoratorType.Tag;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (d != null)
|
if (d != null)
|
||||||
ret.Add(d.Name);
|
ret.Add(d.Name);
|
||||||
|
|
|
@ -449,7 +449,7 @@ namespace SourceGit.ViewModels
|
||||||
if (l.IsRepository != r.IsRepository)
|
if (l.IsRepository != r.IsRepository)
|
||||||
return l.IsRepository ? 1 : -1;
|
return l.IsRepository ? 1 : -1;
|
||||||
|
|
||||||
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
|
return Models.NumericSort.Compare(l.Name, r.Name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ namespace SourceGit.ViewModels
|
||||||
var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result();
|
var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result();
|
||||||
CallUIThread(() =>
|
CallUIThread(() =>
|
||||||
{
|
{
|
||||||
_repo.NavigateToCommitDelayed(head);
|
_repo.NavigateToCommit(head, true);
|
||||||
_repo.SetWatcherEnabled(true);
|
_repo.SetWatcherEnabled(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace SourceGit.ViewModels
|
||||||
public override Task<bool> Sure()
|
public override Task<bool> Sure()
|
||||||
{
|
{
|
||||||
_repo.SetWatcherEnabled(false);
|
_repo.SetWatcherEnabled(false);
|
||||||
|
_repo.ClearCommitMessage();
|
||||||
ProgressDescription = "Rebasing ...";
|
ProgressDescription = "Rebasing ...";
|
||||||
|
|
||||||
var log = _repo.CreateLog("Rebase");
|
var log = _repo.CreateLog("Rebase");
|
||||||
|
|
|
@ -736,11 +736,8 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||||
|
|
||||||
foreach (var url in urls)
|
foreach (var (name, addr) in urls)
|
||||||
{
|
{
|
||||||
var name = url.Key;
|
|
||||||
var addr = url.Value;
|
|
||||||
|
|
||||||
var item = new MenuItem();
|
var item = new MenuItem();
|
||||||
item.Header = App.Text("Repository.Visit", name);
|
item.Header = App.Text("Repository.Visit", name);
|
||||||
item.Icon = App.CreateMenuIcon("Icons.Remotes");
|
item.Icon = App.CreateMenuIcon("Icons.Remotes");
|
||||||
|
@ -928,24 +925,23 @@ namespace SourceGit.ViewModels
|
||||||
_lastFetchTime = DateTime.Now;
|
_lastFetchTime = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NavigateToCommit(string sha)
|
public void NavigateToCommit(string sha, bool isDelayMode = false)
|
||||||
{
|
{
|
||||||
if (_histories != null)
|
if (isDelayMode)
|
||||||
|
{
|
||||||
|
_navigateToCommitDelayed = sha;
|
||||||
|
}
|
||||||
|
else if (_histories != null)
|
||||||
{
|
{
|
||||||
SelectedViewIndex = 0;
|
SelectedViewIndex = 0;
|
||||||
_histories.NavigateTo(sha);
|
_histories.NavigateTo(sha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NavigateToCommitDelayed(string sha)
|
public void ClearCommitMessage()
|
||||||
{
|
{
|
||||||
_navigateToCommitDelayed = sha;
|
if (_workingCopy is not null)
|
||||||
}
|
_workingCopy.CommitMessage = string.Empty;
|
||||||
|
|
||||||
public void NavigateToCurrentHead()
|
|
||||||
{
|
|
||||||
if (_currentBranch != null)
|
|
||||||
NavigateToCommit(_currentBranch.Head);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearHistoriesFilter()
|
public void ClearHistoriesFilter()
|
||||||
|
@ -1275,6 +1271,7 @@ namespace SourceGit.ViewModels
|
||||||
if (_workingCopy == null)
|
if (_workingCopy == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
|
||||||
_workingCopy.SetData(changes);
|
_workingCopy.SetData(changes);
|
||||||
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
@ -1316,7 +1313,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
if (branch.IsLocal)
|
if (branch.IsLocal)
|
||||||
{
|
{
|
||||||
var worktree = _worktrees.Find(x => x.Branch == branch.FullName);
|
var worktree = _worktrees.Find(x => x.Branch.Equals(branch.FullName, StringComparison.Ordinal));
|
||||||
if (worktree != null)
|
if (worktree != null)
|
||||||
{
|
{
|
||||||
OpenWorktree(worktree);
|
OpenWorktree(worktree);
|
||||||
|
@ -1341,9 +1338,13 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
foreach (var b in _branches)
|
foreach (var b in _branches)
|
||||||
{
|
{
|
||||||
if (b.IsLocal && b.Upstream == branch.FullName)
|
if (b.IsLocal &&
|
||||||
|
b.Upstream.Equals(branch.FullName, StringComparison.Ordinal) &&
|
||||||
|
b.TrackStatus.Ahead.Count == 0)
|
||||||
{
|
{
|
||||||
if (!b.IsCurrent)
|
if (b.TrackStatus.Behind.Count > 0)
|
||||||
|
ShowPopup(new CheckoutAndFastForward(this, b, branch));
|
||||||
|
else if (!b.IsCurrent)
|
||||||
CheckoutBranch(b);
|
CheckoutBranch(b);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -1354,6 +1355,12 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteBranch(Models.Branch branch)
|
||||||
|
{
|
||||||
|
if (CanCreatePopup())
|
||||||
|
ShowPopup(new DeleteBranch(this, branch));
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteMultipleBranches(List<Models.Branch> branches, bool isLocal)
|
public void DeleteMultipleBranches(List<Models.Branch> branches, bool isLocal)
|
||||||
{
|
{
|
||||||
if (CanCreatePopup())
|
if (CanCreatePopup())
|
||||||
|
@ -1378,12 +1385,24 @@ namespace SourceGit.ViewModels
|
||||||
ShowPopup(new CreateTag(this, _currentBranch));
|
ShowPopup(new CreateTag(this, _currentBranch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteTag(Models.Tag tag)
|
||||||
|
{
|
||||||
|
if (CanCreatePopup())
|
||||||
|
ShowPopup(new DeleteTag(this, tag));
|
||||||
|
}
|
||||||
|
|
||||||
public void AddRemote()
|
public void AddRemote()
|
||||||
{
|
{
|
||||||
if (CanCreatePopup())
|
if (CanCreatePopup())
|
||||||
ShowPopup(new AddRemote(this));
|
ShowPopup(new AddRemote(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteRemote(Models.Remote remote)
|
||||||
|
{
|
||||||
|
if (CanCreatePopup())
|
||||||
|
ShowPopup(new DeleteRemote(this, remote));
|
||||||
|
}
|
||||||
|
|
||||||
public void AddSubmodule()
|
public void AddSubmodule()
|
||||||
{
|
{
|
||||||
if (CanCreatePopup())
|
if (CanCreatePopup())
|
||||||
|
@ -2445,7 +2464,7 @@ namespace SourceGit.ViewModels
|
||||||
public ContextMenu CreateContextMenuForTagSortMode()
|
public ContextMenu CreateContextMenuForTagSortMode()
|
||||||
{
|
{
|
||||||
var mode = _settings.TagSortMode;
|
var mode = _settings.TagSortMode;
|
||||||
var changeMode = new Action<Models.TagSortMode>((m) =>
|
var changeMode = new Action<Models.TagSortMode>(m =>
|
||||||
{
|
{
|
||||||
if (_settings.TagSortMode != m)
|
if (_settings.TagSortMode != m)
|
||||||
{
|
{
|
||||||
|
@ -2723,10 +2742,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
if (filters.TryGetValue(node.Path, out var value))
|
node.FilterMode = filters.GetValueOrDefault(node.Path, Models.FilterMode.None);
|
||||||
node.FilterMode = value;
|
|
||||||
else
|
|
||||||
node.FilterMode = Models.FilterMode.None;
|
|
||||||
|
|
||||||
if (!node.IsBranch)
|
if (!node.IsBranch)
|
||||||
UpdateBranchTreeFilterMode(node.Children, filters);
|
UpdateBranchTreeFilterMode(node.Children, filters);
|
||||||
|
@ -2737,10 +2753,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
foreach (var tag in _tags)
|
foreach (var tag in _tags)
|
||||||
{
|
{
|
||||||
if (filters.TryGetValue(tag.Name, out var value))
|
tag.FilterMode = filters.GetValueOrDefault(tag.Name, Models.FilterMode.None);
|
||||||
tag.FilterMode = value;
|
|
||||||
else
|
|
||||||
tag.FilterMode = Models.FilterMode.None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2929,7 +2942,7 @@ namespace SourceGit.ViewModels
|
||||||
private List<string> _matchedFilesForSearching = null;
|
private List<string> _matchedFilesForSearching = null;
|
||||||
|
|
||||||
private string _filter = string.Empty;
|
private string _filter = string.Empty;
|
||||||
private object _lockRemotes = new object();
|
private readonly Lock _lockRemotes = new();
|
||||||
private List<Models.Remote> _remotes = new List<Models.Remote>();
|
private List<Models.Remote> _remotes = new List<Models.Remote>();
|
||||||
private List<Models.Branch> _branches = new List<Models.Branch>();
|
private List<Models.Branch> _branches = new List<Models.Branch>();
|
||||||
private Models.Branch _currentBranch = null;
|
private Models.Branch _currentBranch = null;
|
||||||
|
|
|
@ -156,7 +156,7 @@ namespace SourceGit.ViewModels
|
||||||
foreach (var service in Preferences.Instance.OpenAIServices)
|
foreach (var service in Preferences.Instance.OpenAIServices)
|
||||||
AvailableOpenAIServices.Add(service.Name);
|
AvailableOpenAIServices.Add(service.Name);
|
||||||
|
|
||||||
if (AvailableOpenAIServices.IndexOf(PreferredOpenAIService) == -1)
|
if (!AvailableOpenAIServices.Contains(PreferredOpenAIService))
|
||||||
PreferredOpenAIService = "---";
|
PreferredOpenAIService = "---";
|
||||||
|
|
||||||
_cached = new Commands.Config(repo.FullPath).ListAll();
|
_cached = new Commands.Config(repo.FullPath).ListAll();
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace SourceGit.ViewModels
|
||||||
public override Task<bool> Sure()
|
public override Task<bool> Sure()
|
||||||
{
|
{
|
||||||
_repo.SetWatcherEnabled(false);
|
_repo.SetWatcherEnabled(false);
|
||||||
|
_repo.ClearCommitMessage();
|
||||||
ProgressDescription = $"Revert commit '{Target.SHA}' ...";
|
ProgressDescription = $"Revert commit '{Target.SHA}' ...";
|
||||||
|
|
||||||
var log = _repo.CreateLog($"Revert '{Target.SHA}'");
|
var log = _repo.CreateLog($"Revert '{Target.SHA}'");
|
||||||
|
|
|
@ -64,7 +64,6 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
|
|
||||||
Preferences.Instance.AutoRemoveInvalidNode();
|
Preferences.Instance.AutoRemoveInvalidNode();
|
||||||
Preferences.Instance.SortNodes(Preferences.Instance.RepositoryNodes);
|
|
||||||
Preferences.Instance.Save();
|
Preferences.Instance.Save();
|
||||||
|
|
||||||
Welcome.Instance.Refresh();
|
Welcome.Instance.Refresh();
|
||||||
|
@ -128,14 +127,14 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
private RepositoryNode FindOrCreateGroupRecursive(List<RepositoryNode> collection, string path)
|
private RepositoryNode FindOrCreateGroupRecursive(List<RepositoryNode> collection, string path)
|
||||||
{
|
{
|
||||||
var idx = path.IndexOf('/');
|
RepositoryNode node = null;
|
||||||
if (idx < 0)
|
foreach (var name in path.Split('/'))
|
||||||
return FindOrCreateGroup(collection, path);
|
{
|
||||||
|
node = FindOrCreateGroup(collection, name);
|
||||||
|
collection = node.SubNodes;
|
||||||
|
}
|
||||||
|
|
||||||
var name = path.Substring(0, idx);
|
return node;
|
||||||
var tail = path.Substring(idx + 1);
|
|
||||||
var parent = FindOrCreateGroup(collection, name);
|
|
||||||
return FindOrCreateGroupRecursive(parent.SubNodes, tail);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private RepositoryNode FindOrCreateGroup(List<RepositoryNode> collection, string name)
|
private RepositoryNode FindOrCreateGroup(List<RepositoryNode> collection, string name)
|
||||||
|
@ -154,8 +153,8 @@ namespace SourceGit.ViewModels
|
||||||
IsExpanded = true,
|
IsExpanded = true,
|
||||||
};
|
};
|
||||||
collection.Add(added);
|
collection.Add(added);
|
||||||
Preferences.Instance.SortNodes(collection);
|
|
||||||
|
|
||||||
|
Preferences.Instance.SortNodes(collection);
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace SourceGit.ViewModels
|
||||||
changes.Add(c);
|
changes.Add(c);
|
||||||
|
|
||||||
if (needSort)
|
if (needSort)
|
||||||
changes.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal));
|
changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
@ -295,6 +295,12 @@ namespace SourceGit.ViewModels
|
||||||
SearchFilter = string.Empty;
|
SearchFilter = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Drop(Models.Stash stash)
|
||||||
|
{
|
||||||
|
if (stash != null && _repo.CanCreatePopup())
|
||||||
|
_repo.ShowPopup(new DropStash(_repo, stash));
|
||||||
|
}
|
||||||
|
|
||||||
private void RefreshVisible()
|
private void RefreshVisible()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_searchFilter))
|
if (string.IsNullOrEmpty(_searchFilter))
|
||||||
|
|
|
@ -1778,16 +1778,11 @@ namespace SourceGit.ViewModels
|
||||||
if (old.Count != cur.Count)
|
if (old.Count != cur.Count)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var oldMap = new Dictionary<string, Models.Change>();
|
for (int idx = 0; idx < old.Count; idx++)
|
||||||
foreach (var c in old)
|
|
||||||
oldMap.Add(c.Path, c);
|
|
||||||
|
|
||||||
foreach (var c in cur)
|
|
||||||
{
|
{
|
||||||
if (!oldMap.TryGetValue(c.Path, out var o))
|
var o = old[idx];
|
||||||
return true;
|
var c = cur[idx];
|
||||||
|
if (o.Path != c.Path || o.Index != c.Index || o.WorkTree != c.WorkTree)
|
||||||
if (o.Index != c.Index || o.WorkTree != c.WorkTree)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,6 @@
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
|
||||||
<TextBlock x:Name="TxtCopyright" Margin="0,40,0,0" Foreground="{DynamicResource Brush.FG2}"/>
|
<TextBlock x:Name="TxtCopyright" Margin="0,40,0,0" Foreground="{DynamicResource Brush.FG2}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -10,4 +10,3 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
<Grid Height="26" ColumnDefinitions="26,*,30">
|
<Grid Height="26" ColumnDefinitions="26,*,30">
|
||||||
<Path Grid.Column="0" Width="14" Height="14" Margin="8,0,0,0" HorizontalAlignment="Center" Data="{StaticResource Icons.File}"/>
|
<Path Grid.Column="0" Width="14" Height="14" Margin="8,0,0,0" HorizontalAlignment="Center" Data="{StaticResource Icons.File}"/>
|
||||||
<Border Grid.Column="1" Margin="4,0" ClipToBounds="True">
|
<Border Grid.Column="1" Margin="4,0" ClipToBounds="True">
|
||||||
<TextBlock Grid.Column="1" Text="{Binding}" HorizontalAlignment="Left"/>
|
<TextBlock Text="{Binding}" HorizontalAlignment="Left"/>
|
||||||
</Border>
|
</Border>
|
||||||
<Button Grid.Column="2" Classes="icon_button" Click="OnRemoveButtonClicked">
|
<Button Grid.Column="2" Classes="icon_button" Click="OnRemoveButtonClicked">
|
||||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Clear}"/>
|
<Path Width="14" Height="14" Data="{StaticResource Icons.Clear}"/>
|
||||||
|
|
|
@ -187,7 +187,7 @@ namespace SourceGit.Views
|
||||||
if (storageFile != null)
|
if (storageFile != null)
|
||||||
{
|
{
|
||||||
var saveTo = storageFile.Path.LocalPath;
|
var saveTo = storageFile.Path.LocalPath;
|
||||||
using (var writer = File.OpenWrite(saveTo))
|
await using (var writer = File.OpenWrite(saveTo))
|
||||||
{
|
{
|
||||||
if (_img != null)
|
if (_img != null)
|
||||||
{
|
{
|
||||||
|
@ -201,7 +201,7 @@ namespace SourceGit.Views
|
||||||
using (var rt = new RenderTargetBitmap(pixelSize, dpi))
|
using (var rt = new RenderTargetBitmap(pixelSize, dpi))
|
||||||
using (var ctx = rt.CreateDrawingContext())
|
using (var ctx = rt.CreateDrawingContext())
|
||||||
{
|
{
|
||||||
this.Render(ctx);
|
Render(ctx);
|
||||||
rt.Save(writer);
|
rt.Save(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:vm="using:SourceGit.ViewModels"
|
xmlns:vm="using:SourceGit.ViewModels"
|
||||||
xmlns:v="using:SourceGit.Views"
|
xmlns:v="using:SourceGit.Views"
|
||||||
|
xmlns:c="using:SourceGit.Converters"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="SourceGit.Views.Blame"
|
x:Class="SourceGit.Views.Blame"
|
||||||
x:DataType="vm:Blame"
|
x:DataType="vm:Blame"
|
||||||
|
@ -42,8 +43,46 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- File -->
|
<!-- File -->
|
||||||
<Border Grid.Row="1" Padding="8,0">
|
<Border Grid.Row="1" Padding="8,0" >
|
||||||
<TextBlock Text="{Binding Title}" VerticalAlignment="Center"/>
|
<Grid ColumnDefinitions="Auto,*,Auto,Auto,400">
|
||||||
|
<Path Grid.Column="0"
|
||||||
|
Width="14" Height="14"
|
||||||
|
Data="{StaticResource Icons.File}"/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Margin="4,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{Binding FilePath, Mode=OneWay}"/>
|
||||||
|
|
||||||
|
<Button Grid.Column="2"
|
||||||
|
Classes="icon_button"
|
||||||
|
IsEnabled="{Binding CanBack}"
|
||||||
|
Width="28"
|
||||||
|
Command="{Binding Back}">
|
||||||
|
<Path Width="12" Height="12" Data="{StaticResource Icons.TriangleLeft}"/>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button Grid.Column="3"
|
||||||
|
Classes="icon_button"
|
||||||
|
IsEnabled="{Binding CanForward}"
|
||||||
|
Width="28"
|
||||||
|
Command="{Binding Forward}">
|
||||||
|
<Path Width="12" Height="12" Data="{StaticResource Icons.TriangleRight}"/>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Border Grid.Column="4" Background="#40000000" CornerRadius="3" Padding="4,0" Margin="0,2">
|
||||||
|
<Grid ColumnDefinitions="Auto,*">
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Margin="0,0,6,0"
|
||||||
|
Text="{Binding Revision.SHA, Converter={x:Static c:StringConverters.ToShortSHA}, Mode=OneWay}"/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="{Binding Revision.Subject}"
|
||||||
|
TextTrimming="CharacterEllipsis"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- Body -->
|
<!-- Body -->
|
||||||
|
|
|
@ -102,9 +102,8 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
var info = _editor.BlameData.LineInfos[lineNumber - 1];
|
var info = _editor.BlameData.LineInfos[lineNumber - 1];
|
||||||
|
|
||||||
if (calculated.Contains(info.CommitSHA))
|
if (!calculated.Add(info.CommitSHA))
|
||||||
continue;
|
continue;
|
||||||
calculated.Add(info.CommitSHA);
|
|
||||||
|
|
||||||
var x = 0.0;
|
var x = 0.0;
|
||||||
var shaLink = new FormattedText(
|
var shaLink = new FormattedText(
|
||||||
|
@ -224,9 +223,7 @@ namespace SourceGit.Views
|
||||||
if (rect.Contains(pos))
|
if (rect.Contains(pos))
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.Blame blame)
|
if (DataContext is ViewModels.Blame blame)
|
||||||
{
|
|
||||||
blame.NavigateToCommit(info.CommitSHA);
|
blame.NavigateToCommit(info.CommitSHA);
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
break;
|
break;
|
||||||
|
@ -440,5 +437,24 @@ namespace SourceGit.Views
|
||||||
base.OnClosed(e);
|
base.OnClosed(e);
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPointerReleased(e);
|
||||||
|
|
||||||
|
if (!e.Handled && DataContext is ViewModels.Blame blame)
|
||||||
|
{
|
||||||
|
if (e.InitialPressMouseButton == MouseButton.XButton1)
|
||||||
|
{
|
||||||
|
blame.Back();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
else if (e.InitialPressMouseButton == MouseButton.XButton2)
|
||||||
|
{
|
||||||
|
blame.Forward();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
ItemsSource="{Binding #ThisControl.Rows}"
|
ItemsSource="{Binding #ThisControl.Rows}"
|
||||||
SelectionMode="Multiple"
|
SelectionMode="Multiple"
|
||||||
SelectionChanged="OnNodesSelectionChanged"
|
SelectionChanged="OnNodesSelectionChanged"
|
||||||
|
KeyDown="OnTreeKeyDown"
|
||||||
ContextRequested="OnTreeContextRequested">
|
ContextRequested="OnTreeContextRequested">
|
||||||
<ListBox.ItemsPanel>
|
<ListBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
|
@ -95,4 +96,3 @@
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
||||||
|
|
|
@ -450,6 +450,44 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnTreeKeyDown(object _, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key is not (Key.Delete or Key.Back))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var repo = DataContext as ViewModels.Repository;
|
||||||
|
if (repo?.Settings == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var selected = BranchesPresenter.SelectedItems;
|
||||||
|
if (selected == null || selected.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (selected.Count == 1 && selected[0] is ViewModels.BranchTreeNode { Backend: Models.Remote remote })
|
||||||
|
{
|
||||||
|
repo.DeleteRemote(remote);
|
||||||
|
e.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var branches = new List<Models.Branch>();
|
||||||
|
foreach (var item in selected)
|
||||||
|
{
|
||||||
|
if (item is ViewModels.BranchTreeNode node)
|
||||||
|
CollectBranchesInNode(branches, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branches.Find(x => x.IsCurrent) != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (branches.Count == 1)
|
||||||
|
repo.DeleteBranch(branches[0]);
|
||||||
|
else
|
||||||
|
repo.DeleteMultipleBranches(branches, branches[0].IsLocal);
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDoubleTappedBranchNode(object sender, TappedEventArgs _)
|
private void OnDoubleTappedBranchNode(object sender, TappedEventArgs _)
|
||||||
{
|
{
|
||||||
if (sender is Grid { DataContext: ViewModels.BranchTreeNode node })
|
if (sender is Grid { DataContext: ViewModels.BranchTreeNode node })
|
||||||
|
@ -499,4 +537,3 @@ namespace SourceGit.Views
|
||||||
private bool _disableSelectionChangingEvent = false;
|
private bool _disableSelectionChangingEvent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
74
src/Views/CheckoutAndFastForward.axaml
Normal file
74
src/Views/CheckoutAndFastForward.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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="SourceGit.Views.CheckoutAndFastForward"
|
||||||
|
x:DataType="vm:CheckoutAndFastForward">
|
||||||
|
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||||
|
<TextBlock FontSize="18"
|
||||||
|
Classes="bold"
|
||||||
|
Text="{DynamicResource Text.Checkout.WithFastForward}"/>
|
||||||
|
|
||||||
|
<Grid Margin="0,16,0,0" ColumnDefinitions="140,*">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="32"/>
|
||||||
|
<RowDefinition Height="32"/>
|
||||||
|
<RowDefinition Height="Auto" MinHeight="32"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||||
|
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
Text="{DynamicResource Text.Checkout.Target}"/>
|
||||||
|
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
|
||||||
|
<Path Width="14" Height="14" Margin="4,0" Data="{StaticResource Icons.Branch}"/>
|
||||||
|
<TextBlock Text="{Binding LocalBranch.Name}"/>
|
||||||
|
<Border Height="18"
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
Padding="8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
CornerRadius="9"
|
||||||
|
Background="{DynamicResource Brush.Badge}"
|
||||||
|
IsVisible="{Binding LocalBranch.TrackStatus.IsVisible}">
|
||||||
|
<TextBlock Foreground="{DynamicResource Brush.BadgeFG}"
|
||||||
|
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||||
|
FontSize="10"
|
||||||
|
Text="{Binding LocalBranch.TrackStatus}"/>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||||
|
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
Text="{DynamicResource Text.Checkout.WithFastForward.Upstream}"/>
|
||||||
|
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
|
||||||
|
<Path Width="14" Height="14" Margin="4,0" Data="{StaticResource Icons.Branch}"/>
|
||||||
|
<TextBlock Text="{Binding RemoteBranch.FriendlyName}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||||
|
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
Text="{DynamicResource Text.Checkout.LocalChanges}"/>
|
||||||
|
<WrapPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<RadioButton GroupName="LocalChanges"
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
Content="{DynamicResource Text.Checkout.LocalChanges.StashAndReply}"
|
||||||
|
IsChecked="{Binding !DiscardLocalChanges, Mode=TwoWay}"/>
|
||||||
|
<RadioButton GroupName="LocalChanges"
|
||||||
|
Content="{DynamicResource Text.Checkout.LocalChanges.Discard}"/>
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
|
<CheckBox Grid.Row="3" Grid.Column="1"
|
||||||
|
Height="32"
|
||||||
|
Content="{DynamicResource Text.Checkout.RecurseSubmodules}"
|
||||||
|
IsChecked="{Binding RecurseSubmodules, Mode=TwoWay}"
|
||||||
|
IsVisible="{Binding IsRecurseSubmoduleVisible}"
|
||||||
|
ToolTip.Tip="--recurse-submodules"/>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
12
src/Views/CheckoutAndFastForward.axaml.cs
Normal file
12
src/Views/CheckoutAndFastForward.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace SourceGit.Views
|
||||||
|
{
|
||||||
|
public partial class CheckoutAndFastForward : UserControl
|
||||||
|
{
|
||||||
|
public CheckoutAndFastForward()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,8 +76,7 @@
|
||||||
<Border Grid.Column="1"
|
<Border Grid.Column="1"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
ToolTip.Tip="{DynamicResource Text.CherryPick.Mainline.Tips}">
|
ToolTip.Tip="{DynamicResource Text.CherryPick.Mainline.Tips}">
|
||||||
<Path Grid.Column="1"
|
<Path Width="14" Height="14"
|
||||||
Width="14" Height="14"
|
|
||||||
Data="{StaticResource Icons.Info}"/>
|
Data="{StaticResource Icons.Info}"/>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values are copied from Avalonia: src/Avalonia.Controls.ColorPicker/ColorPalettes/FluentColorPalette.cs
|
// Values are copied from Avalonia: src/Avalonia.Controls.ColorPicker/ColorPalettes/FluentColorPalette.cs
|
||||||
private static readonly Color[,] COLOR_TABLE = new Color[,]
|
private static readonly Color[,] COLOR_TABLE = new[,]
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Color.FromArgb(255, 255, 67, 67), /* #FF4343 */
|
Color.FromArgb(255, 255, 67, 67), /* #FF4343 */
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
private void StopTimer()
|
private void StopTimer()
|
||||||
{
|
{
|
||||||
if (_refreshTimer is { })
|
if (_refreshTimer is not null)
|
||||||
{
|
{
|
||||||
_refreshTimer.Dispose();
|
_refreshTimer.Dispose();
|
||||||
_refreshTimer = null;
|
_refreshTimer = null;
|
||||||
|
|
|
@ -51,6 +51,14 @@
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate DataType="m:Change">
|
<DataTemplate DataType="m:Change">
|
||||||
<Grid Background="Transparent" Height="24" ColumnDefinitions="36,*" ContextRequested="OnChangeContextRequested" DoubleTapped="OnChangeDoubleTapped">
|
<Grid Background="Transparent" Height="24" ColumnDefinitions="36,*" ContextRequested="OnChangeContextRequested" DoubleTapped="OnChangeDoubleTapped">
|
||||||
|
<ToolTip.Tip>
|
||||||
|
<TextBlock TextWrapping="Wrap">
|
||||||
|
<Run Text="{Binding Path, Mode=OneWay}"/>
|
||||||
|
<Run Text=" • " Foreground="Gray"/>
|
||||||
|
<Run Text="{Binding IndexDesc, Mode=OneWay}" Foreground="Gray"/>
|
||||||
|
</TextBlock>
|
||||||
|
</ToolTip.Tip>
|
||||||
|
|
||||||
<v:ChangeStatusIcon Grid.Column="0"
|
<v:ChangeStatusIcon Grid.Column="0"
|
||||||
Width="14" Height="14"
|
Width="14" Height="14"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
|
|
@ -264,8 +264,7 @@ namespace SourceGit.Views
|
||||||
if (currentParent is { DataContext: ViewModels.CommitDetail currentDetail } &&
|
if (currentParent is { DataContext: ViewModels.CommitDetail currentDetail } &&
|
||||||
currentDetail.Commit.SHA == lastDetailCommit)
|
currentDetail.Commit.SHA == lastDetailCommit)
|
||||||
{
|
{
|
||||||
if (!_inlineCommits.ContainsKey(sha))
|
_inlineCommits.TryAdd(sha, c);
|
||||||
_inlineCommits.Add(sha, c);
|
|
||||||
|
|
||||||
// Make sure user still hovers the target SHA.
|
// Make sure user still hovers the target SHA.
|
||||||
if (_lastHover == link && c != null)
|
if (_lastHover == link && c != null)
|
||||||
|
|
|
@ -120,4 +120,3 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace SourceGit.Views
|
||||||
set => SetValue(BehindBrushProperty, value);
|
set => SetValue(BehindBrushProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Status
|
private enum Status
|
||||||
{
|
{
|
||||||
Normal,
|
Normal,
|
||||||
Ahead,
|
Ahead,
|
||||||
|
|
|
@ -10,4 +10,3 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -261,7 +261,11 @@
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel Orientation="Vertical" Margin="8,0">
|
<StackPanel Orientation="Vertical" Margin="8,0">
|
||||||
<Border IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}">
|
<Border Height="16" HorizontalAlignment="Center" Background="Red" CornerRadius="8" IsVisible="{Binding New, Converter={x:Static ObjectConverters.IsNull}}">
|
||||||
|
<TextBlock Classes="primary" Text="{DynamicResource Text.Diff.Submodule.Deleted}" Margin="8,0" FontSize="10" Foreground="White"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Margin="0,8,0,0" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<ContentControl Content="{Binding Old}">
|
<ContentControl Content="{Binding Old}">
|
||||||
<ContentControl.DataTemplates>
|
<ContentControl.DataTemplates>
|
||||||
<DataTemplate DataType="m:RevisionSubmodule">
|
<DataTemplate DataType="m:RevisionSubmodule">
|
||||||
|
@ -273,12 +277,19 @@
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<Path Width="16" Height="16" Data="{StaticResource Icons.DoubleDown}" HorizontalAlignment="Center">
|
||||||
|
<Path.IsVisible>
|
||||||
|
<MultiBinding Converter="{x:Static BoolConverters.And}">
|
||||||
|
<Binding Path="Old" Converter="{x:Static ObjectConverters.IsNotNull}"/>
|
||||||
|
<Binding Path="New" Converter="{x:Static ObjectConverters.IsNotNull}"/>
|
||||||
|
</MultiBinding>
|
||||||
|
</Path.IsVisible>
|
||||||
|
</Path>
|
||||||
|
|
||||||
<Border Height="16" HorizontalAlignment="Center" Background="Green" CornerRadius="8" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNull}}">
|
<Border Height="16" HorizontalAlignment="Center" Background="Green" CornerRadius="8" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNull}}">
|
||||||
<TextBlock Classes="primary" Text="{DynamicResource Text.Diff.Submodule.New}" Margin="8,0" FontSize="10" Foreground="White"/>
|
<TextBlock Classes="primary" Text="{DynamicResource Text.Diff.Submodule.New}" Margin="8,0" FontSize="10" Foreground="White"/>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Path Width="16" Height="16" Data="{StaticResource Icons.DoubleDown}" HorizontalAlignment="Center" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
|
||||||
|
|
||||||
<Border Margin="0,8,0,0" BorderThickness="1" BorderBrush="Green" Background="{DynamicResource Brush.Window}" IsVisible="{Binding New, Converter={x:Static ObjectConverters.IsNotNull}}">
|
<Border Margin="0,8,0,0" BorderThickness="1" BorderBrush="Green" Background="{DynamicResource Brush.Window}" IsVisible="{Binding New, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<ContentControl Content="{Binding New}">
|
<ContentControl Content="{Binding New}">
|
||||||
<ContentControl.DataTemplates>
|
<ContentControl.DataTemplates>
|
||||||
|
@ -288,10 +299,6 @@
|
||||||
</ContentControl.DataTemplates>
|
</ContentControl.DataTemplates>
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Margin="0,8,0,0" Height="16" HorizontalAlignment="Center" Background="Red" CornerRadius="8" IsVisible="{Binding New, Converter={x:Static ObjectConverters.IsNull}}">
|
|
||||||
<TextBlock Classes="primary" Text="{DynamicResource Text.Diff.Submodule.Deleted}" Margin="8,0" FontSize="10" Foreground="White"/>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace SourceGit.Views
|
||||||
options.DefaultExtension = ".patch";
|
options.DefaultExtension = ".patch";
|
||||||
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
|
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
|
||||||
|
|
||||||
var storageFile = await this.StorageProvider.SaveFilePickerAsync(options);
|
var storageFile = await StorageProvider.SaveFilePickerAsync(options);
|
||||||
if (storageFile != null)
|
if (storageFile != null)
|
||||||
await compare.SaveAsPatch(storageFile.Path.LocalPath);
|
await compare.SaveAsPatch(storageFile.Path.LocalPath);
|
||||||
|
|
||||||
|
|
|
@ -163,5 +163,3 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace SourceGit.Views
|
||||||
if (DataContext is ViewModels.Histories)
|
if (DataContext is ViewModels.Histories)
|
||||||
{
|
{
|
||||||
var list = CommitListContainer;
|
var list = CommitListContainer;
|
||||||
if (list != null && list.SelectedItems.Count == 1)
|
if (list is { SelectedItems.Count: 1 })
|
||||||
list.ScrollIntoView(list.SelectedIndex);
|
list.ScrollIntoView(list.SelectedIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
private void OnCommitListContextRequested(object sender, ContextRequestedEventArgs e)
|
private void OnCommitListContextRequested(object sender, ContextRequestedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems: { Count: > 0 } } list)
|
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems.Count: > 0 } list)
|
||||||
{
|
{
|
||||||
var menu = histories.MakeContextMenu(list);
|
var menu = histories.MakeContextMenu(list);
|
||||||
menu?.Open(list);
|
menu?.Open(list);
|
||||||
|
@ -180,7 +180,7 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
private void OnCommitListDoubleTapped(object sender, TappedEventArgs e)
|
private void OnCommitListDoubleTapped(object sender, TappedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems: { Count: 1 } })
|
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems.Count: 1 })
|
||||||
{
|
{
|
||||||
var source = e.Source as Control;
|
var source = e.Source as Control;
|
||||||
var item = source.FindAncestorOfType<ListBoxItem>();
|
var item = source.FindAncestorOfType<ListBoxItem>();
|
||||||
|
|
|
@ -86,26 +86,12 @@ namespace SourceGit.Views
|
||||||
var imageSize = image.Size;
|
var imageSize = image.Size;
|
||||||
var scaleW = availableSize.Width / imageSize.Width;
|
var scaleW = availableSize.Width / imageSize.Width;
|
||||||
var scaleH = availableSize.Height / imageSize.Height;
|
var scaleH = availableSize.Height / imageSize.Height;
|
||||||
var scale = Math.Min(scaleW, scaleH);
|
var scale = Math.Min(1, Math.Min(scaleW, scaleH));
|
||||||
return new Size(scale * imageSize.Width, scale * imageSize.Height);
|
return new Size(scale * imageSize.Width, scale * imageSize.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return availableSize;
|
return availableSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
|
||||||
{
|
|
||||||
if (Image is { } image)
|
|
||||||
{
|
|
||||||
var imageSize = image.Size;
|
|
||||||
var scaleW = finalSize.Width / imageSize.Width;
|
|
||||||
var scaleH = finalSize.Height / imageSize.Height;
|
|
||||||
var scale = Math.Min(scaleW, scaleH);
|
|
||||||
return new Size(scale * imageSize.Width, scale * imageSize.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.ArrangeOverride(finalSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImageSwipeControl : ImageContainer
|
public class ImageSwipeControl : ImageContainer
|
||||||
|
@ -151,21 +137,12 @@ namespace SourceGit.Views
|
||||||
var w = Bounds.Width;
|
var w = Bounds.Width;
|
||||||
var h = Bounds.Height;
|
var h = Bounds.Height;
|
||||||
var x = w * alpha;
|
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(0, 0, x, h);
|
|
||||||
context.DrawImage(left, src, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
var right = NewImage;
|
if (OldImage is { } left && alpha > 0)
|
||||||
if (right != null && alpha < 1)
|
RenderSingleSide(context, left, new Rect(0, 0, x, h));
|
||||||
{
|
|
||||||
var src = new Rect(right.Size.Width * alpha, 0, right.Size.Width * (1 - alpha), right.Size.Height);
|
if (NewImage is { } right && alpha < 1)
|
||||||
var dst = new Rect(x, 0, w - x, h);
|
RenderSingleSide(context, right, new Rect(x, 0, w - x, h));
|
||||||
context.DrawImage(right, src, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.DrawLine(new Pen(Brushes.DarkGreen, 2), new Point(x, 0), new Point(x, Bounds.Height));
|
context.DrawLine(new Pen(Brushes.DarkGreen, 2), new Point(x, 0), new Point(x, Bounds.Height));
|
||||||
}
|
}
|
||||||
|
@ -243,10 +220,29 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
var sw = available.Width / img.Width;
|
var sw = available.Width / img.Width;
|
||||||
var sh = available.Height / img.Height;
|
var sh = available.Height / img.Height;
|
||||||
var scale = Math.Min(sw, sh);
|
var scale = Math.Min(1, Math.Min(sw, sh));
|
||||||
return new Size(scale * img.Width, scale * img.Height);
|
return new Size(scale * img.Width, scale * img.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RenderSingleSide(DrawingContext context, Bitmap img, Rect clip)
|
||||||
|
{
|
||||||
|
var w = Bounds.Width;
|
||||||
|
var h = Bounds.Height;
|
||||||
|
|
||||||
|
var imgW = img.Size.Width;
|
||||||
|
var imgH = img.Size.Height;
|
||||||
|
var scale = Math.Min(1, Math.Min(w / imgW, h / imgH));
|
||||||
|
|
||||||
|
var scaledW = img.Size.Width * scale;
|
||||||
|
var scaledH = img.Size.Height * scale;
|
||||||
|
|
||||||
|
var src = new Rect(0, 0, imgW, imgH);
|
||||||
|
var dst = new Rect((w - scaledW) * 0.5, (h - scaledH) * 0.5, scaledW, scaledH);
|
||||||
|
|
||||||
|
using (context.PushClip(clip))
|
||||||
|
context.DrawImage(img, src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
private bool _pressedOnSlider = false;
|
private bool _pressedOnSlider = false;
|
||||||
private bool _lastInSlider = false;
|
private bool _lastInSlider = false;
|
||||||
}
|
}
|
||||||
|
@ -290,7 +286,6 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
base.Render(context);
|
base.Render(context);
|
||||||
|
|
||||||
var rect = new Rect(0, 0, Bounds.Width, Bounds.Height);
|
|
||||||
var alpha = Alpha;
|
var alpha = Alpha;
|
||||||
var left = OldImage;
|
var left = OldImage;
|
||||||
var right = NewImage;
|
var right = NewImage;
|
||||||
|
@ -299,32 +294,27 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
if (drawLeft && drawRight)
|
if (drawLeft && drawRight)
|
||||||
{
|
{
|
||||||
using (var rt = new RenderTargetBitmap(right.PixelSize, right.Dpi))
|
using (var rt = new RenderTargetBitmap(new PixelSize((int)Bounds.Width, (int)Bounds.Height), right.Dpi))
|
||||||
{
|
{
|
||||||
var rtRect = new Rect(rt.Size);
|
|
||||||
using (var dc = rt.CreateDrawingContext())
|
using (var dc = rt.CreateDrawingContext())
|
||||||
{
|
{
|
||||||
using (dc.PushRenderOptions(RO_SRC))
|
using (dc.PushRenderOptions(RO_SRC))
|
||||||
using (dc.PushOpacity(1 - alpha))
|
RenderSingleSide(dc, left, rt.Size.Width, rt.Size.Height, 1 - alpha);
|
||||||
dc.DrawImage(left, rtRect);
|
|
||||||
|
|
||||||
using (dc.PushRenderOptions(RO_DST))
|
using (dc.PushRenderOptions(RO_DST))
|
||||||
using (dc.PushOpacity(alpha))
|
RenderSingleSide(dc, right, rt.Size.Width, rt.Size.Height, alpha);
|
||||||
dc.DrawImage(right, rtRect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.DrawImage(rt, rtRect, rect);
|
context.DrawImage(rt, new Rect(0, 0, Bounds.Width, Bounds.Height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (drawLeft)
|
else if (drawLeft)
|
||||||
{
|
{
|
||||||
using (context.PushOpacity(1 - alpha))
|
RenderSingleSide(context, left, Bounds.Width, Bounds.Height, 1 - alpha);
|
||||||
context.DrawImage(left, rect);
|
|
||||||
}
|
}
|
||||||
else if (drawRight)
|
else if (drawRight)
|
||||||
{
|
{
|
||||||
using (context.PushOpacity(alpha))
|
RenderSingleSide(context, right, Bounds.Width, Bounds.Height, alpha);
|
||||||
context.DrawImage(right, rect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,10 +338,26 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
var sw = available.Width / img.Width;
|
var sw = available.Width / img.Width;
|
||||||
var sh = available.Height / img.Height;
|
var sh = available.Height / img.Height;
|
||||||
var scale = Math.Min(sw, sh);
|
var scale = Math.Min(1, Math.Min(sw, sh));
|
||||||
return new Size(scale * img.Width, scale * img.Height);
|
return new Size(scale * img.Width, scale * img.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RenderSingleSide(DrawingContext context, Bitmap img, double w, double h, double alpha)
|
||||||
|
{
|
||||||
|
var imgW = img.Size.Width;
|
||||||
|
var imgH = img.Size.Height;
|
||||||
|
var scale = Math.Min(1, Math.Min(w / imgW, h / imgH));
|
||||||
|
|
||||||
|
var scaledW = img.Size.Width * scale;
|
||||||
|
var scaledH = img.Size.Height * scale;
|
||||||
|
|
||||||
|
var src = new Rect(0, 0, imgW, imgH);
|
||||||
|
var dst = new Rect((w - scaledW) * 0.5, (h - scaledH) * 0.5, scaledW, scaledH);
|
||||||
|
|
||||||
|
using (context.PushOpacity(alpha))
|
||||||
|
context.DrawImage(img, src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly RenderOptions RO_SRC = new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Source, BitmapInterpolationMode = BitmapInterpolationMode.HighQuality };
|
private static readonly RenderOptions RO_SRC = new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Source, BitmapInterpolationMode = BitmapInterpolationMode.HighQuality };
|
||||||
private static readonly RenderOptions RO_DST = new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Plus, BitmapInterpolationMode = BitmapInterpolationMode.HighQuality };
|
private static readonly RenderOptions RO_DST = new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Plus, BitmapInterpolationMode = BitmapInterpolationMode.HighQuality };
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
<TextBlock Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
<TextBlock Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
<Border Grid.Row="1" Margin="0,12,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
<Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8">
|
<Border Background="{DynamicResource Brush.Popup}" Padding="8">
|
||||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
|
||||||
<v:ImageView Image="{Binding Old}"/>
|
<v:ImageView Image="{Binding Old}"/>
|
||||||
</Border>
|
</Border>
|
||||||
|
@ -52,8 +52,8 @@
|
||||||
<TextBlock Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
<TextBlock Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
<Border Grid.Row="1" Margin="0,12,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
<Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8">
|
<Border Background="{DynamicResource Brush.Popup}" Padding="8">
|
||||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
|
||||||
<v:ImageView Image="{Binding New}"/>
|
<v:ImageView Image="{Binding New}"/>
|
||||||
</Border>
|
</Border>
|
||||||
|
@ -87,8 +87,8 @@
|
||||||
<TextBlock Grid.Column="7" Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
<TextBlock Grid.Column="7" Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
<Border Grid.Row="1" Margin="0,12,0,0" HorizontalAlignment="Center" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
<Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}">
|
<Border Background="{DynamicResource Brush.Window}">
|
||||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
||||||
<v:ImageSwipeControl OldImage="{Binding Old}"
|
<v:ImageSwipeControl OldImage="{Binding Old}"
|
||||||
NewImage="{Binding New}"
|
NewImage="{Binding New}"
|
||||||
|
@ -123,8 +123,8 @@
|
||||||
<TextBlock Grid.Column="7" Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
<TextBlock Grid.Column="7" Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
<Border Grid.Row="1" Margin="0,12,0,0" HorizontalAlignment="Center" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
<Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}">
|
<Border Background="{DynamicResource Brush.Window}">
|
||||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
||||||
<v:ImageBlendControl Alpha="{Binding #ImageBlendSlider.Value}"
|
<v:ImageBlendControl Alpha="{Binding #ImageBlendSlider.Value}"
|
||||||
OldImage="{Binding Old}"
|
OldImage="{Binding Old}"
|
||||||
|
|
|
@ -46,4 +46,3 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,6 @@
|
||||||
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
Text="{Binding Node.Name}"
|
Text="{Binding Node.Name}"
|
||||||
IsVisible="{Binding Node.IsRepository}"
|
|
||||||
IsHitTestVisible="False"/>
|
IsHitTestVisible="False"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
@ -99,6 +98,7 @@
|
||||||
Text="{DynamicResource Text.PageTabBar.Welcome.Title}"
|
Text="{DynamicResource Text.PageTabBar.Welcome.Title}"
|
||||||
IsVisible="{Binding !Node.IsRepository}"
|
IsVisible="{Binding !Node.IsRepository}"
|
||||||
IsHitTestVisible="False"/>
|
IsHitTestVisible="False"/>
|
||||||
|
|
||||||
<Button Grid.Column="2"
|
<Button Grid.Column="2"
|
||||||
Classes="icon_button"
|
Classes="icon_button"
|
||||||
Width="16" Height="16" Margin="12,0"
|
Width="16" Height="16" Margin="12,0"
|
||||||
|
|
|
@ -98,7 +98,6 @@ namespace SourceGit.Views
|
||||||
ctx.BeginFigure(new Point(x, y), true);
|
ctx.BeginFigure(new Point(x, y), true);
|
||||||
y = 1;
|
y = 1;
|
||||||
ctx.LineTo(new Point(x, y));
|
ctx.LineTo(new Point(x, y));
|
||||||
x = drawRightX - 6;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -112,9 +111,10 @@ namespace SourceGit.Views
|
||||||
x += 6;
|
x += 6;
|
||||||
y = 1;
|
y = 1;
|
||||||
ctx.ArcTo(new Point(x, y), new Size(6, 6), angle, false, SweepDirection.Clockwise);
|
ctx.ArcTo(new Point(x, y), new Size(6, 6), angle, false, SweepDirection.Clockwise);
|
||||||
x = drawRightX - 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x = drawRightX - 6;
|
||||||
|
|
||||||
if (drawRightX <= LauncherTabsScroller.Bounds.Right)
|
if (drawRightX <= LauncherTabsScroller.Bounds.Right)
|
||||||
{
|
{
|
||||||
ctx.LineTo(new Point(x, y));
|
ctx.LineTo(new Point(x, y));
|
||||||
|
|
|
@ -10,5 +10,3 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -95,20 +95,15 @@ namespace SourceGit.Views
|
||||||
normalTypeface,
|
normalTypeface,
|
||||||
FontSize,
|
FontSize,
|
||||||
Foreground);
|
Foreground);
|
||||||
|
context.DrawText(formatted, new Point(offsetX, 0));
|
||||||
|
|
||||||
if (isName)
|
if (isName)
|
||||||
{
|
{
|
||||||
var lineY = formatted.Baseline + 2;
|
var lineY = formatted.Baseline + 2;
|
||||||
context.DrawText(formatted, new Point(offsetX, 0));
|
|
||||||
context.DrawLine(underlinePen, new Point(offsetX, lineY), new Point(offsetX + formatted.Width, lineY));
|
context.DrawLine(underlinePen, new Point(offsetX, lineY), new Point(offsetX + formatted.Width, lineY));
|
||||||
offsetX += formatted.WidthIncludingTrailingWhitespace;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context.DrawText(formatted, new Point(offsetX, 0));
|
|
||||||
offsetX += formatted.WidthIncludingTrailingWhitespace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offsetX += formatted.WidthIncludingTrailingWhitespace;
|
||||||
isName = !isName;
|
isName = !isName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,7 @@ namespace SourceGit.Views
|
||||||
SetIfChanged(config, "user.name", DefaultUser, "");
|
SetIfChanged(config, "user.name", DefaultUser, "");
|
||||||
SetIfChanged(config, "user.email", DefaultEmail, "");
|
SetIfChanged(config, "user.email", DefaultEmail, "");
|
||||||
SetIfChanged(config, "user.signingkey", GPGUserKey, "");
|
SetIfChanged(config, "user.signingkey", GPGUserKey, "");
|
||||||
SetIfChanged(config, "core.autocrlf", CRLFMode != null ? CRLFMode.Value : null, null);
|
SetIfChanged(config, "core.autocrlf", CRLFMode?.Value, null);
|
||||||
SetIfChanged(config, "fetch.prune", EnablePruneOnFetch ? "true" : "false", "false");
|
SetIfChanged(config, "fetch.prune", EnablePruneOnFetch ? "true" : "false", "false");
|
||||||
SetIfChanged(config, "commit.gpgsign", EnableGPGCommitSigning ? "true" : "false", "false");
|
SetIfChanged(config, "commit.gpgsign", EnableGPGCommitSigning ? "true" : "false", "false");
|
||||||
SetIfChanged(config, "tag.gpgsign", EnableGPGTagSigning ? "true" : "false", "false");
|
SetIfChanged(config, "tag.gpgsign", EnableGPGTagSigning ? "true" : "false", "false");
|
||||||
|
|
|
@ -208,7 +208,7 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
private void OnWorktreeListPropertyChanged(object _, AvaloniaPropertyChangedEventArgs e)
|
private void OnWorktreeListPropertyChanged(object _, AvaloniaPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Property == ListBox.ItemsSourceProperty || e.Property == ListBox.IsVisibleProperty)
|
if (e.Property == ItemsControl.ItemsSourceProperty || e.Property == IsVisibleProperty)
|
||||||
UpdateLeftSidebarLayout();
|
UpdateLeftSidebarLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ namespace SourceGit.Views
|
||||||
private void UpdateLeftSidebarLayout()
|
private void UpdateLeftSidebarLayout()
|
||||||
{
|
{
|
||||||
var vm = DataContext as ViewModels.Repository;
|
var vm = DataContext as ViewModels.Repository;
|
||||||
if (vm == null || vm.Settings == null)
|
if (vm?.Settings == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!IsLoaded)
|
if (!IsLoaded)
|
||||||
|
|
|
@ -126,10 +126,9 @@
|
||||||
</ContentControl.DataTemplates>
|
</ContentControl.DataTemplates>
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
|
|
||||||
<Button Classes="icon_button" Width="32" Command="{Binding NavigateToCurrentHead}" ToolTip.Tip="{DynamicResource Text.Repository.NavigateToCurrentHead}">
|
<Button Classes="icon_button" Width="32" Click="NavigateToHead" ToolTip.Tip="{DynamicResource Text.Repository.NavigateToCurrentHead}">
|
||||||
<Path Width="13" Height="13" Margin="0,2,0,0" Data="{StaticResource Icons.Target}" Fill="{DynamicResource Brush.FG1}"/>
|
<Path Width="13" Height="13" Margin="0,2,0,0" Data="{StaticResource Icons.Target}" Fill="{DynamicResource Brush.FG1}"/>
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,8 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
if (repo.LocalChangesCount > 0)
|
if (repo.LocalChangesCount > 0)
|
||||||
App.RaiseException(repo.FullPath, "You have un-committed local changes. Please discard or stash them first.");
|
App.RaiseException(repo.FullPath, "You have un-committed local changes. Please discard or stash them first.");
|
||||||
|
else if (repo.IsBisectCommandRunning || repo.BisectState != Models.BisectState.None)
|
||||||
|
App.RaiseException(repo.FullPath, "Bisect is running! Please abort it before starting a new one.");
|
||||||
else
|
else
|
||||||
repo.Bisect("start");
|
repo.Bisect("start");
|
||||||
}
|
}
|
||||||
|
@ -150,6 +152,14 @@ namespace SourceGit.Views
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void NavigateToHead(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is ViewModels.Repository { CurrentBranch: { } } repo)
|
||||||
|
{
|
||||||
|
repo.NavigateToCommit(repo.CurrentBranch.Head);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
KeyDown="OnResetModeKeyDown">
|
KeyDown="OnResetModeKeyDown">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
<DataTemplate DataType="m:ResetMode">
|
<DataTemplate DataType="m:ResetMode">
|
||||||
<Grid ColumnDefinitions="16,60,*">
|
<Grid ColumnDefinitions="16,60,*,Auto">
|
||||||
<Ellipse Grid.Column="0" Width="12" Height="12" Fill="{Binding Color}"/>
|
<Ellipse Grid.Column="0" Width="12" Height="12" Fill="{Binding Color}"/>
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Name}" Margin="2,0,0,0"/>
|
<TextBlock Grid.Column="1" Text="{Binding Name}" Margin="2,0,0,0"/>
|
||||||
<TextBlock Grid.Column="2" Text="{Binding Desc}" Margin="2,0,16,0" FontSize="11" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
|
<TextBlock Grid.Column="2" Text="{Binding Desc}" Margin="2,0,16,0" FontSize="11" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
|
||||||
|
@ -53,6 +53,16 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ComboBox.ItemTemplate>
|
</ComboBox.ItemTemplate>
|
||||||
|
|
||||||
|
<ComboBox.SelectionBoxItemTemplate>
|
||||||
|
<DataTemplate DataType="m:ResetMode">
|
||||||
|
<Grid ColumnDefinitions="16,60,*">
|
||||||
|
<Ellipse Grid.Column="0" Width="12" Height="12" Fill="{Binding Color}"/>
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding Name}" Margin="2,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="2" Text="{Binding Desc}" Margin="2,0,16,0" FontSize="11" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.SelectionBoxItemTemplate>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
<DataTemplate DataType="m:RevisionImageFile">
|
<DataTemplate DataType="m:RevisionImageFile">
|
||||||
<Grid RowDefinitions="*,Auto" Margin="0,8" VerticalAlignment="Center" HorizontalAlignment="Center">
|
<Grid RowDefinitions="*,Auto" Margin="0,8" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||||
<Border Grid.Row="0" Effect="drop-shadow(0 0 8 #A0000000)">
|
<Border Grid.Row="0" HorizontalAlignment="Center" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
<Border Background="{DynamicResource Brush.Window}">
|
<Border Background="{DynamicResource Brush.Window}">
|
||||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
||||||
<v:ImageView Image="{Binding Image}"/>
|
<v:ImageView Image="{Binding Image}"/>
|
||||||
|
@ -97,4 +97,3 @@
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</UserControl.DataTemplates>
|
</UserControl.DataTemplates>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
||||||
|
|
|
@ -163,4 +163,3 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace SourceGit.Views
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var vm = DataContext as ViewModels.CommitDetail;
|
var vm = DataContext as ViewModels.CommitDetail;
|
||||||
if (vm == null || vm.Commit == null)
|
if (vm?.Commit == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var objects = vm.GetRevisionFilesUnderFolder(file);
|
var objects = vm.GetRevisionFilesUnderFolder(file);
|
||||||
|
@ -254,7 +254,7 @@ namespace SourceGit.Views
|
||||||
_searchResult.Clear();
|
_searchResult.Clear();
|
||||||
|
|
||||||
var vm = DataContext as ViewModels.CommitDetail;
|
var vm = DataContext as ViewModels.CommitDetail;
|
||||||
if (vm == null || vm.Commit == null)
|
if (vm?.Commit == null)
|
||||||
{
|
{
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
return;
|
return;
|
||||||
|
@ -270,12 +270,7 @@ namespace SourceGit.Views
|
||||||
foreach (var obj in objects)
|
foreach (var obj in objects)
|
||||||
_tree.Add(new ViewModels.RevisionFileTreeNode { Backend = obj });
|
_tree.Add(new ViewModels.RevisionFileTreeNode { Backend = obj });
|
||||||
|
|
||||||
_tree.Sort((l, r) =>
|
SortNodes(_tree);
|
||||||
{
|
|
||||||
if (l.IsFolder == r.IsFolder)
|
|
||||||
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
|
|
||||||
return l.IsFolder ? -1 : 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
var topTree = new List<ViewModels.RevisionFileTreeNode>();
|
var topTree = new List<ViewModels.RevisionFileTreeNode>();
|
||||||
MakeRows(topTree, _tree, 0);
|
MakeRows(topTree, _tree, 0);
|
||||||
|
@ -341,13 +336,7 @@ namespace SourceGit.Views
|
||||||
foreach (var obj in objects)
|
foreach (var obj in objects)
|
||||||
node.Children.Add(new ViewModels.RevisionFileTreeNode() { Backend = obj });
|
node.Children.Add(new ViewModels.RevisionFileTreeNode() { Backend = obj });
|
||||||
|
|
||||||
node.Children.Sort((l, r) =>
|
SortNodes(node.Children);
|
||||||
{
|
|
||||||
if (l.IsFolder == r.IsFolder)
|
|
||||||
return Models.NumericSort.Compare(l.Name, r.Name);
|
|
||||||
return l.IsFolder ? -1 : 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
return node.Children;
|
return node.Children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,6 +354,16 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SortNodes(List<ViewModels.RevisionFileTreeNode> nodes)
|
||||||
|
{
|
||||||
|
nodes.Sort((l, r) =>
|
||||||
|
{
|
||||||
|
if (l.IsFolder == r.IsFolder)
|
||||||
|
return Models.NumericSort.Compare(l.Name, r.Name);
|
||||||
|
return l.IsFolder ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private List<ViewModels.RevisionFileTreeNode> _tree = [];
|
private List<ViewModels.RevisionFileTreeNode> _tree = [];
|
||||||
private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = [];
|
private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = [];
|
||||||
private bool _disableSelectionChangingEvent = false;
|
private bool _disableSelectionChangingEvent = false;
|
||||||
|
|
|
@ -25,7 +25,6 @@ namespace SourceGit.Views
|
||||||
TextArea.TextView.Margin = new Thickness(4, 0);
|
TextArea.TextView.Margin = new Thickness(4, 0);
|
||||||
TextArea.TextView.Options.EnableHyperlinks = false;
|
TextArea.TextView.Options.EnableHyperlinks = false;
|
||||||
TextArea.TextView.Options.EnableEmailHyperlinks = false;
|
TextArea.TextView.Options.EnableEmailHyperlinks = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnLoaded(RoutedEventArgs e)
|
protected override void OnLoaded(RoutedEventArgs e)
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
ItemsSource="{Binding VisibleStashes}"
|
ItemsSource="{Binding VisibleStashes}"
|
||||||
SelectedItem="{Binding SelectedStash, Mode=TwoWay}"
|
SelectedItem="{Binding SelectedStash, Mode=TwoWay}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
|
KeyDown="OnStashListKeyDown"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||||
<ListBox.Styles>
|
<ListBox.Styles>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
|
||||||
namespace SourceGit.Views
|
namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
|
@ -23,6 +24,18 @@ namespace SourceGit.Views
|
||||||
layout.StashesLeftWidth = new GridLength(maxLeft, GridUnitType.Pixel);
|
layout.StashesLeftWidth = new GridLength(maxLeft, GridUnitType.Pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnStashListKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key is not (Key.Delete or Key.Back))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (DataContext is not ViewModels.StashesPage vm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vm.Drop(vm.SelectedStash);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnStashContextRequested(object sender, ContextRequestedEventArgs e)
|
private void OnStashContextRequested(object sender, ContextRequestedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.StashesPage vm && sender is Border border)
|
if (DataContext is ViewModels.StashesPage vm && sender is Border border)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
<ListBox Classes="repo_left_content_list"
|
<ListBox Classes="repo_left_content_list"
|
||||||
ItemsSource="{Binding Rows}"
|
ItemsSource="{Binding Rows}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
|
KeyDown="OnKeyDown"
|
||||||
SelectionChanged="OnSelectionChanged">
|
SelectionChanged="OnSelectionChanged">
|
||||||
|
|
||||||
<ListBox.DataTemplates>
|
<ListBox.DataTemplates>
|
||||||
|
@ -88,6 +89,7 @@
|
||||||
Margin="8,0,0,0"
|
Margin="8,0,0,0"
|
||||||
ItemsSource="{Binding Tags}"
|
ItemsSource="{Binding Tags}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
|
KeyDown="OnKeyDown"
|
||||||
SelectionChanged="OnSelectionChanged">
|
SelectionChanged="OnSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate DataType="m:Tag">
|
<DataTemplate DataType="m:Tag">
|
||||||
|
@ -131,4 +133,3 @@
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</UserControl.DataTemplates>
|
</UserControl.DataTemplates>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
||||||
|
|
|
@ -214,6 +214,19 @@ namespace SourceGit.Views
|
||||||
if (selectedTag != null)
|
if (selectedTag != null)
|
||||||
RaiseEvent(new RoutedEventArgs(SelectionChangedEvent));
|
RaiseEvent(new RoutedEventArgs(SelectionChangedEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is not ViewModels.Repository repo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var selected = (sender as ListBox)?.SelectedItem;
|
||||||
|
if (selected is ViewModels.TagTreeNode { Tag: { } tagInNode })
|
||||||
|
repo.DeleteTag(tagInNode);
|
||||||
|
else if (selected is Models.Tag tag)
|
||||||
|
repo.DeleteTag(tag);
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -765,12 +765,10 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
else if (change.Property == BlockNavigationProperty)
|
else if (change.Property == BlockNavigationProperty)
|
||||||
{
|
{
|
||||||
var oldValue = change.OldValue as ViewModels.BlockNavigation;
|
if (change.OldValue is ViewModels.BlockNavigation oldValue)
|
||||||
if (oldValue != null)
|
|
||||||
oldValue.PropertyChanged -= OnBlockNavigationPropertyChanged;
|
oldValue.PropertyChanged -= OnBlockNavigationPropertyChanged;
|
||||||
|
|
||||||
var newValue = change.NewValue as ViewModels.BlockNavigation;
|
if (change.NewValue is ViewModels.BlockNavigation newValue)
|
||||||
if (newValue != null)
|
|
||||||
newValue.PropertyChanged += OnBlockNavigationPropertyChanged;
|
newValue.PropertyChanged += OnBlockNavigationPropertyChanged;
|
||||||
|
|
||||||
TextArea?.TextView?.Redraw();
|
TextArea?.TextView?.Redraw();
|
||||||
|
@ -1251,8 +1249,7 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
base.OnDataContextChanged(e);
|
base.OnDataContextChanged(e);
|
||||||
|
|
||||||
var textDiff = DataContext as Models.TextDiff;
|
if (DataContext is Models.TextDiff textDiff)
|
||||||
if (textDiff != null)
|
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
foreach (var line in textDiff.Lines)
|
foreach (var line in textDiff.Lines)
|
||||||
|
@ -1410,8 +1407,7 @@ namespace SourceGit.Views
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var textDiff = this.FindAncestorOfType<TextDiffView>()?.DataContext as Models.TextDiff;
|
if (this.FindAncestorOfType<TextDiffView>()?.DataContext is Models.TextDiff textDiff)
|
||||||
if (textDiff != null)
|
|
||||||
{
|
{
|
||||||
var lineIdx = -1;
|
var lineIdx = -1;
|
||||||
foreach (var line in view.VisualLines)
|
foreach (var line in view.VisualLines)
|
||||||
|
@ -1537,7 +1533,7 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
private void DirectSyncScrollOffset()
|
private void DirectSyncScrollOffset()
|
||||||
{
|
{
|
||||||
if (_scrollViewer is { } && DataContext is ViewModels.TwoSideTextDiff diff)
|
if (_scrollViewer is not null && DataContext is ViewModels.TwoSideTextDiff diff)
|
||||||
diff.SyncScrollOffset = _scrollViewer?.Offset ?? Vector.Zero;
|
diff.SyncScrollOffset = _scrollViewer?.Offset ?? Vector.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
ItemsSource="{Binding Logs}"
|
ItemsSource="{Binding Logs}"
|
||||||
SelectedItem="{Binding SelectedLog, Mode=TwoWay}"
|
SelectedItem="{Binding SelectedLog, Mode=TwoWay}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
|
KeyDown="OnLogKeyDown"
|
||||||
Grid.IsSharedSizeScope="True"
|
Grid.IsSharedSizeScope="True"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
|
||||||
namespace SourceGit.Views
|
namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
|
@ -39,5 +40,16 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnLogKeyDown(object _, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key is not (Key.Delete or Key.Back))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (DataContext is ViewModels.ViewLogs { SelectedLog: { } log } vm)
|
||||||
|
vm.Logs.Remove(log);
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,7 @@
|
||||||
ItemsSource="{Binding Rows}"
|
ItemsSource="{Binding Rows}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
Loaded="SetupTreeViewDragAndDrop"
|
Loaded="SetupTreeViewDragAndDrop"
|
||||||
LostFocus="OnTreeViewLostFocus"
|
LostFocus="OnTreeViewLostFocus">
|
||||||
KeyDown="OnTreeViewKeyDown">
|
|
||||||
<ListBox.Styles>
|
<ListBox.Styles>
|
||||||
<Style Selector="ListBox">
|
<Style Selector="ListBox">
|
||||||
<Setter Property="FocusAdorner">
|
<Setter Property="FocusAdorner">
|
||||||
|
|
|
@ -31,9 +31,25 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
protected override void OnKeyDown(KeyEventArgs e)
|
protected override void OnKeyDown(KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (SelectedItem is ViewModels.RepositoryNode { IsRepository: false } node && e.KeyModifiers == KeyModifiers.None)
|
if (SelectedItem is ViewModels.RepositoryNode node && e.KeyModifiers == KeyModifiers.None)
|
||||||
{
|
{
|
||||||
if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
|
if (e.Key is Key.Delete or Key.Back)
|
||||||
|
{
|
||||||
|
node.Delete();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
else if (node.IsRepository)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
var parent = this.FindAncestorOfType<Launcher>();
|
||||||
|
if (parent is { DataContext: ViewModels.Launcher launcher })
|
||||||
|
launcher.OpenRepositoryInTab(node, null);
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right) || e.Key == Key.Enter)
|
||||||
{
|
{
|
||||||
ViewModels.Welcome.Instance.ToggleNodeIsExpanded(node);
|
ViewModels.Welcome.Instance.ToggleNodeIsExpanded(node);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
|
@ -92,25 +108,6 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTreeViewKeyDown(object _, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (TreeContainer.SelectedItem is ViewModels.RepositoryNode node && e.Key == Key.Enter)
|
|
||||||
{
|
|
||||||
if (node.IsRepository)
|
|
||||||
{
|
|
||||||
var parent = this.FindAncestorOfType<Launcher>();
|
|
||||||
if (parent is { DataContext: ViewModels.Launcher launcher })
|
|
||||||
launcher.OpenRepositoryInTab(node, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ViewModels.Welcome.Instance.ToggleNodeIsExpanded(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTreeNodeContextRequested(object sender, ContextRequestedEventArgs e)
|
private void OnTreeNodeContextRequested(object sender, ContextRequestedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Grid { DataContext: ViewModels.RepositoryNode node } grid)
|
if (sender is Grid { DataContext: ViewModels.RepositoryNode node } grid)
|
||||||
|
@ -218,17 +215,9 @@ namespace SourceGit.Views
|
||||||
if (to == null)
|
if (to == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (to.IsRepository)
|
e.DragEffects = to.IsRepository ? DragDropEffects.None : DragDropEffects.Move;
|
||||||
{
|
|
||||||
e.DragEffects = DragDropEffects.None;
|
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
e.DragEffects = DragDropEffects.Move;
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DropOnTreeNode(object sender, DragEventArgs e)
|
private void DropOnTreeNode(object sender, DragEventArgs e)
|
||||||
|
|
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