Merge branch 'release/v2026.06'

This commit is contained in:
leo
2026-03-16 10:27:00 +08:00
142 changed files with 2047 additions and 871 deletions

View File

@@ -14,6 +14,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
- name: Set up .NET
uses: actions/setup-dotnet@v4

View File

@@ -6,30 +6,39 @@ This document shows the translation status of each locale file in the repository
### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)
### ![de__DE](https://img.shields.io/badge/de__DE-99.58%25-yellow)
### ![de__DE](https://img.shields.io/badge/de__DE-98.46%25-yellow)
<details>
<summary>Missing keys in de_DE.axaml</summary>
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitMessageTextBox.Column
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.GotoRevisionSelector
- Text.Hotkeys.Repo.GoToChild
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.Preferences.General.Use24Hours
- Text.StashCM.ApplyFileChanges
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Path
</details>
### ![es__ES](https://img.shields.io/badge/es__ES-99.69%25-yellow)
### ![es__ES](https://img.shields.io/badge/es__ES-99.90%25-yellow)
<details>
<summary>Missing keys in es_ES.axaml</summary>
- Text.GotoRevisionSelector
- Text.Hotkeys.Repo.GoToChild
- Text.StashCM.ApplyFileChanges
- Text.Preferences.General.Use24Hours
</details>
### ![fr__FR](https://img.shields.io/badge/fr__FR-93.33%25-yellow)
### ![fr__FR](https://img.shields.io/badge/fr__FR-92.28%25-yellow)
<details>
<summary>Missing keys in fr_FR.axaml</summary>
@@ -44,10 +53,15 @@ This document shows the translation status of each locale file in the repository
- Text.ChangeCM.MergeExternal
- Text.ChangeCM.ResetFileTo
- Text.Checkout.WarnUpdatingSubmodules
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitMessageTextBox.Column
- Text.CommitMessageTextBox.Placeholder
- Text.Compare.WithHead
- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.EditBranchDescription
- Text.EditBranchDescription.Target
- Text.FileCM.CustomAction
@@ -58,6 +72,8 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.Global.Zoom
- Text.Hotkeys.Repo.GoToChild
- Text.Hotkeys.Repo.GoToParent
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.MergeConflictEditor.AcceptBoth.MineFirst
- Text.MergeConflictEditor.AcceptBoth.TheirsFirst
- Text.MergeConflictEditor.UseBoth
@@ -82,6 +98,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.DiffMerge.DiffArgs.Tip
- Text.Preferences.DiffMerge.MergeArgs
- Text.Preferences.DiffMerge.MergeArgs.Tip
- Text.Preferences.General.Use24Hours
- Text.Preferences.Shell.Args
- Text.Preferences.Shell.Args.Tip
- Text.Repository.OpenAsFolder
@@ -97,11 +114,14 @@ This document shows the translation status of each locale file in the repository
- Text.TagCM.CompareWithHead
- Text.WorkingCopy.Conflicts.Merge
- Text.WorkingCopy.Conflicts.MergeExternal
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Path
- Text.Yes
</details>
### ![id__ID](https://img.shields.io/badge/id__ID-91.25%25-yellow)
### ![id__ID](https://img.shields.io/badge/id__ID-90.22%25-yellow)
<details>
<summary>Missing keys in id_ID.axaml</summary>
@@ -120,6 +140,10 @@ This document shows the translation status of each locale file in the repository
- Text.ChangeCM.MergeExternal
- Text.ChangeCM.ResetFileTo
- Text.Checkout.WarnUpdatingSubmodules
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitCM.Drop
- Text.CommitMessageTextBox.Column
- Text.CommitMessageTextBox.Placeholder
@@ -128,6 +152,7 @@ This document shows the translation status of each locale file in the repository
- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules
- Text.Configure.Git.ConventionalTypesOverride
- Text.ConfigureCustomActionControls.StringValue.Tip
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.DropHead
- Text.DropHead.Commit
- Text.DropHead.NewHead
@@ -144,6 +169,8 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.Repo.GoToChild
- Text.Hotkeys.Repo.GoToParent
- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.Launcher.Commands
- Text.Launcher.OpenRepository
- Text.MergeConflictEditor.AcceptBoth.MineFirst
@@ -172,6 +199,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.DiffMerge.DiffArgs.Tip
- Text.Preferences.DiffMerge.MergeArgs
- Text.Preferences.DiffMerge.MergeArgs.Tip
- Text.Preferences.General.Use24Hours
- Text.Preferences.Shell.Args
- Text.Preferences.Shell.Args.Tip
- Text.PushToNewBranch
@@ -189,31 +217,62 @@ This document shows the translation status of each locale file in the repository
- Text.TagCM.CompareWithHead
- Text.WorkingCopy.Conflicts.Merge
- Text.WorkingCopy.Conflicts.MergeExternal
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Path
- Text.Yes
</details>
### ![it__IT](https://img.shields.io/badge/it__IT-98.96%25-yellow)
### ![it__IT](https://img.shields.io/badge/it__IT-97.84%25-yellow)
<details>
<summary>Missing keys in it_IT.axaml</summary>
- Text.ChangeCM.ResetFileTo
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitMessageTextBox.Column
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.GotoRevisionSelector
- Text.Histories.Header.DateTime
- Text.Histories.ShowColumns
- Text.Hotkeys.Repo.GoToChild
- Text.Hotkeys.Repo.GoToParent
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.Preferences.General.Use24Hours
- Text.SelfUpdate.CurrentVersion
- Text.SelfUpdate.ReleaseDate
- Text.StashCM.ApplyFileChanges
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Path
</details>
### ![ja__JP](https://img.shields.io/badge/ja__JP-%E2%88%9A-brightgreen)
### ![ja__JP](https://img.shields.io/badge/ja__JP-98.87%25-yellow)
### ![ko__KR](https://img.shields.io/badge/ko__KR-91.56%25-yellow)
<details>
<summary>Missing keys in ja_JP.axaml</summary>
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.Preferences.General.Use24Hours
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Path
</details>
### ![ko__KR](https://img.shields.io/badge/ko__KR-90.53%25-yellow)
<details>
<summary>Missing keys in ko_KR.axaml</summary>
@@ -232,12 +291,17 @@ This document shows the translation status of each locale file in the repository
- Text.ChangeCM.MergeExternal
- Text.ChangeCM.ResetFileTo
- Text.Checkout.WarnUpdatingSubmodules
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitMessageTextBox.Column
- Text.CommitMessageTextBox.Placeholder
- Text.Compare.WithHead
- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules
- Text.Configure.Git.ConventionalTypesOverride
- Text.ConfigureCustomActionControls.StringValue.Tip
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.EditBranchDescription
- Text.EditBranchDescription.Target
- Text.FileCM.CustomAction
@@ -251,6 +315,8 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.Repo.GoToChild
- Text.Hotkeys.Repo.GoToParent
- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.Launcher.Commands
- Text.Launcher.OpenRepository
- Text.MergeConflictEditor.AcceptBoth.MineFirst
@@ -280,6 +346,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.DiffMerge.DiffArgs.Tip
- Text.Preferences.DiffMerge.MergeArgs
- Text.Preferences.DiffMerge.MergeArgs.Tip
- Text.Preferences.General.Use24Hours
- Text.Preferences.Shell.Args
- Text.Preferences.Shell.Args.Tip
- Text.PushToNewBranch
@@ -298,11 +365,14 @@ This document shows the translation status of each locale file in the repository
- Text.TagCM.CompareWithHead
- Text.WorkingCopy.Conflicts.Merge
- Text.WorkingCopy.Conflicts.MergeExternal
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Path
- Text.Yes
</details>
### ![pt__BR](https://img.shields.io/badge/pt__BR-69.27%25-red)
### ![pt__BR](https://img.shields.io/badge/pt__BR-68.49%25-red)
<details>
<summary>Missing keys in pt_BR.axaml</summary>
@@ -325,6 +395,10 @@ This document shows the translation status of each locale file in the repository
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
- Text.Clone.RecurseSubmodules
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitMessage
- Text.CommitCM.CopyCommitter
@@ -385,6 +459,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.ConfirmRestart.Title
- Text.ConfirmRestart.Message
@@ -438,6 +513,8 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.Repo.GoToParent
- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.InProgress.CherryPick.Head
- Text.InProgress.Merge.Operating
- Text.InProgress.Rebase.StoppedAt
@@ -492,6 +569,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
- Text.Preferences.General.ShowChildren
- Text.Preferences.General.ShowTagsInGraph
- Text.Preferences.General.Use24Hours
- Text.Preferences.General.UseGitHubStyleAvatar
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.SSLVerify
@@ -600,23 +678,31 @@ This document shows the translation status of each locale file in the repository
- Text.WorkingCopy.NoVerify
- Text.WorkingCopy.ResetAuthor
- Text.WorkingCopy.SignOff
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Open
- Text.Worktree.Path
- Text.Yes
</details>
### ![ru__RU](https://img.shields.io/badge/ru__RU-99.69%25-yellow)
### ![ru__RU](https://img.shields.io/badge/ru__RU-99.18%25-yellow)
<details>
<summary>Missing keys in ru_RU.axaml</summary>
- Text.GotoRevisionSelector
- Text.Hotkeys.Repo.GoToChild
- Text.StashCM.ApplyFileChanges
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.Preferences.General.Use24Hours
</details>
### ![ta__IN](https://img.shields.io/badge/ta__IN-71.56%25-red)
### ![ta__IN](https://img.shields.io/badge/ta__IN-70.75%25-red)
<details>
<summary>Missing keys in ta_IN.axaml</summary>
@@ -667,6 +753,10 @@ This document shows the translation status of each locale file in the repository
- Text.Checkout.WarnUpdatingSubmodules
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitMessage
- Text.CommitCM.CopyCommitter
@@ -719,6 +809,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.ConfirmRestart.Title
- Text.ConfirmRestart.Message
@@ -763,6 +854,8 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.Repo.GoToParent
- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.InteractiveRebase.ReorderTip
- Text.Launcher.Commands
- Text.Launcher.OpenRepository
@@ -803,6 +896,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.General.EnableCompactFolders
- Text.Preferences.General.ShowChangesPageByDefault
- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
- Text.Preferences.General.Use24Hours
- Text.Preferences.General.UseGitHubStyleAvatar
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.UseLibsecret
@@ -892,12 +986,15 @@ This document shows the translation status of each locale file in the repository
- Text.WorkingCopy.Conflicts.UseTheirs
- Text.WorkingCopy.NoVerify
- Text.WorkingCopy.ResetAuthor
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Open
- Text.Worktree.Path
- Text.Yes
</details>
### ![uk__UA](https://img.shields.io/badge/uk__UA-72.40%25-red)
### ![uk__UA](https://img.shields.io/badge/uk__UA-71.58%25-red)
<details>
<summary>Missing keys in uk_UA.axaml</summary>
@@ -948,6 +1045,10 @@ This document shows the translation status of each locale file in the repository
- Text.Checkout.WarnUpdatingSubmodules
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
- Text.CommandPalette.Branches
- Text.CommandPalette.BranchesAndTags
- Text.CommandPalette.RepositoryActions
- Text.CommandPalette.RevisionFiles
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitMessage
- Text.CommitCM.CopyCommitter
@@ -997,6 +1098,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfigureCustomActionControls.StringValue.Tip
- Text.ConfigureCustomActionControls.Type
- Text.ConfigureWorkspace.Name
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
- Text.ConfirmRestart.Title
- Text.ConfirmRestart.Message
- Text.CreateBranch.OverwriteExisting
@@ -1040,6 +1142,8 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.Repo.GoToParent
- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Init.CommandTip
- Text.Init.ErrorMessageTip
- Text.InteractiveRebase.ReorderTip
- Text.Launcher.Commands
- Text.Launcher.OpenRepository
@@ -1080,6 +1184,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.General.EnableCompactFolders
- Text.Preferences.General.ShowChangesPageByDefault
- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
- Text.Preferences.General.Use24Hours
- Text.Preferences.General.UseGitHubStyleAvatar
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.UseLibsecret
@@ -1165,7 +1270,10 @@ This document shows the translation status of each locale file in the repository
- Text.WorkingCopy.Conflicts.MergeExternal
- Text.WorkingCopy.NoVerify
- Text.WorkingCopy.ResetAuthor
- Text.Worktree.Branch
- Text.Worktree.Head
- Text.Worktree.Open
- Text.Worktree.Path
- Text.Yes
</details>

View File

@@ -1 +1 @@
2026.05
2026.06

View File

@@ -57,10 +57,5 @@ namespace SourceGit
// Ignore exceptions.
}
}
public static string GetRelativePath(this DirectoryInfo dir, string fullpath)
{
return fullpath.Substring(dir.FullName.Length).TrimStart(Path.DirectorySeparatorChar);
}
}
}

View File

@@ -208,13 +208,14 @@ namespace SourceGit
return false;
}
public static async Task<Models.ConfirmEmptyCommitResult> AskConfirmEmptyCommitAsync(bool hasLocalChanges)
public static async Task<Models.ConfirmEmptyCommitResult> AskConfirmEmptyCommitAsync(bool hasLocalChanges, bool hasSelectedUnstaged)
{
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
{
var confirm = new Views.ConfirmEmptyCommit();
confirm.TxtMessage.Text = Text(hasLocalChanges ? "ConfirmEmptyCommit.WithLocalChanges" : "ConfirmEmptyCommit.NoLocalChanges");
confirm.BtnStageAllAndCommit.IsVisible = hasLocalChanges;
confirm.BtnStageSelectedAndCommit.IsVisible = hasSelectedUnstaged;
return await confirm.ShowDialog<Models.ConfirmEmptyCommitResult>(owner);
}

View File

@@ -7,9 +7,9 @@ namespace SourceGit.Commands
{
public partial class CompareRevisions : Command
{
[GeneratedRegex(@"^([MADC])\s+(.+)$")]
[GeneratedRegex(@"^([MAD])\s+(.+)$")]
private static partial Regex REG_FORMAT();
[GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
[GeneratedRegex(@"^([CR])[0-9]{0,4}\s+(.+)$")]
private static partial Regex REG_RENAME_FORMAT();
public CompareRevisions(string repo, string start, string end)
@@ -47,8 +47,9 @@ namespace SourceGit.Commands
match = REG_RENAME_FORMAT().Match(line);
if (match.Success)
{
var renamed = new Models.Change() { Path = match.Groups[1].Value };
renamed.Set(Models.ChangeState.Renamed);
var type = match.Groups[1].Value;
var renamed = new Models.Change() { Path = match.Groups[2].Value };
renamed.Set(type == "R" ? Models.ChangeState.Renamed : Models.ChangeState.Copied);
changes.Add(renamed);
}
@@ -72,10 +73,6 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Deleted);
changes.Add(change);
break;
case 'C':
change.Set(Models.ChangeState.Copied);
changes.Add(change);
break;
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace SourceGit.Commands
{
public partial class QueryFileHistory : Command
{
[GeneratedRegex(@"^([MAD])\s+(.+)$")]
private static partial Regex REG_FORMAT();
[GeneratedRegex(@"^([CR])[0-9]{0,4}\s+(.+)$")]
private static partial Regex REG_RENAME_FORMAT();
public QueryFileHistory(string repo, string path, string head)
{
WorkingDirectory = repo;
Context = repo;
RaiseError = false;
var builder = new StringBuilder();
builder.Append("log --no-show-signature --date-order -n 10000 --decorate=no --format=\"@%H%x00%P%x00%aN±%aE%x00%at%x00%s\" --follow --name-status ");
if (!string.IsNullOrEmpty(head))
builder.Append(head).Append(" ");
builder.Append("-- ").Append(path.Quoted());
Args = builder.ToString();
}
public async Task<List<Models.FileVersion>> GetResultAsync()
{
var versions = new List<Models.FileVersion>();
var rs = await ReadToEndAsync().ConfigureAwait(false);
if (!rs.IsSuccess)
return versions;
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
if (lines.Length == 0)
return versions;
Models.FileVersion last = null;
foreach (var line in lines)
{
if (line.StartsWith('@'))
{
var parts = line.Split('\0');
if (parts.Length != 5)
continue;
last = new Models.FileVersion();
last.SHA = parts[0].Substring(1);
last.HasParent = !string.IsNullOrEmpty(parts[1]);
last.Author = Models.User.FindOrAdd(parts[2]);
last.AuthorTime = ulong.Parse(parts[3]);
last.Subject = parts[4];
versions.Add(last);
}
else if (last != null)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
{
match = REG_RENAME_FORMAT().Match(line);
if (match.Success)
{
var type = match.Groups[1].Value;
last.Change.Path = match.Groups[2].Value;
last.Change.Set(type == "R" ? Models.ChangeState.Renamed : Models.ChangeState.Copied);
}
continue;
}
last.Change.Path = match.Groups[2].Value;
var status = match.Groups[1].Value;
switch (status[0])
{
case 'M':
last.Change.Set(Models.ChangeState.Modified);
break;
case 'A':
last.Change.Set(Models.ChangeState.Added);
break;
case 'D':
last.Change.Set(Models.ChangeState.Deleted);
break;
}
}
}
return versions;
}
}
}

View File

@@ -6,9 +6,9 @@ namespace SourceGit.Commands
{
public partial class QueryStagedChangesWithAmend : Command
{
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ACDMT])\d{0,6}\t(.*)$")]
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ADMT])\d{0,6}\t(.*)$")]
private static partial Regex REG_FORMAT1();
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} R\d{0,6}\t(.*\t.*)$")]
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([RC])\d{0,6}\t(.*\t.*)$")]
private static partial Regex REG_FORMAT2();
public QueryStagedChangesWithAmend(string repo, string parent)
@@ -34,7 +34,7 @@ namespace SourceGit.Commands
{
var change = new Models.Change()
{
Path = match.Groups[3].Value,
Path = match.Groups[4].Value,
DataForAmend = new Models.ChangeDataForAmend()
{
FileMode = match.Groups[1].Value,
@@ -42,7 +42,8 @@ namespace SourceGit.Commands
ParentSHA = _parent,
},
};
change.Set(Models.ChangeState.Renamed);
var type = match.Groups[3].Value;
change.Set(type == "R" ? Models.ChangeState.Renamed : Models.ChangeState.Copied);
changes.Add(change);
continue;
}
@@ -67,9 +68,6 @@ namespace SourceGit.Commands
case "A":
change.Set(Models.ChangeState.Added);
break;
case "C":
change.Set(Models.ChangeState.Copied);
break;
case "D":
change.Set(Models.ChangeState.Deleted);
break;

View File

@@ -13,7 +13,7 @@
{
WorkingDirectory = repo;
Context = repo;
Args = $"reset HEAD --pathspec-from-file={pathspec.Quoted()}";
Args = $"reset --pathspec-from-file={pathspec.Quoted()}";
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
@@ -29,7 +28,6 @@ namespace SourceGit.Commands
if (line.StartsWith("worktree ", StringComparison.Ordinal))
{
last = new Models.Worktree() { FullPath = line.Substring(9).Trim() };
last.RelativePath = Path.GetRelativePath(WorkingDirectory, last.FullPath);
worktrees.Add(last);
continue;
}
@@ -39,8 +37,7 @@ namespace SourceGit.Commands
if (line.StartsWith("bare", StringComparison.Ordinal))
{
worktrees.Remove(last);
last = null;
last.IsBare = true;
}
else if (line.StartsWith("HEAD ", StringComparison.Ordinal))
{

View File

@@ -6,7 +6,7 @@ namespace SourceGit.Converters
public static class InteractiveRebaseActionConverters
{
public static readonly FuncValueConverter<Models.InteractiveRebaseAction, IBrush> ToIconBrush =
new FuncValueConverter<Models.InteractiveRebaseAction, IBrush>(v =>
new(v =>
{
return v switch
{
@@ -20,6 +20,12 @@ namespace SourceGit.Converters
});
public static readonly FuncValueConverter<Models.InteractiveRebaseAction, string> ToName =
new FuncValueConverter<Models.InteractiveRebaseAction, string>(v => v.ToString());
new(v => v.ToString());
public static readonly FuncValueConverter<Models.InteractiveRebaseAction, bool> IsDrop =
new(v => v == Models.InteractiveRebaseAction.Drop);
public static readonly FuncValueConverter<Models.InteractiveRebaseAction, double> ToOpacity =
new(v => v > Models.InteractiveRebaseAction.Reword ? 0.65 : 1.0);
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
namespace SourceGit.Models
{
@@ -10,7 +9,6 @@ namespace SourceGit.Models
public string File { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public ulong Timestamp { get; set; } = 0;
public string Time => DateTime.UnixEpoch.AddSeconds(Timestamp).ToLocalTime().ToString(DateTimeFormat.Active.DateOnly);
}
public class BlameData

View File

@@ -60,7 +60,7 @@
Index = index;
WorkTree = workTree;
if (index == ChangeState.Renamed || workTree == ChangeState.Renamed)
if (index == ChangeState.Renamed || index == ChangeState.Copied || workTree == ChangeState.Renamed)
{
var parts = Path.Split('\t', 2);
if (parts.Length < 2)

View File

@@ -30,11 +30,6 @@ namespace SourceGit.Models
public int Color { get; set; } = 0;
public double LeftMargin { get; set; } = 0;
public string AuthorTimeStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString(DateTimeFormat.Active.DateTime);
public string CommitterTimeStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString(DateTimeFormat.Active.DateTime);
public string AuthorTimeShortStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString(DateTimeFormat.Active.DateOnly);
public string CommitterTimeShortStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString(DateTimeFormat.Active.DateOnly);
public bool IsCommitterVisible => !Author.Equals(Committer) || AuthorTime != CommitterTime;
public bool IsCurrentHead => Decorators.Find(x => x.Type is DecoratorType.CurrentBranchHead or DecoratorType.CurrentCommitHead) != null;
public bool HasDecorators => Decorators.Count > 0;

View File

@@ -3,6 +3,7 @@
public enum ConfirmEmptyCommitResult
{
Cancel = 0,
StageSelectedAndCommit,
StageAllAndCommit,
CreateEmptyCommit,
}

View File

@@ -5,19 +5,20 @@ namespace SourceGit.Models
{
public class DateTimeFormat
{
public string DateOnly { get; set; }
public string DateTime { get; set; }
public string Example
public static readonly List<DateTimeFormat> Supported = new List<DateTimeFormat>
{
get => _example.ToString(DateTime);
}
public DateTimeFormat(string dateOnly, string dateTime)
{
DateOnly = dateOnly;
DateTime = dateTime;
}
new("yyyy/MM/dd"),
new("yyyy.MM.dd"),
new("yyyy-MM-dd"),
new("MM/dd/yyyy"),
new("MM.dd.yyyy"),
new("MM-dd-yyyy"),
new("dd/MM/yyyy"),
new("dd.MM.yyyy"),
new("dd-MM-yyyy"),
new("MMM d yyyy"),
new("d MMM yyyy"),
};
public static int ActiveIndex
{
@@ -25,26 +26,41 @@ namespace SourceGit.Models
set;
} = 0;
public static DateTimeFormat Active
public static bool Use24Hours
{
get => Supported[ActiveIndex];
get;
set;
} = true;
public string DateFormat
{
get;
}
public static readonly List<DateTimeFormat> Supported = new List<DateTimeFormat>
public string Example
{
new DateTimeFormat("yyyy/MM/dd", "yyyy/MM/dd, HH:mm:ss"),
new DateTimeFormat("yyyy.MM.dd", "yyyy.MM.dd, HH:mm:ss"),
new DateTimeFormat("yyyy-MM-dd", "yyyy-MM-dd, HH:mm:ss"),
new DateTimeFormat("MM/dd/yyyy", "MM/dd/yyyy, HH:mm:ss"),
new DateTimeFormat("MM.dd.yyyy", "MM.dd.yyyy, HH:mm:ss"),
new DateTimeFormat("MM-dd-yyyy", "MM-dd-yyyy, HH:mm:ss"),
new DateTimeFormat("dd/MM/yyyy", "dd/MM/yyyy, HH:mm:ss"),
new DateTimeFormat("dd.MM.yyyy", "dd.MM.yyyy, HH:mm:ss"),
new DateTimeFormat("dd-MM-yyyy", "dd-MM-yyyy, HH:mm:ss"),
new DateTimeFormat("MMM d yyyy", "MMM d yyyy, HH:mm:ss"),
new DateTimeFormat("d MMM yyyy", "d MMM yyyy, HH:mm:ss"),
};
get => DateTime.Now.ToString(DateFormat);
}
private static readonly DateTime _example = new DateTime(2025, 1, 31, 8, 0, 0, DateTimeKind.Local);
public DateTimeFormat(string date)
{
DateFormat = date;
}
public static string Format(ulong timestamp, bool dateOnly = false)
{
var localTime = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime();
return Format(localTime, dateOnly);
}
public static string Format(DateTime localTime, bool dateOnly = false)
{
var actived = Supported[ActiveIndex];
if (dateOnly)
return localTime.ToString(actived.DateFormat);
var format = Use24Hours ? $"{actived.DateFormat} HH:mm:ss" : $"{actived.DateFormat} hh:mm:ss tt";
return localTime.ToString(format);
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Text;
namespace SourceGit.Models
@@ -79,6 +80,63 @@ namespace SourceGit.Models
_path = file;
}
/// <summary>
/// Used to diff in `FileHistory`
/// </summary>
/// <param name="ver"></param>
public DiffOption(FileVersion ver)
{
if (string.IsNullOrEmpty(ver.OriginalPath))
{
_revisions.Add(ver.HasParent ? $"{ver.SHA}^" : Commit.EmptyTreeSHA1);
_revisions.Add(ver.SHA);
_path = ver.Path;
}
else
{
_revisions.Add($"{ver.SHA}^:{ver.OriginalPath.Quoted()}");
_revisions.Add($"{ver.SHA}:{ver.Path.Quoted()}");
_path = ver.Path;
_orgPath = ver.Change.OriginalPath;
_ignorePaths = true;
}
}
/// <summary>
/// Used to diff two revisions in `FileHistory`
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
public DiffOption(FileVersion start, FileVersion end)
{
if (start.Change.Index == ChangeState.Deleted)
{
_revisions.Add(Commit.EmptyTreeSHA1);
_revisions.Add(end.SHA);
_path = end.Path;
}
else if (end.Change.Index == ChangeState.Deleted)
{
_revisions.Add(start.SHA);
_revisions.Add(Commit.EmptyTreeSHA1);
_path = start.Path;
}
else if (!end.Path.Equals(start.Path, StringComparison.Ordinal))
{
_revisions.Add($"{start.SHA}:{start.Path.Quoted()}");
_revisions.Add($"{end.SHA}:{end.Path.Quoted()}");
_path = end.Path;
_orgPath = start.Path;
_ignorePaths = true;
}
else
{
_revisions.Add(start.SHA);
_revisions.Add(end.SHA);
_path = start.Path;
}
}
/// <summary>
/// Used to show differences between two revisions.
/// </summary>
@@ -104,6 +162,9 @@ namespace SourceGit.Models
foreach (var r in _revisions)
builder.Append($"{r} ");
if (_ignorePaths)
return builder.ToString();
builder.Append("-- ");
if (!string.IsNullOrEmpty(_orgPath))
builder.Append($"{_orgPath.Quoted()} ");
@@ -118,5 +179,6 @@ namespace SourceGit.Models
private readonly string _orgPath = string.Empty;
private readonly string _extra = string.Empty;
private readonly List<string> _revisions = [];
private readonly bool _ignorePaths = false;
}
}

View File

@@ -124,9 +124,9 @@ namespace SourceGit.Models
continue;
if (i >= selection.StartLine - 1 && i < selection.EndLine)
writer.WriteLine($"+{line.Content}");
WriteLine(writer, '+', line);
else
writer.WriteLine($" {line.Content}");
WriteLine(writer, ' ', line);
}
}
else
@@ -137,11 +137,10 @@ namespace SourceGit.Models
var line = Lines[i];
if (line.Type != TextDiffLineType.Added)
continue;
writer.WriteLine($"+{line.Content}");
WriteLine(writer, '+', line);
}
}
writer.WriteLine("\\ No newline at end of file");
writer.Flush();
}
@@ -255,7 +254,8 @@ namespace SourceGit.Models
}
}
writer.WriteLine($" {tail}");
if (!string.IsNullOrEmpty(tail))
writer.WriteLine($" {tail}");
writer.Flush();
}
@@ -406,7 +406,8 @@ namespace SourceGit.Models
}
}
writer.WriteLine($" {tail}");
if (!string.IsNullOrEmpty(tail))
writer.WriteLine($" {tail}");
writer.Flush();
}

View File

@@ -230,10 +230,14 @@ namespace SourceGit.Models
return null;
var options = new List<ExternalTool.LaunchOption>();
var prefixLen = root.FullName.Length;
root.WalkFiles(f =>
{
if (f.EndsWith(".code-workspace", StringComparison.OrdinalIgnoreCase))
options.Add(new(root.GetRelativePath(f), f.Quoted()));
{
var display = f.Substring(prefixLen).TrimStart(Path.DirectorySeparatorChar);
options.Add(new(display, f.Quoted()));
}
}, 2);
return options;
}

14
src/Models/FileVersion.cs Normal file
View File

@@ -0,0 +1,14 @@
namespace SourceGit.Models
{
public class FileVersion
{
public string SHA { get; set; } = string.Empty;
public bool HasParent { get; set; } = false;
public User Author { get; set; } = User.Invalid;
public ulong AuthorTime { get; set; } = 0;
public string Subject { get; set; } = string.Empty;
public Change Change { get; set; } = new();
public string Path => Change.Path;
public string OriginalPath => Change.OriginalPath;
}
}

View File

@@ -28,7 +28,7 @@ namespace SourceGit.Models
public bool IsNewVersion => CurrentVersion.CompareTo(new System.Version(TagName.Substring(1))) < 0;
[JsonIgnore]
public string ReleaseDateStr => PublishedAt.ToString(DateTimeFormat.Active.DateOnly);
public string ReleaseDateStr => DateTimeFormat.Format(PublishedAt, true);
public Version()
{

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
namespace SourceGit.Models
{
@@ -10,24 +9,6 @@ namespace SourceGit.Models
public List<string> Parents { get; set; } = [];
public ulong Time { get; set; } = 0;
public string Message { get; set; } = "";
public string Subject
{
get
{
return Message.Split('\n', 2)[0].Trim();
}
}
public string TimeStr
{
get
{
return DateTime.UnixEpoch
.AddSeconds(Time)
.ToLocalTime()
.ToString(DateTimeFormat.Active.DateTime);
}
}
public string Subject => Message.Split('\n', 2)[0].Trim();
}
}

View File

@@ -1,6 +1,4 @@
using System;
namespace SourceGit.Models
namespace SourceGit.Models
{
public enum TagSortMode
{
@@ -16,10 +14,5 @@ namespace SourceGit.Models
public User Creator { get; set; } = null;
public ulong CreatorDate { get; set; } = 0;
public string Message { get; set; } = string.Empty;
public string CreatorDateStr
{
get => DateTime.UnixEpoch.AddSeconds(CreatorDate).ToLocalTime().ToString(DateTimeFormat.Active.DateTime);
}
}
}

View File

@@ -1,39 +1,12 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.Models
{
public class Worktree : ObservableObject
public class Worktree
{
public string Branch { get; set; } = string.Empty;
public string FullPath { get; set; } = string.Empty;
public string RelativePath { get; set; } = string.Empty;
public string Head { get; set; } = string.Empty;
public bool IsBare { get; set; } = false;
public bool IsDetached { get; set; } = false;
public bool IsLocked
{
get => _isLocked;
set => SetProperty(ref _isLocked, value);
}
public string Name
{
get
{
if (IsDetached)
return $"detached HEAD at {Head.AsSpan(10)}";
if (Branch.StartsWith("refs/heads/", StringComparison.Ordinal))
return Branch.Substring(11);
if (Branch.StartsWith("refs/remotes/", StringComparison.Ordinal))
return Branch.Substring(13);
return Branch;
}
}
private bool _isLocked = false;
public bool IsLocked { get; set; } = false;
}
}

View File

@@ -234,11 +234,15 @@ namespace SourceGit.Native
return null;
var options = new List<Models.ExternalTool.LaunchOption>();
var prefixLen = root.FullName.Length;
root.WalkFiles(f =>
{
if (f.EndsWith(".sln", StringComparison.OrdinalIgnoreCase) ||
f.EndsWith(".slnx", StringComparison.OrdinalIgnoreCase))
options.Add(new(root.GetRelativePath(f), f.Quoted()));
{
var display = f.Substring(prefixLen).TrimStart(Path.DirectorySeparatorChar);
options.Add(new(display, f.Quoted()));
}
});
return options;
}

View File

@@ -134,6 +134,10 @@
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">Repository URL:</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">CLOSE</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Editor</x:String>
<x:String x:Key="Text.CommandPalette.Branches" xml:space="preserve">Branches</x:String>
<x:String x:Key="Text.CommandPalette.BranchesAndTags" xml:space="preserve">Branches &amp; Tags</x:String>
<x:String x:Key="Text.CommandPalette.RepositoryActions" xml:space="preserve">Repository Custom Actions</x:String>
<x:String x:Key="Text.CommandPalette.RevisionFiles" xml:space="preserve">Revision Files</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Checkout Commit</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Cherry-Pick Commit</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick ...</x:String>
@@ -277,7 +281,8 @@
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">CONTINUE</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">Empty commit detected! Do you want to continue (--allow-empty)?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">STAGE ALL &amp; COMMIT</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">Empty commit detected! Do you want to continue (--allow-empty) or stage all then commit?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageSelectedThenCommit" xml:space="preserve">STAGE SELECTED &amp; COMMIT</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">Empty commit detected! Do you want to continue (--allow-empty) or auto-stage then commit?</x:String>
<x:String x:Key="Text.ConfirmRestart.Title" xml:space="preserve">Restart Required</x:String>
<x:String x:Key="Text.ConfirmRestart.Message" xml:space="preserve">You need to restart this app to apply changes.</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Conventional Commit Helper</x:String>
@@ -309,7 +314,7 @@
<x:String x:Key="Text.CreateTag.Name" xml:space="preserve">Tag Name:</x:String>
<x:String x:Key="Text.CreateTag.Name.Placeholder" xml:space="preserve">Recommended format: v1.0.0-alpha</x:String>
<x:String x:Key="Text.CreateTag.PushToAllRemotes" xml:space="preserve">Push to all remotes after created</x:String>
<x:String x:Key="Text.CreateTag.Title" xml:space="preserve">Create New Tag</x:String>
<x:String x:Key="Text.CreateTag.Title" xml:space="preserve">Create Tag</x:String>
<x:String x:Key="Text.CreateTag.Type" xml:space="preserve">Kind:</x:String>
<x:String x:Key="Text.CreateTag.Type.Annotated" xml:space="preserve">annotated</x:String>
<x:String x:Key="Text.CreateTag.Type.Lightweight" xml:space="preserve">lightweight</x:String>
@@ -519,6 +524,8 @@
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Stage</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Unstage</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Initialize Repository</x:String>
<x:String x:Key="Text.Init.CommandTip" xml:space="preserve">Do you want to run `git init` command under this path?</x:String>
<x:String x:Key="Text.Init.ErrorMessageTip" xml:space="preserve">Open repository failed. Reason: </x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Path:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick in progress.</x:String>
<x:String x:Key="Text.InProgress.CherryPick.Head" xml:space="preserve">Processing commit</x:String>
@@ -642,6 +649,7 @@
<x:String x:Key="Text.Preferences.General.ShowChildren" xml:space="preserve">Show children in the commit details</x:String>
<x:String x:Key="Text.Preferences.General.ShowTagsInGraph" xml:space="preserve">Show tags in commit graph</x:String>
<x:String x:Key="Text.Preferences.General.SubjectGuideLength" xml:space="preserve">Subject Guide Length</x:String>
<x:String x:Key="Text.Preferences.General.Use24Hours" xml:space="preserve">24-Hours</x:String>
<x:String x:Key="Text.Preferences.General.UseGitHubStyleAvatar" xml:space="preserve">Generate Github style default avatar</x:String>
<x:String x:Key="Text.Preferences.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preferences.Git.CRLF" xml:space="preserve">Enable Auto CRLF</x:String>
@@ -969,9 +977,12 @@
<x:String x:Key="Text.Workspace" xml:space="preserve">WORKSPACE: </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Configure Workspaces...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">WORKTREE</x:String>
<x:String x:Key="Text.Worktree.Branch" xml:space="preserve">BRANCH</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Copy Path</x:String>
<x:String x:Key="Text.Worktree.Head" xml:space="preserve">HEAD</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Lock</x:String>
<x:String x:Key="Text.Worktree.Open" xml:space="preserve">Open</x:String>
<x:String x:Key="Text.Worktree.Path" xml:space="preserve">PATH</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">Remove</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">Unlock</x:String>
<x:String x:Key="Text.Yes" xml:space="preserve">YES</x:String>

View File

@@ -138,6 +138,10 @@
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">URL del Repositorio:</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">CERRAR</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Editor</x:String>
<x:String x:Key="Text.CommandPalette.Branches" xml:space="preserve">Ramas</x:String>
<x:String x:Key="Text.CommandPalette.BranchesAndTags" xml:space="preserve">Ramas &amp; Etiquetas</x:String>
<x:String x:Key="Text.CommandPalette.RepositoryActions" xml:space="preserve">Acciones Personalizadas del Repositorio</x:String>
<x:String x:Key="Text.CommandPalette.RevisionFiles" xml:space="preserve">Archivos de Revisión</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Checkout Commit</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Cherry-Pick Este Commit</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick ...</x:String>
@@ -281,6 +285,7 @@
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">CONTINUAR</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">¡Commit vacío detectado! ¿Quieres continuar (--allow-empty)?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">HACER STAGE A TODO &amp; COMMIT</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageSelectedThenCommit" xml:space="preserve">STAGE LO SELECCIONADO &amp; COMMIT</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">¡Commit vacío detectado! ¿Quieres continuar (--allow-empty) o hacer stage a todo y después commit?</x:String>
<x:String x:Key="Text.ConfirmRestart.Title" xml:space="preserve">Reinicio Requerido</x:String>
<x:String x:Key="Text.ConfirmRestart.Message" xml:space="preserve">Necesita reiniciar esta aplicación para aplicar los cambios.</x:String>
@@ -473,6 +478,7 @@
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Remoto:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Seguir archivos llamados '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Seguir todos los archivos *{0}</x:String>
<x:String x:Key="Text.GotoRevisionSelector" xml:space="preserve">Seleccionar Commit</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">Historias</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">AUTOR</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">HORA DEL AUTOR</x:String>
@@ -502,6 +508,7 @@
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Stage todos los cambios y commit</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, empieza directamente</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Modo Dashboard (Por Defecto)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToChild" xml:space="preserve">Ir al hijo del commit seleccionado</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToParent" xml:space="preserve">Ir al padre del commit seleccionado</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenCommandPalette" xml:space="preserve">Abrir paleta de comandos</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Modo de búsqueda de commits</x:String>
@@ -521,6 +528,8 @@
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Stage</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Unstage</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Inicializar Repositorio</x:String>
<x:String x:Key="Text.Init.CommandTip" xml:space="preserve">¿Quieres correr el comando `git init` en esta ruta?</x:String>
<x:String x:Key="Text.Init.ErrorMessageTip" xml:space="preserve">Falló la apertura del repositorio. Razón: </x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Ruta:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick en progreso.</x:String>
<x:String x:Key="Text.InProgress.CherryPick.Head" xml:space="preserve">Procesando commit</x:String>
@@ -853,6 +862,7 @@
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">¡Tanto los cambios staged como los no staged de los archivos seleccionados serán stashed!</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Stash Cambios Locales</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Aplicar</x:String>
<x:String x:Key="Text.StashCM.ApplyFileChanges" xml:space="preserve">Aplicar Cambios</x:String>
<x:String x:Key="Text.StashCM.CopyMessage" xml:space="preserve">Copiar Mensaje</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Eliminar</x:String>
<x:String x:Key="Text.StashCM.SaveAsPatch" xml:space="preserve">Guardar como Parche...</x:String>
@@ -970,9 +980,12 @@
<x:String x:Key="Text.Workspace" xml:space="preserve">ESPACIO DE TRABAJO: </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Configura Espacios de Trabajo...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">WORKTREE</x:String>
<x:String x:Key="Text.Worktree.Branch" xml:space="preserve">RAMA</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Copiar Ruta</x:String>
<x:String x:Key="Text.Worktree.Head" xml:space="preserve">HEAD</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Bloquear</x:String>
<x:String x:Key="Text.Worktree.Open" xml:space="preserve">Abrir</x:String>
<x:String x:Key="Text.Worktree.Path" xml:space="preserve">RUTA</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">Eliminar</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">Desbloquear</x:String>
<x:String x:Key="Text.Yes" xml:space="preserve">SÍ</x:String>

View File

@@ -473,6 +473,7 @@
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Внешнее хранилище:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Отслеживать файлы с именем «{0}»</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Отслеживать все файлы (*{0})</x:String>
<x:String x:Key="Text.GotoRevisionSelector" xml:space="preserve">Выбрать ревизию</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">Истории</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">АВТОР</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">ВРЕМЯ АВТОРА</x:String>
@@ -502,7 +503,8 @@
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Сформировать все изменения и зафиксировать</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Извлечь (fetch), запускается сразу</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Режим доски (по умолчанию)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToParent" xml:space="preserve">Перейти к родительскому выбранной ревизии</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToChild" xml:space="preserve">К дочернему выбранной ревизии</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToParent" xml:space="preserve">К родительскому выбранной ревизии</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenCommandPalette" xml:space="preserve">Открыть палитру команд</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Режим поиска ревизий</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Загрузить (pull), запускается сразу</x:String>
@@ -853,6 +855,7 @@
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">Сформированные так и несформированные изменения выбранных файлов будут сохранены!!!</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Отложить локальные изменения</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Принять</x:String>
<x:String x:Key="Text.StashCM.ApplyFileChanges" xml:space="preserve">Применить изменения</x:String>
<x:String x:Key="Text.StashCM.CopyMessage" xml:space="preserve">Копировать сообщение</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Отбросить</x:String>
<x:String x:Key="Text.StashCM.SaveAsPatch" xml:space="preserve">Сохранить как заплатку...</x:String>
@@ -970,9 +973,12 @@
<x:String x:Key="Text.Workspace" xml:space="preserve">РАБОЧЕЕ ПРОСТРАНСТВО: </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Настройка рабочего пространства...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">РАБОЧИЙ КАТАЛОГ</x:String>
<x:String x:Key="Text.Worktree.Branch" xml:space="preserve">ВЕТКА</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Копировать путь</x:String>
<x:String x:Key="Text.Worktree.Head" xml:space="preserve">ГОЛОВА</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Заблокировать</x:String>
<x:String x:Key="Text.Worktree.Open" xml:space="preserve">Открыть</x:String>
<x:String x:Key="Text.Worktree.Path" xml:space="preserve">ПУТЬ</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">Удалить</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">Разблокировать</x:String>
<x:String x:Key="Text.Yes" xml:space="preserve">Да</x:String>

View File

@@ -138,6 +138,10 @@
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">远程仓库 </x:String>
<x:String x:Key="Text.Close" xml:space="preserve">关闭</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">提交信息编辑器</x:String>
<x:String x:Key="Text.CommandPalette.Branches" xml:space="preserve">分支列表</x:String>
<x:String x:Key="Text.CommandPalette.BranchesAndTags" xml:space="preserve">分支 &amp; 标签</x:String>
<x:String x:Key="Text.CommandPalette.RepositoryActions" xml:space="preserve">自定义操作列表</x:String>
<x:String x:Key="Text.CommandPalette.RevisionFiles" xml:space="preserve">文件列表</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">检出此提交</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">挑选(cherry-pick)此提交</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">挑选(cherry-pick)...</x:String>
@@ -280,8 +284,9 @@
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">启动时恢复打开的仓库</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">确认继续</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">提交未包含变更文件!是否继续(--allow-empty)</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">自动暂存并提交</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">提交未包含变更文件!是否继续(--allow-empty)或是自动暂存所变更并提交</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">暂存所有变更并提交</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageSelectedThenCommit" xml:space="preserve">仅暂存所变更并提交</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">提交未包含变更文件!是否继续(--allow-empty)或是自动暂存变更并提交?</x:String>
<x:String x:Key="Text.ConfirmRestart.Title" xml:space="preserve">系统提示</x:String>
<x:String x:Key="Text.ConfirmRestart.Message" xml:space="preserve">程序需要重新启动,以便修改生效!</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">规范化提交信息生成</x:String>
@@ -523,6 +528,8 @@
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">暂存</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">移出暂存区</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">初始化新仓库</x:String>
<x:String x:Key="Text.Init.CommandTip" xml:space="preserve">是否在该路径下执行 `git init` 命令(初始化仓库)?</x:String>
<x:String x:Key="Text.Init.ErrorMessageTip" xml:space="preserve">打开本地仓库失败,原因:</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">路径 </x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">挑选Cherry-Pick操作进行中。</x:String>
<x:String x:Key="Text.InProgress.CherryPick.Head" xml:space="preserve">正在处理提交</x:String>
@@ -646,6 +653,7 @@
<x:String x:Key="Text.Preferences.General.ShowChildren" xml:space="preserve">在提交详情页中显示子提交列表</x:String>
<x:String x:Key="Text.Preferences.General.ShowTagsInGraph" xml:space="preserve">在提交路线图中显示标签</x:String>
<x:String x:Key="Text.Preferences.General.SubjectGuideLength" xml:space="preserve">SUBJECT字数检测</x:String>
<x:String x:Key="Text.Preferences.General.Use24Hours" xml:space="preserve">24小时制</x:String>
<x:String x:Key="Text.Preferences.General.UseGitHubStyleAvatar" xml:space="preserve">生成GitHub风格的默认头像</x:String>
<x:String x:Key="Text.Preferences.Git" xml:space="preserve">GIT配置</x:String>
<x:String x:Key="Text.Preferences.Git.CRLF" xml:space="preserve">自动换行转换</x:String>
@@ -973,9 +981,12 @@
<x:String x:Key="Text.Workspace" xml:space="preserve">工作区:</x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">配置工作区...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">本地工作树</x:String>
<x:String x:Key="Text.Worktree.Branch" xml:space="preserve">連結分支</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">复制工作树路径</x:String>
<x:String x:Key="Text.Worktree.Head" xml:space="preserve">最新提交</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">锁定工作树</x:String>
<x:String x:Key="Text.Worktree.Open" xml:space="preserve">打开工作树</x:String>
<x:String x:Key="Text.Worktree.Path" xml:space="preserve">位置</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">移除工作树</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">解除工作树锁定</x:String>
<x:String x:Key="Text.Yes" xml:space="preserve">好的</x:String>

View File

@@ -138,6 +138,10 @@
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">遠端存放庫:</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">關閉</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">提交訊息編輯器</x:String>
<x:String x:Key="Text.CommandPalette.Branches" xml:space="preserve">分支列表</x:String>
<x:String x:Key="Text.CommandPalette.BranchesAndTags" xml:space="preserve">分支 &amp; 標籤</x:String>
<x:String x:Key="Text.CommandPalette.RepositoryActions" xml:space="preserve">自訂動作</x:String>
<x:String x:Key="Text.CommandPalette.RevisionFiles" xml:space="preserve">檔案列表</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">簽出 (checkout) 此提交</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">揀選 (cherry-pick) 此提交</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">揀選 (cherry-pick)...</x:String>
@@ -280,8 +284,9 @@
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">啟動時還原上次開啟的存放庫</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">確認繼續</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">未包含任何檔案變更! 您是否仍要提交 (--allow-empty)?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">自動暫存並提交</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">未包含任何檔案變更! 您是否仍要提交 (--allow-empty) 或者自動暫存全部變更提交?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">暫存全部變更並提交</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageSelectedThenCommit" xml:space="preserve">僅暫存所選變更提交</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">未包含任何檔案變更! 您是否仍要提交 (--allow-empty) 或者自動暫存變更並提交?</x:String>
<x:String x:Key="Text.ConfirmRestart.Title" xml:space="preserve">系統提示</x:String>
<x:String x:Key="Text.ConfirmRestart.Message" xml:space="preserve">您需要重新啟動此應用程式才能套用變更!</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">產生約定式提交訊息</x:String>
@@ -523,6 +528,8 @@
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">暫存</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">取消暫存</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">初始化存放庫</x:String>
<x:String x:Key="Text.Init.CommandTip" xml:space="preserve">在該路徑執行 git init 以初始化 git 倉庫?</x:String>
<x:String x:Key="Text.Init.ErrorMessageTip" xml:space="preserve">無法在指定路徑開啟本機儲存庫。原因:</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">路徑:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">揀選 (cherry-pick) 操作進行中。</x:String>
<x:String x:Key="Text.InProgress.CherryPick.Head" xml:space="preserve">正在處理提交</x:String>
@@ -646,6 +653,7 @@
<x:String x:Key="Text.Preferences.General.ShowChildren" xml:space="preserve">在提交詳細資訊中顯示後續提交</x:String>
<x:String x:Key="Text.Preferences.General.ShowTagsInGraph" xml:space="preserve">在路線圖中顯示標籤</x:String>
<x:String x:Key="Text.Preferences.General.SubjectGuideLength" xml:space="preserve">提交標題字數偵測</x:String>
<x:String x:Key="Text.Preferences.General.Use24Hours" xml:space="preserve">24小時制</x:String>
<x:String x:Key="Text.Preferences.General.UseGitHubStyleAvatar" xml:space="preserve">產生 GitHub 風格的預設頭貼</x:String>
<x:String x:Key="Text.Preferences.Git" xml:space="preserve">Git 設定</x:String>
<x:String x:Key="Text.Preferences.Git.CRLF" xml:space="preserve">自動換行轉換</x:String>
@@ -973,9 +981,12 @@
<x:String x:Key="Text.Workspace" xml:space="preserve">工作區: </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">設定工作區...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">本機工作區</x:String>
<x:String x:Key="Text.Worktree.Branch" xml:space="preserve">关联分支</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">複製工作區路徑</x:String>
<x:String x:Key="Text.Worktree.Head" xml:space="preserve">最新提交</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">鎖定工作區</x:String>
<x:String x:Key="Text.Worktree.Open" xml:space="preserve">開啟工作區</x:String>
<x:String x:Key="Text.Worktree.Path" xml:space="preserve">位置</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">移除工作區</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">解除鎖定工作區</x:String>
<x:String x:Key="Text.Yes" xml:space="preserve">是</x:String>

View File

@@ -182,6 +182,14 @@
<Setter Property="FontSize" Value="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize}"/>
</Style>
<Style Selector="AdornerLayer">
<Setter Property="DefaultFocusAdorner">
<FocusAdornerTemplate>
<Rectangle Margin="0" Stroke="{DynamicResource Brush.FG1}" StrokeDashArray="1,2" StrokeThickness="1"/>
</FocusAdornerTemplate>
</Setter>
</Style>
<Style Selector="ToolTip">
<Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/>
<Setter Property="Background" Value="{DynamicResource Brush.Popup}"/>
@@ -190,9 +198,8 @@
<Setter Property="TextBlock.TextDecorations" Value=""/>
<Setter Property="Template">
<ControlTemplate>
<Grid Effect="drop-shadow(0 0 8 #30000000)">
<Border Margin="8"
Padding="8,6"
<Grid Margin="8" Effect="drop-shadow(0 0 8 #30000000)">
<Border Padding="8,6"
CornerRadius="4"
Background="{DynamicResource Brush.Popup}"
BorderBrush="{DynamicResource Brush.Border2}"
@@ -219,17 +226,10 @@
<Setter Property="Template">
<ControlTemplate>
<Grid>
<Border Background="{DynamicResource Brush.Popup}" BorderThickness="0" Margin="4" CornerRadius="{TemplateBinding CornerRadius}">
<Border.Effect>
<DropShadowEffect OffsetX="0" OffsetY="0" BlurRadius="4" Color="Black" Opacity=".6"/>
</Border.Effect>
</Border>
<Grid Margin="4" Effect="drop-shadow(0 0 4 #A0000000)">
<Border Name="LayoutRoot"
Margin="4"
Padding="12"
Background="Transparent"
Background="{DynamicResource Brush.Popup}"
BorderThickness="0"
CornerRadius="{TemplateBinding CornerRadius}">
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
@@ -524,6 +524,9 @@
<Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/>
<Setter Property="Opacity" Value=".56"/>
</Style>
<Style Selector="TextBlock.dropped">
<Setter Property="TextDecorations" Value="Strikethrough"/>
</Style>
<Style Selector="Run.issue_link">
<Setter Property="Foreground" Value="{DynamicResource Brush.Link}"/>
@@ -813,15 +816,11 @@
<Setter Property="VerticalOffset" Value="-4"/>
<Setter Property="Template">
<ControlTemplate>
<Grid>
<Border Background="{DynamicResource Brush.Popup}" BorderThickness="0" Margin="4" CornerRadius="{TemplateBinding CornerRadius}">
<Border.Effect>
<DropShadowEffect OffsetX="0" OffsetY="0" BlurRadius="4" Color="Black" Opacity=".6"/>
</Border.Effect>
</Border>
<Grid Margin="4" Effect="drop-shadow(0 0 4 #A0000000)">
<Border BorderThickness="0"
Margin="8,4"
Background="{DynamicResource Brush.Popup}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="8,4"
MaxWidth="{TemplateBinding MaxWidth}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
@@ -841,16 +840,9 @@
<Style Selector="MenuFlyoutPresenter">
<Setter Property="Template">
<ControlTemplate>
<Grid>
<Border Background="{DynamicResource Brush.Popup}" BorderThickness="0" Margin="4" CornerRadius="{TemplateBinding CornerRadius}">
<Border.Effect>
<DropShadowEffect OffsetX="0" OffsetY="0" BlurRadius="4" Color="Black" Opacity=".6"/>
</Border.Effect>
</Border>
<Grid Margin="4" Effect="drop-shadow(0 0 4 #A0000000)">
<Border Name="LayoutRoot"
Margin="4"
Background="Transparent"
Background="{DynamicResource Brush.Popup}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0"
Padding="4,2"
@@ -961,14 +953,8 @@
HorizontalOffset="-4"
VerticalOffset="-4"
IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}">
<Grid>
<Border Background="{DynamicResource Brush.Popup}" Margin="4" CornerRadius="{DynamicResource OverlayCornerRadius}">
<Border.Effect>
<DropShadowEffect OffsetX="0" OffsetY="0" Color="Black" BlurRadius="4" Opacity=".6"/>
</Border.Effect>
</Border>
<Border BorderThickness="0" Margin="8,4" MaxHeight="400">
<Grid Margin="4" Effect="drop-shadow(0 0 4 #A0000000)">
<Border BorderThickness="0" Padding="8,4" MaxHeight="400" Background="{DynamicResource Brush.Popup}" CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ItemsPresenter Name="PART_ItemsPresenter"
Margin="{DynamicResource MenuFlyoutScrollerMargin}"
@@ -1067,6 +1053,12 @@
</Style>
<Style Selector="CheckBox">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Border/>
</FocusAdornerTemplate>
</Setter>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Template">
<ControlTemplate>
@@ -1085,16 +1077,32 @@
</Grid>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Accent}"/>
</Style>
<Style Selector="^:checked /template/ Path#Icon">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="^:focus-visible /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Accent}"/>
<Setter Property="BorderThickness" Value="2"/>
</Style>
<Style Selector="^:focus-visible:checked /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Accent}"/>
<Setter Property="Background" Value="{DynamicResource Brush.Accent}"/>
</Style>
<Style Selector="^:focus-visible:checked /template/ Path#Icon">
<Setter Property="Fill" Value="White"/>
</Style>
</Style>
<Style Selector="RadioButton">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Border/>
</FocusAdornerTemplate>
</Setter>
<Setter Property="Template">
<ControlTemplate>
<Grid ColumnDefinitions="16,*" Background="Transparent">
@@ -1136,9 +1144,26 @@
<Style Selector="^:checked /template/ Ellipse#Dot">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}"/>
</Style>
<Style Selector="^:focus-visible /template/ Ellipse#Border">
<Setter Property="Stroke" Value="{DynamicResource Brush.Accent}"/>
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}"/>
</Style>
<Style Selector="^:focus-visible /template/ Ellipse#Dot">
<Setter Property="Stroke" Value="White"/>
<Setter Property="Fill" Value="White"/>
</Style>
<Style Selector="^:focus-visible:checked /template/ Ellipse#Dot">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}"/>
</Style>
</Style>
<Style Selector="RadioButton.switch_button">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Rectangle Margin="0" Stroke="{DynamicResource Brush.FG1}" StrokeDashArray="1,2" StrokeThickness="1"/>
</FocusAdornerTemplate>
</Setter>
<Setter Property="Height" Value="24"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>

View File

@@ -35,9 +35,8 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _selectedFile, value);
}
public BlameCommandPalette(Launcher launcher, string repo)
public BlameCommandPalette(string repo)
{
_launcher = launcher;
_repo = repo;
_isLoading = true;
@@ -61,17 +60,6 @@ namespace SourceGit.ViewModels
});
}
public override void Cleanup()
{
_launcher = null;
_repo = null;
_head = null;
_repoFiles.Clear();
_filter = null;
_visibleFiles.Clear();
_selectedFile = null;
}
public void ClearFilter()
{
Filter = string.Empty;
@@ -79,9 +67,12 @@ namespace SourceGit.ViewModels
public void Launch()
{
_repoFiles.Clear();
_visibleFiles.Clear();
Close();
if (!string.IsNullOrEmpty(_selectedFile))
App.ShowWindow(new Blame(_repo, _selectedFile, _head));
_launcher.CancelCommandPalette();
}
private void UpdateVisible()
@@ -117,7 +108,6 @@ namespace SourceGit.ViewModels
}
}
private Launcher _launcher = null;
private string _repo = null;
private bool _isLoading = false;
private Models.Commit _head = null;

View File

@@ -28,22 +28,12 @@ namespace SourceGit.ViewModels
}
}
public CheckoutCommandPalette(Launcher launcher, Repository repo)
public CheckoutCommandPalette(Repository repo)
{
_launcher = launcher;
_repo = repo;
UpdateBranches();
}
public override void Cleanup()
{
_launcher = null;
_repo = null;
_branches.Clear();
_selectedBranch = null;
_filter = null;
}
public void ClearFilter()
{
Filter = string.Empty;
@@ -51,13 +41,11 @@ namespace SourceGit.ViewModels
public async Task ExecAsync()
{
_launcher.CommandPalette = null;
_branches.Clear();
Close();
if (_selectedBranch != null)
await _repo.CheckoutBranchAsync(_selectedBranch);
Dispose();
GC.Collect();
}
private void UpdateBranches()
@@ -94,7 +82,6 @@ namespace SourceGit.ViewModels
SelectedBranch = autoSelected;
}
private Launcher _launcher;
private Repository _repo;
private List<Models.Branch> _branches = [];
private Models.Branch _selectedBranch = null;

View File

@@ -32,24 +32,13 @@ namespace SourceGit.ViewModels
}
}
public CompareCommandPalette(Launcher launcher, Repository repo, object basedOn)
public CompareCommandPalette(Repository repo, object basedOn)
{
_launcher = launcher;
_repo = repo;
_basedOn = basedOn ?? repo.CurrentBranch;
UpdateRefs();
}
public override void Cleanup()
{
_launcher = null;
_repo = null;
_basedOn = null;
_compareTo = null;
_refs.Clear();
_filter = null;
}
public void ClearFilter()
{
Filter = string.Empty;
@@ -57,9 +46,11 @@ namespace SourceGit.ViewModels
public void Launch()
{
_refs.Clear();
Close();
if (_compareTo != null)
App.ShowWindow(new Compare(_repo, _basedOn, _compareTo));
_launcher?.CancelCommandPalette();
}
private void UpdateRefs()
@@ -114,7 +105,6 @@ namespace SourceGit.ViewModels
CompareTo = autoSelected;
}
private Launcher _launcher;
private Repository _repo;
private object _basedOn = null;
private object _compareTo = null;

View File

@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace SourceGit.ViewModels
{
public class ExecuteCustomActionCommandPaletteCmd
{
public Models.CustomAction Action { get; set; }
public bool IsGlobal { get; set; }
public string Name { get => Action.Name; }
public ExecuteCustomActionCommandPaletteCmd(Models.CustomAction action, bool isGlobal)
{
Action = action;
IsGlobal = isGlobal;
}
}
public class ExecuteCustomActionCommandPalette : ICommandPalette
{
public List<ExecuteCustomActionCommandPaletteCmd> VisibleActions
{
get => _visibleActions;
private set => SetProperty(ref _visibleActions, value);
}
public ExecuteCustomActionCommandPaletteCmd Selected
{
get => _selected;
set => SetProperty(ref _selected, value);
}
public string Filter
{
get => _filter;
set
{
if (SetProperty(ref _filter, value))
UpdateVisibleActions();
}
}
public ExecuteCustomActionCommandPalette(Repository repo)
{
_repo = repo;
var actions = repo.GetCustomActions(Models.CustomActionScope.Repository);
foreach (var (action, menu) in actions)
_actions.Add(new(action, menu.IsGlobal));
if (_actions.Count > 0)
{
_actions.Sort((l, r) =>
{
if (l.IsGlobal != r.IsGlobal)
return l.IsGlobal ? -1 : 1;
return l.Name.CompareTo(r.Name, StringComparison.OrdinalIgnoreCase);
});
_visibleActions = _actions;
_selected = _actions[0];
}
}
public void ClearFilter()
{
Filter = string.Empty;
}
public async Task ExecAsync()
{
_actions.Clear();
_visibleActions.Clear();
Close();
if (_selected != null)
await _repo.ExecCustomActionAsync(_selected.Action, null);
}
private void UpdateVisibleActions()
{
var filter = _filter?.Trim();
if (string.IsNullOrEmpty(filter))
{
VisibleActions = _actions;
return;
}
var visible = new List<ExecuteCustomActionCommandPaletteCmd>();
foreach (var act in _actions)
{
if (act.Name.Contains(filter, StringComparison.OrdinalIgnoreCase))
visible.Add(act);
}
var autoSelected = _selected;
if (visible.Count == 0)
autoSelected = null;
else if (_selected == null || !visible.Contains(_selected))
autoSelected = visible[0];
VisibleActions = visible;
Selected = autoSelected;
}
private Repository _repo;
private List<ExecuteCustomActionCommandPaletteCmd> _actions = [];
private List<ExecuteCustomActionCommandPaletteCmd> _visibleActions = [];
private ExecuteCustomActionCommandPaletteCmd _selected = null;
private string _filter;
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Collections;
@@ -36,10 +35,10 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _viewContent, value);
}
public FileHistoriesSingleRevision(string repo, string file, Models.Commit revision, bool prevIsDiffMode)
public FileHistoriesSingleRevision(string repo, Models.FileVersion revision, bool prevIsDiffMode)
{
_repo = repo;
_file = file;
_file = revision.Path;
_revision = revision;
_isDiffMode = prevIsDiffMode;
_viewContent = null;
@@ -75,7 +74,7 @@ namespace SourceGit.ViewModels
{
if (_isDiffMode)
{
SetViewContentAsDiff();
ViewContent = new DiffContext(_repo, new(_revision), _viewContent as DiffContext);
return;
}
@@ -153,28 +152,22 @@ namespace SourceGit.ViewModels
return new FileHistoriesRevisionFile(_file);
}
private void SetViewContentAsDiff()
{
var option = new Models.DiffOption(_revision, _file);
ViewContent = new DiffContext(_repo, option, _viewContent as DiffContext);
}
private string _repo = null;
private string _file = null;
private Models.Commit _revision = null;
private Models.FileVersion _revision = null;
private bool _isDiffMode = false;
private object _viewContent = null;
}
public class FileHistoriesCompareRevisions : ObservableObject
{
public Models.Commit StartPoint
public Models.FileVersion StartPoint
{
get => _startPoint;
set => SetProperty(ref _startPoint, value);
}
public Models.Commit EndPoint
public Models.FileVersion EndPoint
{
get => _endPoint;
set => SetProperty(ref _endPoint, value);
@@ -186,19 +179,18 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _viewContent, value);
}
public FileHistoriesCompareRevisions(string repo, string file, Models.Commit start, Models.Commit end)
public FileHistoriesCompareRevisions(string repo, Models.FileVersion start, Models.FileVersion end)
{
_repo = repo;
_file = file;
_startPoint = start;
_endPoint = end;
RefreshViewContent();
_viewContent = new(_repo, new(start, end));
}
public void Swap()
{
(StartPoint, EndPoint) = (_endPoint, _startPoint);
RefreshViewContent();
ViewContent = new(_repo, new(_startPoint, _endPoint), _viewContent);
}
public async Task<bool> SaveAsPatch(string saveTo)
@@ -208,27 +200,9 @@ namespace SourceGit.ViewModels
.ConfigureAwait(false);
}
private void RefreshViewContent()
{
Task.Run(async () =>
{
_changes = await new Commands.CompareRevisions(_repo, _startPoint.SHA, _endPoint.SHA, _file).ReadAsync().ConfigureAwait(false);
if (_changes.Count == 0)
{
Dispatcher.UIThread.Post(() => ViewContent = null);
}
else
{
var option = new Models.DiffOption(_startPoint.SHA, _endPoint.SHA, _changes[0]);
Dispatcher.UIThread.Post(() => ViewContent = new DiffContext(_repo, option, _viewContent));
}
});
}
private string _repo = null;
private string _file = null;
private Models.Commit _startPoint = null;
private Models.Commit _endPoint = null;
private Models.FileVersion _startPoint = null;
private Models.FileVersion _endPoint = null;
private List<Models.Change> _changes = [];
private DiffContext _viewContent = null;
}
@@ -246,13 +220,13 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _isLoading, value);
}
public List<Models.Commit> Commits
public List<Models.FileVersion> Revisions
{
get => _commits;
set => SetProperty(ref _commits, value);
get => _revisions;
set => SetProperty(ref _revisions, value);
}
public AvaloniaList<Models.Commit> SelectedCommits
public AvaloniaList<Models.FileVersion> SelectedRevisions
{
get;
set;
@@ -275,41 +249,34 @@ namespace SourceGit.ViewModels
Task.Run(async () =>
{
var argsBuilder = new StringBuilder();
argsBuilder
.Append("--date-order -n 10000 ")
.Append(commit ?? string.Empty)
.Append(" -- ")
.Append(file.Quoted());
var commits = await new Commands.QueryCommits(_repo, argsBuilder.ToString(), false)
var revisions = await new Commands.QueryFileHistory(_repo, file, commit)
.GetResultAsync()
.ConfigureAwait(false);
Dispatcher.UIThread.Post(() =>
{
IsLoading = false;
Commits = commits;
if (Commits.Count > 0)
SelectedCommits.Add(Commits[0]);
Revisions = revisions;
if (revisions.Count > 0)
SelectedRevisions.Add(revisions[0]);
});
});
SelectedCommits.CollectionChanged += (_, _) =>
SelectedRevisions.CollectionChanged += (_, _) =>
{
if (_viewContent is FileHistoriesSingleRevision singleRevision)
_prevIsDiffMode = singleRevision.IsDiffMode;
ViewContent = SelectedCommits.Count switch
ViewContent = SelectedRevisions.Count switch
{
1 => new FileHistoriesSingleRevision(_repo, file, SelectedCommits[0], _prevIsDiffMode),
2 => new FileHistoriesCompareRevisions(_repo, file, SelectedCommits[0], SelectedCommits[1]),
_ => SelectedCommits.Count,
1 => new FileHistoriesSingleRevision(_repo, SelectedRevisions[0], _prevIsDiffMode),
2 => new FileHistoriesCompareRevisions(_repo, SelectedRevisions[0], SelectedRevisions[1]),
_ => SelectedRevisions.Count,
};
};
}
public void NavigateToCommit(Models.Commit commit)
public void NavigateToCommit(Models.FileVersion revision)
{
var launcher = App.GetLauncher();
if (launcher != null)
@@ -318,16 +285,16 @@ namespace SourceGit.ViewModels
{
if (page.Data is Repository repo && repo.FullPath.Equals(_repo, StringComparison.Ordinal))
{
repo.NavigateToCommit(commit.SHA);
repo.NavigateToCommit(revision.SHA);
break;
}
}
}
}
public string GetCommitFullMessage(Models.Commit commit)
public string GetCommitFullMessage(Models.FileVersion revision)
{
var sha = commit.SHA;
var sha = revision.SHA;
if (_fullCommitMessages.TryGetValue(sha, out var msg))
return msg;
@@ -339,7 +306,7 @@ namespace SourceGit.ViewModels
private readonly string _repo = null;
private bool _isLoading = true;
private bool _prevIsDiffMode = true;
private List<Models.Commit> _commits = null;
private List<Models.FileVersion> _revisions = null;
private Dictionary<string, string> _fullCommitMessages = new();
private object _viewContent = null;
}

View File

@@ -35,9 +35,8 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _selectedFile, value);
}
public FileHistoryCommandPalette(Launcher launcher, string repo)
public FileHistoryCommandPalette(string repo)
{
_launcher = launcher;
_repo = repo;
_isLoading = true;
@@ -56,16 +55,6 @@ namespace SourceGit.ViewModels
});
}
public override void Cleanup()
{
_launcher = null;
_repo = null;
_repoFiles.Clear();
_filter = null;
_visibleFiles.Clear();
_selectedFile = null;
}
public void ClearFilter()
{
Filter = string.Empty;
@@ -73,9 +62,12 @@ namespace SourceGit.ViewModels
public void Launch()
{
_repoFiles.Clear();
_visibleFiles.Clear();
Close();
if (!string.IsNullOrEmpty(_selectedFile))
App.ShowWindow(new FileHistories(_repo, _selectedFile));
_launcher.CancelCommandPalette();
}
private void UpdateVisible()
@@ -111,7 +103,6 @@ namespace SourceGit.ViewModels
}
}
private Launcher _launcher = null;
private string _repo = null;
private bool _isLoading = false;
private List<string> _repoFiles = null;

View File

@@ -1,17 +1,21 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class ICommandPalette : ObservableObject, IDisposable
public class ICommandPalette : ObservableObject
{
public void Dispose()
public void Open()
{
Cleanup();
var host = App.GetLauncher();
if (host != null)
host.CommandPalette = this;
}
public virtual void Cleanup()
public void Close()
{
var host = App.GetLauncher();
if (host != null)
host.CommandPalette = null;
}
}
}

View File

@@ -21,7 +21,9 @@ namespace SourceGit.ViewModels
_pageId = pageId;
_targetPath = path;
_parentNode = parent;
Reason = string.IsNullOrEmpty(reason) ? "Invalid repository detected!" : reason;
Reason = string.IsNullOrEmpty(reason) ? "unknown error" : reason;
Reason = Reason.Trim();
}
public override async Task<bool> Sure()

View File

@@ -76,12 +76,6 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _showEditMessageButton, value);
}
public bool IsFullMessageUsed
{
get => _isFullMessageUsed;
set => SetProperty(ref _isFullMessageUsed, value);
}
public Thickness DropDirectionIndicator
{
get => _dropDirectionIndicator;
@@ -108,7 +102,6 @@ namespace SourceGit.ViewModels
private string _fullMessage;
private bool _canSquashOrFixup = true;
private bool _showEditMessageButton = false;
private bool _isFullMessageUsed = true;
private Thickness _dropDirectionIndicator = new Thickness(0);
}
@@ -354,7 +347,6 @@ namespace SourceGit.ViewModels
if (item.Action == Models.InteractiveRebaseAction.Drop)
{
item.IsFullMessageUsed = false;
item.ShowEditMessageButton = false;
item.PendingType = hasPending ? Models.InteractiveRebasePendingType.Ignore : Models.InteractiveRebasePendingType.None;
item.FullMessage = item.OriginalFullMessage;
@@ -365,7 +357,6 @@ namespace SourceGit.ViewModels
if (item.Action == Models.InteractiveRebaseAction.Fixup ||
item.Action == Models.InteractiveRebaseAction.Squash)
{
item.IsFullMessageUsed = false;
item.ShowEditMessageButton = false;
item.PendingType = hasPending ? Models.InteractiveRebasePendingType.Pending : Models.InteractiveRebasePendingType.Last;
item.FullMessage = item.OriginalFullMessage;
@@ -382,7 +373,6 @@ namespace SourceGit.ViewModels
item.Action == Models.InteractiveRebaseAction.Edit)
{
var oldPendingType = item.PendingType;
item.IsFullMessageUsed = true;
item.ShowEditMessageButton = true;
item.PendingType = hasPending ? Models.InteractiveRebasePendingType.Target : Models.InteractiveRebasePendingType.None;
@@ -412,7 +402,6 @@ namespace SourceGit.ViewModels
if (item.Action == Models.InteractiveRebaseAction.Pick)
{
item.IsFullMessageUsed = true;
item.IsMessageUserEdited = false;
if (hasPending)

View File

@@ -347,23 +347,6 @@ namespace SourceGit.ViewModels
ActivePage = page;
}
public void OpenCommandPalette(ICommandPalette commandPalette)
{
var old = _commandPalette;
CommandPalette = commandPalette;
old?.Dispose();
}
public void CancelCommandPalette()
{
if (_commandPalette != null)
{
_commandPalette?.Dispose();
CommandPalette = null;
GC.Collect();
}
}
public void DispatchNotification(string pageId, string message, bool isError)
{
if (!Dispatcher.UIThread.CheckAccess())
@@ -453,7 +436,7 @@ namespace SourceGit.ViewModels
builder.Append(" - ").Append(_activeWorkspace.Name);
Title = builder.ToString();
CancelCommandPalette();
CommandPalette = null;
}
private Workspace _activeWorkspace;

View File

@@ -60,17 +60,6 @@ namespace SourceGit.ViewModels
UpdateVisible();
}
public override void Cleanup()
{
_launcher = null;
_opened.Clear();
_visiblePages.Clear();
_visibleRepos.Clear();
_searchFilter = null;
_selectedPage = null;
_selectedRepo = null;
}
public void ClearFilter()
{
SearchFilter = string.Empty;
@@ -78,12 +67,15 @@ namespace SourceGit.ViewModels
public void OpenOrSwitchTo()
{
_opened.Clear();
_visiblePages.Clear();
_visibleRepos.Clear();
Close();
if (_selectedPage != null)
_launcher.ActivePage = _selectedPage;
else if (_selectedRepo != null)
_launcher.OpenRepositoryInTab(_selectedRepo, null);
_launcher?.CancelCommandPalette();
}
private void UpdateVisible()

View File

@@ -27,22 +27,12 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _selectedBranch, value);
}
public MergeCommandPalette(Launcher launcher, Repository repo)
public MergeCommandPalette(Repository repo)
{
_launcher = launcher;
_repo = repo;
UpdateBranches();
}
public override void Cleanup()
{
_launcher = null;
_repo = null;
_branches.Clear();
_filter = null;
_selectedBranch = null;
}
public void ClearFilter()
{
Filter = string.Empty;
@@ -50,10 +40,11 @@ namespace SourceGit.ViewModels
public void Launch()
{
_branches.Clear();
Close();
if (_repo.CanCreatePopup() && _selectedBranch != null)
_repo.ShowPopup(new Merge(_repo, _selectedBranch, _repo.CurrentBranch.Name, false));
_launcher?.CancelCommandPalette();
}
private void UpdateBranches()
@@ -90,7 +81,6 @@ namespace SourceGit.ViewModels
SelectedBranch = autoSelected;
}
private Launcher _launcher = null;
private Repository _repo = null;
private List<Models.Branch> _branches = new List<Models.Branch>();
private string _filter = string.Empty;

View File

@@ -35,9 +35,8 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _selectedFile, value);
}
public OpenFileCommandPalette(Launcher launcher, string repo)
public OpenFileCommandPalette(string repo)
{
_launcher = launcher;
_repo = repo;
_isLoading = true;
@@ -56,16 +55,6 @@ namespace SourceGit.ViewModels
});
}
public override void Cleanup()
{
_launcher = null;
_repo = null;
_repoFiles.Clear();
_filter = null;
_visibleFiles.Clear();
_selectedFile = null;
}
public void ClearFilter()
{
Filter = string.Empty;
@@ -73,10 +62,12 @@ namespace SourceGit.ViewModels
public void Launch()
{
_repoFiles.Clear();
_visibleFiles.Clear();
Close();
if (!string.IsNullOrEmpty(_selectedFile))
Native.OS.OpenWithDefaultEditor(Native.OS.GetAbsPath(_repo, _selectedFile));
_launcher.CancelCommandPalette();
}
private void UpdateVisible()
@@ -112,7 +103,6 @@ namespace SourceGit.ViewModels
}
}
private Launcher _launcher = null;
private string _repo = null;
private bool _isLoading = false;
private List<string> _repoFiles = null;

View File

@@ -155,6 +155,19 @@ namespace SourceGit.ViewModels
}
}
public bool Use24Hours
{
get => Models.DateTimeFormat.Use24Hours;
set
{
if (value != Models.DateTimeFormat.Use24Hours)
{
Models.DateTimeFormat.Use24Hours = value;
OnPropertyChanged();
}
}
}
public bool UseFixedTabWidth
{
get => _useFixedTabWidth;

View File

@@ -4,7 +4,7 @@ namespace SourceGit.ViewModels
{
public class RemoveWorktree : Popup
{
public Models.Worktree Target
public Worktree Target
{
get;
}
@@ -15,7 +15,7 @@ namespace SourceGit.ViewModels
set;
} = false;
public RemoveWorktree(Repository repo, Models.Worktree target)
public RemoveWorktree(Repository repo, Worktree target)
{
_repo = repo;
Target = target;

View File

@@ -172,7 +172,7 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _remoteBranchTrees, value);
}
public List<Models.Worktree> Worktrees
public List<Worktree> Worktrees
{
get => _worktrees;
private set => SetProperty(ref _worktrees, value);
@@ -1076,22 +1076,7 @@ namespace SourceGit.ViewModels
Task.Run(async () =>
{
var worktrees = await new Commands.Worktree(FullPath).ReadAllAsync().ConfigureAwait(false);
if (worktrees.Count == 0)
{
Dispatcher.UIThread.Invoke(() => Worktrees = worktrees);
return;
}
var cleaned = new List<Models.Worktree>();
foreach (var worktree in worktrees)
{
if (worktree.FullPath.Equals(FullPath, StringComparison.Ordinal) ||
worktree.FullPath.Equals(GitDir, StringComparison.Ordinal))
continue;
cleaned.Add(worktree);
}
var cleaned = Worktree.Build(FullPath, worktrees);
Dispatcher.UIThread.Invoke(() => Worktrees = cleaned);
});
}
@@ -1303,7 +1288,7 @@ namespace SourceGit.ViewModels
{
if (branch.IsLocal)
{
var worktree = _worktrees.Find(x => x.Branch.Equals(branch.FullName, StringComparison.Ordinal));
var worktree = _worktrees.Find(x => x.IsAttachedTo(branch));
if (worktree != null)
{
OpenWorktree(worktree);
@@ -1470,8 +1455,11 @@ namespace SourceGit.ViewModels
await ShowAndStartPopupAsync(new PruneWorktrees(this));
}
public void OpenWorktree(Models.Worktree worktree)
public void OpenWorktree(Worktree worktree)
{
if (worktree.IsCurrent)
return;
var node = Preferences.Instance.FindNode(worktree.FullPath) ??
new RepositoryNode
{
@@ -1484,7 +1472,7 @@ namespace SourceGit.ViewModels
App.GetLauncher().OpenRepositoryInTab(node, null);
}
public async Task LockWorktreeAsync(Models.Worktree worktree)
public async Task LockWorktreeAsync(Worktree worktree)
{
using var lockWatcher = _watcher?.Lock();
var log = CreateLog("Lock Worktree");
@@ -1494,7 +1482,7 @@ namespace SourceGit.ViewModels
log.Complete();
}
public async Task UnlockWorktreeAsync(Models.Worktree worktree)
public async Task UnlockWorktreeAsync(Worktree worktree)
{
using var lockWatcher = _watcher?.Lock();
var log = CreateLog("Unlock Worktree");
@@ -1864,7 +1852,7 @@ namespace SourceGit.ViewModels
private Models.Branch _currentBranch = null;
private List<BranchTreeNode> _localBranchTrees = [];
private List<BranchTreeNode> _remoteBranchTrees = [];
private List<Models.Worktree> _worktrees = [];
private List<Worktree> _worktrees = [];
private List<Models.Tag> _tags = [];
private object _visibleTags = null;
private List<Models.Submodule> _submodules = [];

View File

@@ -5,15 +5,29 @@ namespace SourceGit.ViewModels
{
public class RepositoryCommandPaletteCmd
{
public string Key { get; set; }
public string Label { get; set; }
public string Keyword { get; set; }
public string Icon { get; set; }
public bool CloseBeforeExec { get; set; }
public Action Action { get; set; }
public string Label => $"{App.Text(Key)}...";
public RepositoryCommandPaletteCmd(string key, Action action)
public RepositoryCommandPaletteCmd(string labelKey, string keyword, string icon, Action action)
{
Key = key;
Label = $"{App.Text(labelKey)}...";
Keyword = keyword;
Icon = icon;
CloseBeforeExec = true;
Action = action;
}
public RepositoryCommandPaletteCmd(string labelKey, string keyword, string icon, ICommandPalette child)
{
Label = $"{App.Text(labelKey)}...";
Keyword = keyword;
Icon = icon;
CloseBeforeExec = false;
Action = () => child.Open();
}
}
public class RepositoryCommandPalette : ICommandPalette
@@ -40,61 +54,32 @@ namespace SourceGit.ViewModels
}
}
public RepositoryCommandPalette(Launcher launcher, Repository repo)
public RepositoryCommandPalette(Repository repo)
{
_launcher = launcher;
_repo = repo;
// Sub-CommandPalettes
_cmds.Add(new("Blame", "blame", "Blame", new BlameCommandPalette(repo.FullPath)));
_cmds.Add(new("Checkout", "checkout", "Check", new CheckoutCommandPalette(repo)));
_cmds.Add(new("Compare.WithHead", "compare", "Compare", new CompareCommandPalette(repo, null)));
_cmds.Add(new("FileHistory", "history", "Histories", new FileHistoryCommandPalette(repo.FullPath)));
_cmds.Add(new("Merge", "merge", "Merge", new MergeCommandPalette(repo)));
_cmds.Add(new("OpenFile", "open", "OpenWith", new OpenFileCommandPalette(repo.FullPath)));
_cmds.Add(new("Repository.CustomActions", "custom actions", "Action", new ExecuteCustomActionCommandPalette(repo)));
_cmds.Add(new("Blame", () =>
{
var sub = new BlameCommandPalette(_launcher, _repo.FullPath);
_launcher.OpenCommandPalette(sub);
}));
_cmds.Add(new("Checkout", () =>
{
var sub = new CheckoutCommandPalette(_launcher, _repo);
_launcher.OpenCommandPalette(sub);
}));
_cmds.Add(new("Compare.WithHead", () =>
{
var sub = new CompareCommandPalette(_launcher, _repo, _repo.CurrentBranch);
_launcher.OpenCommandPalette(sub);
}));
_cmds.Add(new("FileHistory", () =>
{
var sub = new FileHistoryCommandPalette(_launcher, _repo.FullPath);
_launcher.OpenCommandPalette(sub);
}));
_cmds.Add(new("Merge", () =>
{
var sub = new MergeCommandPalette(_launcher, _repo);
_launcher.OpenCommandPalette(sub);
}));
_cmds.Add(new("OpenFile", () =>
{
var sub = new OpenFileCommandPalette(_launcher, _repo.FullPath);
_launcher.OpenCommandPalette(sub);
}));
// Raw-Actions
_cmds.Add(new("Repository.NewBranch", "create branch", "Branch.Add", () => repo.CreateNewBranch()));
_cmds.Add(new("CreateTag.Title", "create tag", "Tag.Add", () => repo.CreateNewTag()));
_cmds.Add(new("Fetch", "fetch", "Fetch", async () => await repo.FetchAsync(false)));
_cmds.Add(new("Pull.Title", "pull", "Pull", async () => await repo.PullAsync(false)));
_cmds.Add(new("Push", "push", "Push", async () => await repo.PushAsync(false)));
_cmds.Add(new("Stash.Title", "stash", "Stashes.Add", async () => await repo.StashAllAsync(false)));
_cmds.Add(new("Apply.Title", "apply", "Diff", () => repo.ApplyPatch()));
_cmds.Add(new("Configure", "configure", "Settings", async () => await App.ShowDialog(new RepositoryConfigure(repo))));
_cmds.Sort((l, r) => l.Label.CompareTo(r.Label));
_visibleCmds = _cmds;
_selectedCmd = _cmds[0];
}
public override void Cleanup()
{
_launcher = null;
_repo = null;
_cmds.Clear();
_visibleCmds.Clear();
_selectedCmd = null;
_filter = null;
}
public void ClearFilter()
{
Filter = string.Empty;
@@ -102,10 +87,16 @@ namespace SourceGit.ViewModels
public void Exec()
{
_cmds.Clear();
_visibleCmds.Clear();
if (_selectedCmd != null)
{
if (_selectedCmd.CloseBeforeExec)
Close();
_selectedCmd.Action?.Invoke();
else
_launcher?.CancelCommandPalette();
}
}
private void UpdateVisible()
@@ -120,8 +111,8 @@ namespace SourceGit.ViewModels
foreach (var cmd in _cmds)
{
if (cmd.Key.Contains(_filter, StringComparison.OrdinalIgnoreCase) ||
cmd.Label.Contains(_filter, StringComparison.OrdinalIgnoreCase))
if (cmd.Label.Contains(_filter, StringComparison.OrdinalIgnoreCase) ||
cmd.Keyword.Contains(_filter, StringComparison.OrdinalIgnoreCase))
visible.Add(cmd);
}
@@ -134,8 +125,6 @@ namespace SourceGit.ViewModels
}
}
private Launcher _launcher = null;
private Repository _repo = null;
private List<RepositoryCommandPaletteCmd> _cmds = [];
private List<RepositoryCommandPaletteCmd> _visibleCmds = [];
private RepositoryCommandPaletteCmd _selectedCmd = null;

View File

@@ -13,7 +13,7 @@ namespace SourceGit.ViewModels
public string Name { get; private set; }
public bool IsAnnotated { get; private set; }
public Models.User Creator { get; private set; }
public string CreatorDateStr { get; private set; }
public ulong CreatorDate { get; private set; }
public string Message { get; private set; }
public TagToolTip(Models.Tag t)
@@ -21,7 +21,7 @@ namespace SourceGit.ViewModels
Name = t.Name;
IsAnnotated = t.IsAnnotated;
Creator = t.Creator;
CreatorDateStr = t.CreatorDateStr;
CreatorDate = t.CreatorDate;
Message = t.Message;
}
}

View File

@@ -643,12 +643,14 @@ namespace SourceGit.ViewModels
{
if ((!autoStage && _staged.Count == 0) || (autoStage && _cached.Count == 0))
{
var rs = await App.AskConfirmEmptyCommitAsync(_cached.Count > 0);
var rs = await App.AskConfirmEmptyCommitAsync(_cached.Count > 0, _selectedUnstaged is { Count: > 0 });
if (rs == Models.ConfirmEmptyCommitResult.Cancel)
return;
if (rs == Models.ConfirmEmptyCommitResult.StageAllAndCommit)
autoStage = true;
else if (rs == Models.ConfirmEmptyCommitResult.StageSelectedAndCommit)
await StageChangesAsync(_selectedUnstaged, null);
}
}

112
src/ViewModels/Worktree.cs Normal file
View File

@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.IO;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class Worktree : ObservableObject
{
public Models.Worktree Backend { get; private set; }
public bool IsMain { get; private set; }
public bool IsCurrent { get; private set; }
public bool IsLast { get; private set; }
public string DisplayPath { get; private set; }
public string Name { get; private set; }
public string Branch { get; private set; }
public bool IsLocked
{
get => _isLocked;
set => SetProperty(ref _isLocked, value);
}
public string FullPath => Backend.FullPath;
public string Head => Backend.Head;
public Worktree(DirectoryInfo repo, Models.Worktree wt, bool isMain, bool isLast)
{
Backend = wt;
IsMain = isMain;
IsCurrent = IsCurrentWorktree(repo, wt);
IsLast = isLast;
DisplayPath = IsCurrent ? string.Empty : Path.GetRelativePath(repo.FullName, wt.FullPath);
Name = GenerateName();
Branch = GenerateBranchName();
IsLocked = wt.IsLocked;
}
public static List<Worktree> Build(string repo, List<Models.Worktree> worktrees)
{
if (worktrees is not { Count: > 1 })
return [];
var repoDir = new DirectoryInfo(repo);
var nodes = new List<Worktree>();
nodes.Add(new(repoDir, worktrees[0], true, false));
for (int i = 1; i < worktrees.Count; i++)
nodes.Add(new(repoDir, worktrees[i], false, i == worktrees.Count - 1));
return nodes;
}
public bool IsAttachedTo(Models.Branch branch)
{
if (string.IsNullOrEmpty(branch.WorktreePath))
return false;
var wtDir = new DirectoryInfo(Backend.FullPath);
var test = new DirectoryInfo(branch.WorktreePath);
return test.FullName.Equals(wtDir.FullName, StringComparison.Ordinal);
}
private bool IsCurrentWorktree(DirectoryInfo repo, Models.Worktree wt)
{
var wtDir = new DirectoryInfo(wt.FullPath);
return wtDir.FullName.Equals(repo.FullName, StringComparison.Ordinal);
}
private string GenerateName()
{
if (IsMain)
return Path.GetFileName(Backend.FullPath);
if (Backend.IsDetached)
return $"detached HEAD at {Backend.Head.AsSpan(10)}";
var b = Backend.Branch;
if (b.StartsWith("refs/heads/", StringComparison.Ordinal))
return b.Substring(11);
if (b.StartsWith("refs/remotes/", StringComparison.Ordinal))
return b.Substring(13);
return b;
}
private string GenerateBranchName()
{
if (Backend.IsBare)
return "-- (default)";
if (Backend.IsDetached)
return "-- (detached)";
if (string.IsNullOrEmpty(Backend.Branch))
return "-- (unknown)";
var b = Backend.Branch;
if (b.StartsWith("refs/heads/", StringComparison.Ordinal))
return b.Substring(11);
if (b.StartsWith("refs/remotes/", StringComparison.Ordinal))
return b.Substring(13);
return b;
}
private bool _isLocked = false;
}
}

View File

@@ -29,8 +29,7 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.Remote.Name.Placeholder}"
Text="{Binding Name, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Text="{Binding Name, Mode=TwoWay}"/>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"

View File

@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SourceGit.Views.AddSubmodule"
x:DataType="vm:AddSubmodule">
@@ -28,8 +27,7 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.RepositoryURL}"
Text="{Binding Url, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Text="{Binding Url, Mode=TwoWay}"/>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"

View File

@@ -4,7 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.AddToIgnore"
x:DataType="vm:AddToIgnore">
@@ -27,8 +26,7 @@
<TextBox Grid.Row="0" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding Pattern, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True">
Text="{Binding Pattern, Mode=TwoWay}">
<TextBox.InnerLeftContent>
<Path Width="12" Height="12" Margin="6,0,2,0" Data="{StaticResource Icons.Pattern}" Fill="{DynamicResource Brush.FG2}"/>
</TextBox.InnerLeftContent>

View File

@@ -4,7 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Apply"
x:DataType="vm:Apply">
@@ -29,8 +28,7 @@
Height="28"
CornerRadius="3"
Watermark="{DynamicResource Text.Apply.File.Placeholder}"
Text="{Binding PatchFile, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True">
Text="{Binding PatchFile, Mode=TwoWay}">
<TextBox.InnerRightContent>
<Button Classes="icon_button" Width="30" Height="30" Click="SelectPatchFile">
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>

View File

@@ -4,7 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SourceGit.Views.Archive"
@@ -60,8 +59,7 @@
Height="28"
CornerRadius="3"
Watermark="{DynamicResource Text.Archive.File.Placeholder}"
Text="{Binding SaveFile, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True">
Text="{Binding SaveFile, Mode=TwoWay}">
<TextBox.InnerRightContent>
<Button Classes="icon_button" Width="30" Height="30" Click="SelectOutputFile">
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>

View File

@@ -46,8 +46,7 @@
Focusable="True"
PasswordChar="*"
RevealPassword="{Binding #ToggleShowPassword.IsChecked, Mode=OneWay}"
HorizontalAlignment="Stretch"
v:AutoFocusBehaviour.IsEnabled="True">
HorizontalAlignment="Stretch">
<TextBox.InnerRightContent>
<ToggleButton Grid.Column="6"
x:Name="ToggleShowPassword"

View File

@@ -1,4 +1,6 @@
using System;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
@@ -10,6 +12,12 @@ namespace SourceGit.Views
InitializeComponent();
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
TxtPassphrase.Focus(NavigationMethod.Directional);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
Console.Out.WriteLine("No passphrase entered.");

View File

@@ -1,42 +0,0 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
namespace SourceGit.Views
{
public class AutoFocusBehaviour : AvaloniaObject
{
public static readonly AttachedProperty<bool> IsEnabledProperty =
AvaloniaProperty.RegisterAttached<AutoFocusBehaviour, TextBox, bool>("IsEnabled");
static AutoFocusBehaviour()
{
IsEnabledProperty.Changed.AddClassHandler<TextBox>(OnIsEnabledChanged);
}
public static bool GetIsEnabled(AvaloniaObject elem)
{
return elem.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(AvaloniaObject elem, bool value)
{
elem.SetValue(IsEnabledProperty, value);
}
private static void OnIsEnabledChanged(TextBox elem, AvaloniaPropertyChangedEventArgs e)
{
if (GetIsEnabled(elem))
{
elem.AttachedToVisualTree += (o, _) =>
{
if (o is TextBox box)
{
box.Focus(NavigationMethod.Directional);
box.CaretIndex = box.Text?.Length ?? 0;
}
};
}
}
}
}

View File

@@ -38,6 +38,8 @@ namespace SourceGit.Views
var typeface = view.CreateTypeface();
var underlinePen = new Pen(Brushes.DarkOrange);
var width = Bounds.Width;
var lineHeight = view.DefaultLineHeight;
var pixelHeight = PixelSnapHelpers.GetPixelSize(view).Height;
foreach (var line in view.VisualLines)
{
@@ -50,8 +52,8 @@ namespace SourceGit.Views
var info = _editor.BlameData.LineInfos[lineNumber - 1];
var x = 0.0;
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - view.VerticalOffset;
if (!info.IsFirstInGroup && y > view.DefaultLineHeight * 0.6)
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineMiddle) - view.VerticalOffset;
if (!info.IsFirstInGroup && y > lineHeight)
continue;
var shaLink = new FormattedText(
@@ -61,8 +63,10 @@ namespace SourceGit.Views
typeface,
_editor.FontSize,
Brushes.DarkOrange);
context.DrawText(shaLink, new Point(x, y));
context.DrawLine(underlinePen, new Point(x, y + shaLink.Baseline + 2), new Point(x + shaLink.Width, y + shaLink.Baseline + 2));
var shaLinkTop = y - shaLink.Height * 0.5;
var underlineY = PixelSnapHelpers.PixelAlign(y + shaLink.Height * 0.5 + 0.5, pixelHeight);
context.DrawText(shaLink, new Point(x, shaLinkTop));
context.DrawLine(underlinePen, new Point(x, underlineY), new Point(x + shaLink.Width, underlineY));
x += shaLink.Width + 8;
var author = new FormattedText(
@@ -72,16 +76,19 @@ namespace SourceGit.Views
typeface,
_editor.FontSize,
_editor.Foreground);
context.DrawText(author, new Point(x, y));
var authorTop = y - author.Height * 0.5;
context.DrawText(author, new Point(x, authorTop));
var timeStr = Models.DateTimeFormat.Format(info.Timestamp, true);
var time = new FormattedText(
info.Time,
timeStr,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
typeface,
_editor.FontSize,
_editor.Foreground);
context.DrawText(time, new Point(width - time.Width, y));
var timeTop = y - time.Height * 0.5;
context.DrawText(time, new Point(width - time.Width, timeTop));
}
}
}
@@ -124,8 +131,9 @@ namespace SourceGit.Views
_editor.Foreground);
x += author.Width + 8;
var timeStr = Models.DateTimeFormat.Format(info.Timestamp, true);
var time = new FormattedText(
info.Time,
timeStr,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
typeface,
@@ -150,6 +158,7 @@ namespace SourceGit.Views
{
var pos = e.GetPosition(this);
var typeface = view.CreateTypeface();
var lineHeight = view.DefaultLineHeight;
foreach (var line in view.VisualLines)
{
@@ -161,7 +170,7 @@ namespace SourceGit.Views
break;
var info = _editor.BlameData.LineInfos[lineNumber - 1];
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop) - view.VerticalOffset;
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineTop) - view.VerticalOffset;
var shaLink = new FormattedText(
info.CommitSHA,
CultureInfo.CurrentCulture,
@@ -170,7 +179,7 @@ namespace SourceGit.Views
_editor.FontSize,
Brushes.DarkOrange);
var rect = new Rect(0, y, shaLink.Width, shaLink.Height);
var rect = new Rect(0, y, shaLink.Width, lineHeight);
if (rect.Contains(pos))
{
Cursor = Cursor.Parse("Hand");

View File

@@ -8,7 +8,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.BlameCommandPalette"
x:DataType="vm:BlameCommandPalette">
<Grid RowDefinitions="Auto,Auto">
<Grid RowDefinitions="Auto,Auto,Auto">
<v:RepositoryCommandPaletteTextBox Grid.Row="0"
x:Name="FilterTextBox"
Height="24"
@@ -50,11 +50,17 @@
</Button>
</TextBox.InnerRightContent>
</v:RepositoryCommandPaletteTextBox>
<TextBlock Grid.Row="1"
Margin="6,12,0,0"
Text="{DynamicResource Text.CommandPalette.RevisionFiles}"
FontWeight="Bold"
Foreground="{DynamicResource Brush.FG2}"/>
<ListBox Grid.Row="1"
<ListBox Grid.Row="2"
x:Name="FileListBox"
MaxHeight="250"
Margin="4,8,4,0"
MaxHeight="360"
Margin="4,8"
BorderThickness="0"
SelectionMode="Single"
Background="Transparent"
@@ -88,7 +94,7 @@
<ListBox.ItemTemplate>
<DataTemplate DataType="x:String">
<Grid ColumnDefinitions="Auto,*" Background="Transparent" Tapped="OnItemTapped">
<Grid ColumnDefinitions="Auto,*" Background="Transparent" Tapped="OnItemTapped" ToolTip.Tip="{Binding}">
<Path Grid.Column="0"
Width="12" Height="12"
Data="{StaticResource Icons.File}"

View File

@@ -303,6 +303,15 @@ namespace SourceGit.Views
remove { RemoveHandler(RowsChangedEvent, value); }
}
public static readonly RoutedEvent<RoutedEventArgs> SearchRequestedEvent =
RoutedEvent.Register<BranchTree, RoutedEventArgs>(nameof(SearchRequested), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> SearchRequested
{
add { AddHandler(SearchRequestedEvent, value); }
remove { RemoveHandler(SearchRequestedEvent, value); }
}
public BranchTree()
{
InitializeComponent();
@@ -566,6 +575,13 @@ namespace SourceGit.Views
private void OnTreeKeyDown(object _, KeyEventArgs e)
{
if (e.Key == Key.F && e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
{
RaiseEvent(new RoutedEventArgs(SearchRequestedEvent));
e.Handled = true;
return;
}
if (e.Key is not (Key.Delete or Key.Back))
return;
@@ -722,9 +738,7 @@ namespace SourceGit.Views
compareWith.Icon = App.CreateMenuIcon("Icons.Compare");
compareWith.Click += (_, _) =>
{
var launcher = App.GetLauncher();
if (launcher != null)
launcher.OpenCommandPalette(new ViewModels.CompareCommandPalette(launcher, repo, branch));
new ViewModels.CompareCommandPalette(repo, branch).Open();
};
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(compareWith);
@@ -847,9 +861,7 @@ namespace SourceGit.Views
compareWith.Icon = App.CreateMenuIcon("Icons.Compare");
compareWith.Click += (_, _) =>
{
var launcher = App.GetLauncher();
if (launcher != null)
launcher.OpenCommandPalette(new ViewModels.CompareCommandPalette(launcher, repo, branch));
new ViewModels.CompareCommandPalette(repo, branch).Open();
};
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(compareWithCurrent);
@@ -1155,9 +1167,7 @@ namespace SourceGit.Views
compareWith.Icon = App.CreateMenuIcon("Icons.Compare");
compareWith.Click += (_, _) =>
{
var launcher = App.GetLauncher();
if (launcher != null)
launcher.OpenCommandPalette(new ViewModels.CompareCommandPalette(launcher, repo, branch));
new ViewModels.CompareCommandPalette(repo, branch).Open();
};
menu.Items.Add(pull);

View File

@@ -9,7 +9,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CheckoutCommandPalette"
x:DataType="vm:CheckoutCommandPalette">
<Grid RowDefinitions="Auto,Auto">
<Grid RowDefinitions="Auto,Auto,Auto">
<v:RepositoryCommandPaletteTextBox Grid.Row="0"
x:Name="FilterTextBox"
Height="24"
@@ -52,10 +52,16 @@
</TextBox.InnerRightContent>
</v:RepositoryCommandPaletteTextBox>
<ListBox Grid.Row="1"
<TextBlock Grid.Row="1"
Margin="6,12,0,0"
Text="{DynamicResource Text.CommandPalette.Branches}"
FontWeight="Bold"
Foreground="{DynamicResource Brush.FG2}"/>
<ListBox Grid.Row="2"
x:Name="BranchListBox"
MaxHeight="250"
Margin="4,8,4,0"
MaxHeight="360"
Margin="4,8"
BorderThickness="0"
SelectionMode="Single"
Background="Transparent"

View File

@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Clone"
x:DataType="vm:Clone">
@@ -27,8 +26,7 @@
<TextBox Grid.Row="0" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding Remote, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Text="{Binding Remote, Mode=TwoWay}"/>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right"

View File

@@ -25,10 +25,10 @@
<Run Text="{Binding Author.Email, Mode=OneWay}"/>
</TextBlock>
</Border>
<TextBlock Text="{Binding AuthorTimeStr}"
Margin="2,0,0,0"
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
<v:DateTimePresenter Margin="2,0,0,0"
Timestamp="{Binding AuthorTime}"
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
</Grid>
@@ -43,10 +43,10 @@
<Run Text="{Binding Committer.Email, Mode=OneWay}"/>
</TextBlock>
</Border>
<TextBlock Text="{Binding CommitterTimeStr}"
Margin="2,0,0,0"
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
<v:DateTimePresenter Margin="2,0,0,0"
Timestamp="{Binding CommitterTime}"
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
</Grid>
</UniformGrid>
@@ -127,7 +127,10 @@
<Grid ColumnDefinitions="Auto,*,Auto">
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" Text="{Binding CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
<v:DateTimePresenter Grid.Column="2"
Margin="8,0,0,0"
Timestamp="{Binding CommitterTime}"
Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
<TextBlock Margin="0,8,0,0" Text="{Binding Subject}" TextWrapping="Wrap"/>
@@ -171,7 +174,10 @@
<Grid ColumnDefinitions="Auto,*,Auto">
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" Text="{Binding CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
<v:DateTimePresenter Grid.Column="2"
Margin="8,0,0,0"
Timestamp="{Binding CommitterTime}"
Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
<TextBlock Margin="0,8,0,0" Text="{Binding Subject}" TextWrapping="Wrap"/>
@@ -213,7 +219,10 @@
<Grid ColumnDefinitions="Auto,*,Auto">
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" Text="{Binding CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
<v:DateTimePresenter Grid.Column="2"
Margin="8,0,0,0"
Timestamp="{Binding CommitterTime}"
Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
<TextBlock Margin="0,8,0,0" Text="{Binding Subject}" TextWrapping="Wrap"/>

View File

@@ -18,6 +18,7 @@
<!-- Search & Display Mode -->
<Grid Grid.Row="0" ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0"
x:Name="CommitChangeSearchBox"
Height="26"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent"
@@ -67,7 +68,8 @@
<GridSplitter Grid.Column="1"
MinWidth="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="Transparent"/>
Background="Transparent"
Focusable="False"/>
<Grid Grid.Column="2">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">

View File

@@ -42,8 +42,8 @@ namespace SourceGit.Views
if (sender is not ChangeCollectionView { SelectedChanges: { Count: > 0 } selectedChanges } view)
return;
if (e.Key == Key.C &&
e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
if (e.Key == Key.C && e.KeyModifiers.HasFlag(cmdKey))
{
var builder = new StringBuilder();
var copyAbsPath = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
@@ -65,6 +65,11 @@ namespace SourceGit.Views
await App.CopyTextAsync(builder.ToString());
e.Handled = true;
}
else if (e.Key == Key.F && e.KeyModifiers == cmdKey)
{
CommitChangeSearchBox.Focus();
e.Handled = true;
}
}
}
}

View File

@@ -37,12 +37,20 @@
<StackPanel Grid.Row="1" Orientation="Vertical" Margin="8">
<v:CommitMessageToolBox x:Name="Editor" Height="400"/>
<Button Classes="flat primary"
Width="80"
Margin="0,8,0,4"
Content="{DynamicResource Text.Sure}"
Click="SaveAndClose"
HorizontalAlignment="Center"/>
<StackPanel Margin="0,8,0,4" Orientation="Horizontal" HorizontalAlignment="Center" Spacing="8">
<Button Classes="flat primary"
Width="80"
Content="{DynamicResource Text.Sure}"
Click="SaveAndClose"
HorizontalAlignment="Center"/>
<Button Classes="flat"
Width="80"
Content="{DynamicResource Text.Cancel}"
Click="CancelAndClose"
HotKey="Escape"
HorizontalAlignment="Center"/>
</StackPanel>
</StackPanel>
</Grid>
</v:ChromelessWindow>

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Text.Json;
using Avalonia.Interactivity;
namespace SourceGit.Views
@@ -15,7 +16,6 @@ namespace SourceGit.Views
public CommitMessageEditor()
{
CloseOnESC = true;
InitializeComponent();
}
@@ -67,12 +67,17 @@ namespace SourceGit.Views
private void SaveAndClose(object _1, RoutedEventArgs _2)
{
_onSave?.Invoke(Editor.CommitMessage);
_exitCode = 0;
Close();
}
private void CancelAndClose(object _1, RoutedEventArgs _2)
{
_exitCode = -1;
Close();
}
private Action<string> _onSave = null;
private bool _shouldExitApp = true;
private int _exitCode = -1;
private int _exitCode = 0;
}
}

View File

@@ -279,10 +279,10 @@ namespace SourceGit.Views
_isEditing = false;
var caretOffset = CaretOffset;
var start = caretOffset;
for (; start > 0; start--)
var lineStart = caretOffset;
for (; lineStart > 0; lineStart--)
{
var ch = Text[start - 1];
var ch = Text[lineStart - 1];
if (ch == '\n')
break;
@@ -290,18 +290,18 @@ namespace SourceGit.Views
return;
}
if (caretOffset < start + 2)
if (lineStart == 0 || caretOffset < lineStart + 2)
{
_completionWnd?.Close();
return;
}
var word = Text.Substring(start, caretOffset - start);
var word = Text.Substring(lineStart, caretOffset - lineStart);
var matches = new List<CommitMessageCodeCompletionData>();
foreach (var keyword in _keywords)
foreach (var t in _trailers)
{
if (keyword.StartsWith(word, StringComparison.OrdinalIgnoreCase) && keyword.Length != word.Length)
matches.Add(new(keyword));
if (t.StartsWith(word, StringComparison.OrdinalIgnoreCase) && t.Length != word.Length)
matches.Add(new(t));
}
if (matches.Count > 0)
@@ -315,7 +315,7 @@ namespace SourceGit.Views
_completionWnd.CompletionList.CompletionData.Clear();
_completionWnd.CompletionList.CompletionData.AddRange(matches);
_completionWnd.StartOffset = start;
_completionWnd.StartOffset = lineStart;
_completionWnd.EndOffset = caretOffset;
}
else
@@ -377,7 +377,23 @@ namespace SourceGit.Views
SetCurrentValue(ColumnProperty, col);
}
private readonly List<string> _keywords = ["Acked-by: ", "Co-authored-by: ", "Reviewed-by: ", "Signed-off-by: ", "on-behalf-of: @", "BREAKING CHANGE: ", "Refs: "];
private readonly List<string> _trailers =
[
"Acked-by: ",
"BREAKING CHANGE: ",
"Co-authored-by: ",
"Fixes: ",
"Helped-by: ",
"Issue: ",
"Milestone: ",
"on-behalf-of: @",
"Reference-to: ",
"Refs: ",
"Reviewed-by: ",
"See-also: ",
"Signed-off-by: ",
];
private bool _isEditing = false;
private int _subjectEndLine = 0;
private CompletionWindow _completionWnd = null;
@@ -552,6 +568,7 @@ namespace SourceGit.Views
if (vm.Staged == null || vm.Staged.Count == 0)
{
App.RaiseException(repo.FullPath, "No files added to commit!");
e.Handled = true;
return;
}
@@ -559,12 +576,14 @@ namespace SourceGit.Views
if (services.Count == 0)
{
App.RaiseException(repo.FullPath, "Bad configuration for OpenAI");
e.Handled = true;
return;
}
if (services.Count == 1)
{
await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], vm.Staged));
e.Handled = true;
return;
}

View File

@@ -19,6 +19,15 @@ namespace SourceGit.Views
set => SetValue(ShowAsDateTimeProperty, value);
}
public static readonly StyledProperty<bool> Use24HoursProperty =
AvaloniaProperty.Register<CommitTimeTextBlock, bool>(nameof(Use24Hours), true);
public bool Use24Hours
{
get => GetValue(Use24HoursProperty);
set => SetValue(Use24HoursProperty, value);
}
public static readonly StyledProperty<int> DateTimeFormatProperty =
AvaloniaProperty.Register<CommitTimeTextBlock, int>(nameof(DateTimeFormat));
@@ -62,7 +71,7 @@ namespace SourceGit.Views
HorizontalAlignment = HorizontalAlignment.Center;
}
}
else if (change.Property == DateTimeFormatProperty)
else if (change.Property == DateTimeFormatProperty || change.Property == Use24HoursProperty)
{
if (ShowAsDateTime)
SetCurrentValue(TextProperty, GetDisplayText());
@@ -121,10 +130,10 @@ namespace SourceGit.Views
if (DataContext is not Models.Commit commit)
return string.Empty;
if (ShowAsDateTime)
return UseAuthorTime ? commit.AuthorTimeStr : commit.CommitterTimeStr;
var timestamp = UseAuthorTime ? commit.AuthorTime : commit.CommitterTime;
if (ShowAsDateTime)
return Models.DateTimeFormat.Format(timestamp);
var now = DateTime.Now;
var localTime = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime();
var span = now - localTime;

View File

@@ -53,8 +53,16 @@
<TextBlock Text="{Binding BaseName}" Margin="4,0" Foreground="#FFF2F2F2"/>
</StackPanel>
</Border>
<TextBlock Grid.Column="3" Text="{Binding BaseHead.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" Cursor="Hand" PointerPressed="OnPressedSHA"/>
<TextBlock Grid.Column="4" Text="{Binding BaseHead.CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
<TextBlock Grid.Column="3"
Text="{Binding BaseHead.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
Foreground="DarkOrange" Margin="8,0,0,0"
TextDecorations="Underline"
Cursor="Hand"
PointerPressed="OnPressedSHA"/>
<v:DateTimePresenter Grid.Column="4"
Margin="8,0,0,0"
Timestamp="{Binding BaseHead.CommitterTime}"
Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
<TextBlock Grid.Row="1" Text="{Binding BaseHead.Subject}" VerticalAlignment="Bottom"/>
@@ -81,7 +89,10 @@
</StackPanel>
</Border>
<TextBlock Grid.Column="3" Text="{Binding ToHead.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" Cursor="Hand" PointerPressed="OnPressedSHA"/>
<TextBlock Grid.Column="4" Text="{Binding ToHead.CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
<v:DateTimePresenter Grid.Column="4"
Margin="8,0,0,0"
Timestamp="{Binding ToHead.CommitterTime}"
Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
<TextBlock Grid.Row="1" Text="{Binding ToHead.Subject}" VerticalAlignment="Bottom"/>
@@ -103,6 +114,7 @@
<!-- Search & Display Mode -->
<Grid Grid.Row="0" ColumnDefinitions="*,18">
<TextBox Grid.Column="0"
x:Name="ChangeSearchBox"
Height="26"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent"
@@ -158,7 +170,8 @@
<GridSplitter Grid.Column="1"
MinWidth="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="Transparent"/>
Background="Transparent"
Focusable="False"/>
<Grid Grid.Column="2">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">

View File

@@ -218,7 +218,8 @@ namespace SourceGit.Views
if (sender is not ChangeCollectionView { SelectedChanges: { Count: > 0 } selectedChanges })
return;
if (e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) && e.Key == Key.C)
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
if (e.Key == Key.C && e.KeyModifiers.HasFlag(cmdKey))
{
var builder = new StringBuilder();
var copyAbsPath = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
@@ -235,6 +236,11 @@ namespace SourceGit.Views
await App.CopyTextAsync(builder.ToString());
e.Handled = true;
}
else if (e.Key == Key.F && e.KeyModifiers == cmdKey)
{
ChangeSearchBox.Focus();
e.Handled = true;
}
}
}
}

View File

@@ -9,7 +9,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CompareCommandPalette"
x:DataType="vm:CompareCommandPalette">
<Grid RowDefinitions="Auto,Auto">
<Grid RowDefinitions="Auto,Auto,Auto">
<v:RepositoryCommandPaletteTextBox Grid.Row="0"
x:Name="FilterTextBox"
Height="24"
@@ -64,10 +64,16 @@
</TextBox.InnerRightContent>
</v:RepositoryCommandPaletteTextBox>
<ListBox Grid.Row="1"
<TextBlock Grid.Row="1"
Margin="6,12,0,0"
Text="{DynamicResource Text.CommandPalette.BranchesAndTags}"
FontWeight="Bold"
Foreground="{DynamicResource Brush.FG2}"/>
<ListBox Grid.Row="2"
x:Name="RefsListBox"
MaxHeight="250"
Margin="4,8,4,0"
MaxHeight="360"
Margin="4,8"
BorderThickness="0"
SelectionMode="Single"
Background="Transparent"

View File

@@ -37,11 +37,20 @@
<!-- Body -->
<Border Grid.Row="1" Margin="16">
<TextBlock x:Name="TxtMessage" MaxWidth="520" TextWrapping="Wrap"/>
<TextBlock x:Name="TxtMessage" TextWrapping="NoWrap"/>
</Border>
<!-- Buttons -->
<StackPanel Grid.Row="2" Margin="0,0,0,16" Orientation="Horizontal" HorizontalAlignment="Center">
<StackPanel Grid.Row="2" Margin="32,0,32,16" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Classes="flat"
x:Name="BtnStageSelectedAndCommit"
Height="30"
Margin="4,0"
Click="StageSelectedThenCommit"
Content="{DynamicResource Text.ConfirmEmptyCommit.StageSelectedThenCommit}"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"/>
<Button Classes="flat"
x:Name="BtnStageAllAndCommit"
Height="30"

View File

@@ -9,6 +9,11 @@ namespace SourceGit.Views
InitializeComponent();
}
private void StageSelectedThenCommit(object _1, RoutedEventArgs _2)
{
Close(Models.ConfirmEmptyCommitResult.StageSelectedAndCommit);
}
private void StageAllThenCommit(object _1, RoutedEventArgs _2)
{
Close(Models.ConfirmEmptyCommitResult.StageAllAndCommit);

View File

@@ -20,7 +20,7 @@
Text="{DynamicResource Text.CreateBranch.Title}"/>
</StackPanel>
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,Auto,Auto">
<Grid Margin="0,16,0,0" RowDefinitions="32,32,Auto,Auto,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="140"/>
<ColumnDefinition Width="*"/>
@@ -65,8 +65,7 @@
VerticalAlignment="Center"
CornerRadius="2"
Text="{Binding Name, Mode=TwoWay}"
Watermark="{DynamicResource Text.CreateBranch.Name.Placeholder}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Watermark="{DynamicResource Text.CreateBranch.Name.Placeholder}"/>
<TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"

View File

@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CreateGroup"
x:DataType="vm:CreateGroup">
@@ -20,7 +19,7 @@
<Grid Margin="8,16,0,0" Height="28" ColumnDefinitions="Auto,*">
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="8,0" Text="{DynamicResource Text.Name}"/>
<TextBox Grid.Column="1" CornerRadius="3" v:AutoFocusBehaviour.IsEnabled="True" Text="{Binding Name, Mode=TwoWay}"/>
<TextBox Grid.Column="1" CornerRadius="3" Text="{Binding Name, Mode=TwoWay}"/>
</Grid>
</StackPanel>
</UserControl>

View File

@@ -53,8 +53,7 @@
VerticalAlignment="Center"
CornerRadius="2"
Text="{Binding TagName, Mode=TwoWay}"
Watermark="{DynamicResource Text.CreateTag.Name.Placeholder}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Watermark="{DynamicResource Text.CreateTag.Name.Placeholder}"/>
<TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"

View File

@@ -0,0 +1,80 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data;
namespace SourceGit.Views
{
public class DateTimePresenter : TextBlock
{
public static readonly StyledProperty<bool> ShowDateOnlyProperty =
AvaloniaProperty.Register<DateTimePresenter, bool>(nameof(ShowDateOnly), false);
public bool ShowDateOnly
{
get => GetValue(ShowDateOnlyProperty);
set => SetValue(ShowDateOnlyProperty, value);
}
public static readonly StyledProperty<bool> Use24HoursProperty =
AvaloniaProperty.Register<DateTimePresenter, bool>(nameof(Use24Hours), true);
public bool Use24Hours
{
get => GetValue(Use24HoursProperty);
set => SetValue(Use24HoursProperty, value);
}
public static readonly StyledProperty<int> DateTimeFormatProperty =
AvaloniaProperty.Register<DateTimePresenter, int>(nameof(DateTimeFormat));
public int DateTimeFormat
{
get => GetValue(DateTimeFormatProperty);
set => SetValue(DateTimeFormatProperty, value);
}
public static readonly StyledProperty<ulong> TimestampProperty =
AvaloniaProperty.Register<DateTimePresenter, ulong>(nameof(Timestamp), 0);
public ulong Timestamp
{
get => GetValue(TimestampProperty);
set => SetValue(TimestampProperty, value);
}
protected override Type StyleKeyOverride => typeof(TextBlock);
public DateTimePresenter()
{
Bind(Use24HoursProperty, new Binding()
{
Mode = BindingMode.OneWay,
Source = ViewModels.Preferences.Instance,
Path = "Use24Hours"
});
Bind(DateTimeFormatProperty, new Binding()
{
Mode = BindingMode.OneWay,
Source = ViewModels.Preferences.Instance,
Path = "DateTimeFormat"
});
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ShowDateOnlyProperty ||
change.Property == Use24HoursProperty ||
change.Property == DateTimeFormatProperty ||
change.Property == TimestampProperty)
{
var text = Models.DateTimeFormat.Format(Timestamp, ShowDateOnly);
SetCurrentValue(TextProperty, text);
}
}
}
}

View File

@@ -265,13 +265,14 @@
<TextBlock 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}}">
<Border Margin="0,8"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
Background="{DynamicResource Brush.Window}"
IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}">
<ContentControl Content="{Binding Old}">
<ContentControl.DataTemplates>
<DataTemplate DataType="m:RevisionSubmodule">
<Border Margin="0,0,0,8" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Background="{DynamicResource Brush.Window}">
<v:CommitBaseInfo Margin="0,4,8,6" Content="{Binding Commit}" FullMessage="{Binding FullMessage}"/>
</Border>
<v:CommitBaseInfo Margin="0,4,8,6" Content="{Binding Commit}" FullMessage="{Binding FullMessage}"/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
@@ -290,7 +291,10 @@
<TextBlock Text="{DynamicResource Text.Diff.Submodule.New}" Margin="8,0" FontSize="10" Foreground="White"/>
</Border>
<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"
BorderThickness="1" BorderBrush="Green"
Background="{DynamicResource Brush.Window}"
IsVisible="{Binding New, Converter={x:Static ObjectConverters.IsNotNull}}">
<ContentControl Content="{Binding New}">
<ContentControl.DataTemplates>
<DataTemplate DataType="m:RevisionSubmodule">

View File

@@ -94,7 +94,12 @@
TextDecorations="Underline"
Margin="8,0,0,0"
PointerPressed="OnPressCommitSHA"/>
<TextBlock Grid.Column="3" Text="{Binding AuthorTimeShortStr}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
<v:DateTimePresenter Grid.Column="3"
Margin="8,0,0,0"
ShowDateOnly="True"
Timestamp="{Binding AuthorTime}"
Foreground="{DynamicResource Brush.FG2}"
HorizontalAlignment="Right"/>
</Grid>
<Border Grid.Row="1" Background="Transparent" DataContextChanged="OnCommitSubjectDataContextChanged" PointerMoved="OnCommitSubjectPointerMoved">
@@ -117,7 +122,8 @@
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="Transparent"
BorderThickness="1,0,0,0"
BorderBrush="{DynamicResource Brush.Border0}"/>
BorderBrush="{DynamicResource Brush.Border0}"
Focusable="False"/>
<!-- Commit Detail -->
<Border Grid.Column="2" Padding="0,4" IsVisible="{Binding !IsLoading}">

View File

@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SourceGit.Views.EditRemote"
x:DataType="vm:EditRemote">
@@ -28,8 +27,7 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.Remote.Name.Placeholder}"
Text="{Binding Name, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Text="{Binding Name, Mode=TwoWay}"/>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"

View File

@@ -4,7 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="using:SourceGit.Converters"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.EditRepositoryNode"
x:DataType="vm:EditRepositoryNode">
@@ -32,7 +31,7 @@
</Grid>
<Grid Height="28" Margin="8,4,0,0" ColumnDefinitions="120,*">
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.EditRepositoryNode.Name}"/>
<TextBox Grid.Column="1" CornerRadius="3" Text="{Binding Name, Mode=TwoWay}" v:AutoFocusBehaviour.IsEnabled="True"/>
<TextBox Grid.Column="1" CornerRadius="3" Text="{Binding Name, Mode=TwoWay}"/>
</Grid>
<Grid Height="28" Margin="8,4,0,0" ColumnDefinitions="120,*" IsVisible="{Binding IsRepository}">
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.EditRepositoryNode.Bookmark}"/>

View File

@@ -7,8 +7,7 @@
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SourceGit.Views.ExecuteCustomAction"
x:DataType="vm:ExecuteCustomAction"
Loaded="OnLoaded">
x:DataType="vm:ExecuteCustomAction">
<StackPanel Orientation="Vertical" Margin="8,0">
<StackPanel Orientation="Horizontal">
<Path Width="16" Height="16"

View File

@@ -1,10 +1,8 @@
using System;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
@@ -15,19 +13,6 @@ namespace SourceGit.Views
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var inputs = this.GetVisualDescendants();
foreach (var input in inputs)
{
if (input is InputElement { Focusable: true, IsTabStop: true } focusable)
{
focusable.Focus();
return;
}
}
}
private async void SelectPath(object sender, RoutedEventArgs e)
{
var topLevel = TopLevel.GetTopLevel(this);

View File

@@ -0,0 +1,124 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.ExecuteCustomActionCommandPalette"
x:DataType="vm:ExecuteCustomActionCommandPalette">
<Grid RowDefinitions="Auto,Auto,Auto">
<v:RepositoryCommandPaletteTextBox Grid.Row="0"
x:Name="FilterTextBox"
Height="24"
Margin="4,8,4,0"
BorderThickness="1"
CornerRadius="12"
Text="{Binding Filter, Mode=TwoWay}"
BorderBrush="{DynamicResource Brush.Border2}"
VerticalContentAlignment="Center">
<TextBox.InnerLeftContent>
<StackPanel Orientation="Horizontal">
<Path Width="14" Height="14"
Margin="6,0,0,0"
Fill="{DynamicResource Brush.FG2}"
Data="{StaticResource Icons.Search}"/>
<Border BorderThickness="0"
Background="{DynamicResource Brush.Badge}"
Height="18"
CornerRadius="4"
Margin="4,0,0,0" Padding="4,0">
<TextBlock Text="{DynamicResource Text.Repository.CustomActions}"
Foreground="Black"
FontWeight="Bold"/>
</Border>
</StackPanel>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<Button Classes="icon_button"
Width="16"
Margin="0,0,6,0"
Command="{Binding ClearFilter}"
IsVisible="{Binding Filter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
HorizontalAlignment="Right">
<Path Width="14" Height="14"
Margin="0,1,0,0"
Fill="{DynamicResource Brush.FG1}"
Data="{StaticResource Icons.Clear}"/>
</Button>
</TextBox.InnerRightContent>
</v:RepositoryCommandPaletteTextBox>
<TextBlock Grid.Row="1"
Margin="6,12,0,0"
Text="{DynamicResource Text.CommandPalette.RepositoryActions}"
FontWeight="Bold"
Foreground="{DynamicResource Brush.FG2}"/>
<ListBox Grid.Row="2"
x:Name="ActionListBox"
MaxHeight="360"
Margin="4,8"
BorderThickness="0"
SelectionMode="Single"
Background="Transparent"
Focusable="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding VisibleActions, Mode=OneWay}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
IsVisible="{Binding VisibleActions, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="8,0"/>
<Setter Property="MinHeight" Value="26"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
<Style Selector="ListBox">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Grid/>
</FocusAdornerTemplate>
</Setter>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:ExecuteCustomActionCommandPaletteCmd">
<Grid ColumnDefinitions="Auto,*,Auto" Background="Transparent" Tapped="OnItemTapped">
<Path Grid.Column="0"
Width="12" Height="12"
Data="{StaticResource Icons.Action}"
IsHitTestVisible="False"/>
<TextBlock Grid.Column="1"
Margin="4,0,0,0"
VerticalAlignment="Center"
IsHitTestVisible="False"
Text="{Binding Name, Mode=OneWay}"/>
<Border Grid.Column="2" Margin="4,0,0,0" Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center" IsVisible="{Binding IsGlobal}">
<TextBlock Text="GLOBAL" Margin="8,0" FontSize="10" Foreground="White"/>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Path Grid.Row="2"
Width="64" Height="64"
Margin="0,16,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="{DynamicResource Brush.FG2}"
Data="{StaticResource Icons.Empty}"
IsVisible="{Binding VisibleActions, Mode=OneWay, Converter={x:Static c:ListConverters.IsNullOrEmpty}}"/>
</Grid>
</UserControl>

View File

@@ -0,0 +1,63 @@
using Avalonia.Controls;
using Avalonia.Input;
namespace SourceGit.Views
{
public partial class ExecuteCustomActionCommandPalette : UserControl
{
public ExecuteCustomActionCommandPalette()
{
InitializeComponent();
}
protected override async void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (DataContext is not ViewModels.ExecuteCustomActionCommandPalette vm)
return;
if (e.Key == Key.Enter)
{
await vm.ExecAsync();
e.Handled = true;
}
else if (e.Key == Key.Up)
{
if (ActionListBox.IsKeyboardFocusWithin)
{
FilterTextBox.Focus(NavigationMethod.Directional);
e.Handled = true;
return;
}
}
else if (e.Key == Key.Down || e.Key == Key.Tab)
{
if (FilterTextBox.IsKeyboardFocusWithin)
{
if (vm.VisibleActions.Count > 0)
ActionListBox.Focus(NavigationMethod.Directional);
e.Handled = true;
return;
}
if (ActionListBox.IsKeyboardFocusWithin && e.Key == Key.Tab)
{
FilterTextBox.Focus(NavigationMethod.Directional);
e.Handled = true;
return;
}
}
}
private async void OnItemTapped(object sender, TappedEventArgs e)
{
if (DataContext is ViewModels.ExecuteCustomActionCommandPalette vm)
{
await vm.ExecAsync();
e.Handled = true;
}
}
}
}

View File

@@ -59,8 +59,8 @@
BorderThickness="1"
Margin="8,4,4,8"
BorderBrush="{DynamicResource Brush.Border2}"
ItemsSource="{Binding Commits}"
SelectedItems="{Binding SelectedCommits, Mode=TwoWay}"
ItemsSource="{Binding Revisions}"
SelectedItems="{Binding SelectedRevisions, Mode=TwoWay}"
SelectionMode="Multiple"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
@@ -79,7 +79,7 @@
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Commit">
<DataTemplate DataType="m:FileVersion">
<Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,96">
@@ -93,7 +93,12 @@
TextDecorations="Underline"
Margin="8,0,0,0"
PointerPressed="OnPressCommitSHA"/>
<TextBlock Grid.Column="3" Text="{Binding AuthorTimeShortStr}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
<v:DateTimePresenter Grid.Column="3"
Margin="8,0,0,0"
ShowDateOnly="True"
Timestamp="{Binding AuthorTime}"
Foreground="{DynamicResource Brush.FG2}"
HorizontalAlignment="Right"/>
</Grid>
<Border Grid.Row="1" Background="Transparent" DataContextChanged="OnCommitSubjectDataContextChanged" PointerMoved="OnCommitSubjectPointerMoved">
@@ -110,7 +115,8 @@
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="Transparent"
BorderThickness="1,0,0,0"
BorderBrush="{DynamicResource Brush.Border0}"/>
BorderBrush="{DynamicResource Brush.Border0}"
Focusable="False"/>
<ContentControl Grid.Column="2" Content="{Binding ViewContent}">
<ContentControl.DataTemplates>
@@ -195,19 +201,19 @@
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" Margin="4,6" ColumnDefinitions="*,32,*,Auto">
<Grid.DataTemplates>
<DataTemplate DataType="m:Commit">
<DataTemplate DataType="m:FileVersion">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto,Auto">
<v:Avatar Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto">
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<Border Grid.Column="2" Background="{DynamicResource Brush.Accent}" CornerRadius="4" IsVisible="{Binding IsCurrentHead}">
<TextBlock Text="HEAD" Margin="4,0" Foreground="#FFDDDDDD"/>
</Border>
<TextBlock Grid.Column="3" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" Cursor="Hand" PointerPressed="OnPressCommitSHA" />
<TextBlock Grid.Column="4" Text="{Binding CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" Cursor="Hand" PointerPressed="OnPressCommitSHA" />
<v:DateTimePresenter Grid.Column="3"
Margin="8,0,0,0"
Timestamp="{Binding AuthorTime}"
Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
<TextBlock Grid.Row="1" Text="{Binding Subject}" VerticalAlignment="Bottom"/>
<TextBlock Grid.Row="1" Margin="0,6,0,0" Text="{Binding Subject}" TextTrimming="CharacterEllipsis" VerticalAlignment="Bottom"/>
</Grid>
</DataTemplate>
</Grid.DataTemplates>

View File

@@ -16,10 +16,10 @@ namespace SourceGit.Views
private void OnPressCommitSHA(object sender, PointerPressedEventArgs e)
{
if (sender is TextBlock { DataContext: Models.Commit commit } &&
if (sender is TextBlock { DataContext: Models.FileVersion ver } &&
DataContext is ViewModels.FileHistories vm)
{
vm.NavigateToCommit(commit);
vm.NavigateToCommit(ver);
}
e.Handled = true;
@@ -76,12 +76,12 @@ namespace SourceGit.Views
private void OnCommitSubjectPointerMoved(object sender, PointerEventArgs e)
{
if (sender is Border { DataContext: Models.Commit commit } border &&
if (sender is Border { DataContext: Models.FileVersion ver } border &&
DataContext is ViewModels.FileHistories vm)
{
var tooltip = ToolTip.GetTip(border);
if (tooltip == null)
ToolTip.SetTip(border, vm.GetCommitFullMessage(commit));
ToolTip.SetTip(border, vm.GetCommitFullMessage(ver));
}
}

View File

@@ -8,7 +8,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.FileHistoryCommandPalette"
x:DataType="vm:FileHistoryCommandPalette">
<Grid RowDefinitions="Auto,Auto">
<Grid RowDefinitions="Auto,Auto,Auto">
<v:RepositoryCommandPaletteTextBox Grid.Row="0"
x:Name="FilterTextBox"
Height="24"
@@ -51,10 +51,16 @@
</TextBox.InnerRightContent>
</v:RepositoryCommandPaletteTextBox>
<ListBox Grid.Row="1"
<TextBlock Grid.Row="1"
Margin="6,12,0,0"
Text="{DynamicResource Text.CommandPalette.RevisionFiles}"
FontWeight="Bold"
Foreground="{DynamicResource Brush.FG2}"/>
<ListBox Grid.Row="2"
x:Name="FileListBox"
MaxHeight="250"
Margin="4,8,4,0"
MaxHeight="360"
Margin="4,8"
BorderThickness="0"
SelectionMode="Single"
Background="Transparent"
@@ -88,7 +94,7 @@
<ListBox.ItemTemplate>
<DataTemplate DataType="x:String">
<Grid ColumnDefinitions="Auto,*" Background="Transparent" Tapped="OnItemTapped">
<Grid ColumnDefinitions="Auto,*" Background="Transparent" Tapped="OnItemTapped" ToolTip.Tip="{Binding}">
<Path Grid.Column="0"
Width="12" Height="12"
Data="{StaticResource Icons.File}"

View File

@@ -4,7 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SourceGit.Views.GitFlowStart"
x:DataType="vm:GitFlowStart">
@@ -38,8 +37,7 @@
VerticalAlignment="Center"
CornerRadius="2"
Watermark="{DynamicResource Text.GitFlow.StartPlaceholder}"
Text="{Binding Name, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Text="{Binding Name, Mode=TwoWay}"/>
</Grid>
</StackPanel>
</UserControl>

View File

@@ -87,11 +87,11 @@
Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
Foreground="DarkOrange"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="3"
Margin="4,0"
Text="{Binding CommitterTimeShortStr}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
<v:DateTimePresenter Grid.Column="3"
Margin="4,0"
Timestamp="{Binding CommitterTime}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

View File

@@ -157,6 +157,7 @@
</v:CommitRefsPresenter>
<v:CommitSubjectPresenter Grid.Column="3"
Height="26"
FontFamily="{DynamicResource Fonts.Default}"
CodeFontFamily="{DynamicResource Fonts.Monospace}"
InlineCodeBackground="{DynamicResource Brush.InlineCode}"
@@ -241,8 +242,9 @@
<v:CommitTimeTextBlock FontWeight="{Binding IsCurrentHead, Converter={x:Static c:BoolConverters.IsBoldToFontWeight}}"
Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}"
UseAuthorTime="{Binding Source={x:Static vm:Preferences.Instance}, Path=ShowAuthorTimeInGraph, Mode=OneWay}"
ShowAsDateTime="{Binding Source={x:Static vm:Preferences.Instance}, Path=!DisplayTimeAsPeriodInHistories}"
DateTimeFormat="{Binding Source={x:Static vm:Preferences.Instance}, Path=DateTimeFormat}"/>
ShowAsDateTime="{Binding Source={x:Static vm:Preferences.Instance}, Path=!DisplayTimeAsPeriodInHistories, Mode=OneWay}"
DateTimeFormat="{Binding Source={x:Static vm:Preferences.Instance}, Path=DateTimeFormat, Mode=OneWay}"
Use24Hours="{Binding Source={x:Static vm:Preferences.Instance}, Path=Use24Hours, Mode=OneWay}"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
@@ -277,7 +279,8 @@
MinWidth="1" MinHeight="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="{DynamicResource Brush.Window}"
BorderBrush="{DynamicResource Brush.Border0}"/>
BorderBrush="{DynamicResource Brush.Border0}"
Focusable="False"/>
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3">
<Grid IsVisible="{Binding DetailContext, Converter={x:Static ObjectConverters.IsNull}}">

View File

@@ -87,7 +87,7 @@
<TextBlock Grid.Row="0" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+H, macOS=⌘+⇧+H}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.GoHome}" />
<TextBlock Grid.Row="1" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+F, macOS=⌘+F}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+F, macOS=⌘+⇧+F}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.OpenSearchCommits}" />
<TextBlock Grid.Row="2" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+1, macOS=⌘+1}"/>

View File

@@ -16,11 +16,12 @@
Classes="bold"
Text="{DynamicResource Text.Init}"/>
</StackPanel>
<Grid Margin="0,16,8,0" ColumnDefinitions="100,*">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="Auto" MinHeight="32"/>
<RowDefinition Height="Auto" MinHeight="32"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
@@ -29,9 +30,17 @@
Margin="0,0,8,0"/>
<TextBlock Grid.Row="0" Grid.Column="1"
Text="{Binding TargetPath}"/>
<TextBlock Grid.Row="1" Grid.Column="1"
Foreground="{DynamicResource Brush.FG2}"
Text="{Binding Reason}"
TextWrapping="Wrap">
<Run Text="{DynamicResource Text.Init.ErrorMessageTip}"/>
<Run Text="{Binding Reason, Mode=OneWay}" />
</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="1"
Margin="0,8,0,0"
Text="{DynamicResource Text.Init.CommandTip}"
TextWrapping="Wrap"/>
</Grid>
</StackPanel>

View File

@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SourceGit.Views.InitGitFlow"
x:DataType="vm:InitGitFlow">
@@ -27,8 +26,7 @@
Height="26"
VerticalAlignment="Center"
CornerRadius="2"
Text="{Binding Master, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Text="{Binding Master, Mode=TwoWay}"/>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"

View File

@@ -155,6 +155,7 @@
</Button>
<v:CommitSubjectPresenter Grid.Column="1"
Height="28"
Margin="0,0,4,0"
FontFamily="{DynamicResource Fonts.Default}"
CodeFontFamily="{DynamicResource Fonts.Monospace}"
@@ -164,8 +165,8 @@
Subject="{Binding Subject}"
IssueTrackers="{Binding $parent[v:InteractiveRebase].((vm:InteractiveRebase)DataContext).IssueTrackers}"
FontWeight="Normal"
Opacity="{Binding IsFullMessageUsed, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}"
ShowStrikethrough="{Binding Action, Mode=OneWay, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:InteractiveRebaseAction.Drop}}"/>
Opacity="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.ToOpacity}}"
ShowStrikethrough="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.IsDrop}}"/>
</Grid>
<!-- Author Avatar -->
@@ -173,27 +174,29 @@
Width="16" Height="16"
Margin="8,0,0,0"
VerticalAlignment="Center"
User="{Binding Commit.Author}"
Opacity="{Binding IsFullMessageUsed, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}"/>
User="{Binding Commit.Author}"/>
<!-- Author Name -->
<Border Grid.Column="5" ClipToBounds="True">
<TextBlock Margin="6,0,12,0"
Text="{Binding Commit.Author.Name}"
Opacity="{Binding IsFullMessageUsed, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}"/>
Text="{Binding Commit.Author.Name}"
Opacity="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.ToOpacity}}"
Classes.dropped="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.IsDrop}}"/>
</Border>
<!-- Commit SHA -->
<Border Grid.Column="6" ClipToBounds="True">
<TextBlock Text="{Binding Commit.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
Opacity="{Binding IsFullMessageUsed, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}"/>
Opacity="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.ToOpacity}}"
Classes.dropped="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.IsDrop}}"/>
</Border>
<!-- Commit Time -->
<Border Grid.Column="7">
<TextBlock Margin="16,0,8,0"
Text="{Binding Commit.CommitterTimeStr}"
Opacity="{Binding IsFullMessageUsed, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}"/>
<v:DateTimePresenter Margin="16,0,8,0"
Timestamp="{Binding Commit.CommitterTime}"
Opacity="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.ToOpacity}}"
Classes.dropped="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.IsDrop}}"/>
</Border>
</Grid>
</DataTemplate>
@@ -207,7 +210,8 @@
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="Transparent"
BorderThickness="0,1,0,0"
BorderBrush="{DynamicResource Brush.Border2}"/>
BorderBrush="{DynamicResource Brush.Border2}"
Focusable="False"/>
<ContentControl Grid.Row="2">
<ContentControl.Content>

View File

@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.LFSTrackCustomPattern"
x:DataType="vm:LFSTrackCustomPattern">
@@ -26,8 +25,7 @@
<TextBox Grid.Row="0" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding Pattern, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True"/>
Text="{Binding Pattern, Mode=TwoWay}"/>
<CheckBox Grid.Row="1" Grid.Column="1"
Content="{DynamicResource Text.GitLFS.AddTrackPattern.IsFilename}"

Some files were not shown because too many files have changed in this diff Show More