mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-06-24 11:54:59 +00:00
Merge branch 'sourcegit-scm:develop' into develop
This commit is contained in:
commit
50341e468e
47 changed files with 882 additions and 405 deletions
|
@ -293,6 +293,10 @@ end_of_line = lf
|
||||||
[*.{cmd,bat}]
|
[*.{cmd,bat}]
|
||||||
end_of_line = crlf
|
end_of_line = crlf
|
||||||
|
|
||||||
|
# Package manifests
|
||||||
|
[{*.spec,control}]
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
# YAML files
|
# YAML files
|
||||||
[*.{yml,yaml}]
|
[*.{yml,yaml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
4
.gitattributes
vendored
4
.gitattributes
vendored
|
@ -3,10 +3,12 @@
|
||||||
*.png binary
|
*.png binary
|
||||||
*.ico binary
|
*.ico binary
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf
|
||||||
|
*.spec text eol=lf
|
||||||
|
control text eol=lf
|
||||||
*.bat text eol=crlf
|
*.bat text eol=crlf
|
||||||
*.cmd text eol=crlf
|
*.cmd text eol=crlf
|
||||||
*.ps1 text eol=crlf
|
*.ps1 text eol=crlf
|
||||||
*.json text
|
*.json text
|
||||||
|
|
||||||
.gitattributes export-ignore
|
.gitattributes export-ignore
|
||||||
.gitignore export-ignore
|
.gitignore export-ignore
|
||||||
|
|
2
.github/workflows/package.yml
vendored
2
.github/workflows/package.yml
vendored
|
@ -3,7 +3,7 @@ on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: Source Git package version
|
description: SourceGit package version
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
jobs:
|
jobs:
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
## Translation Status
|
## Translation Status
|
||||||
|
|
||||||
[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
|
[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
|
||||||
|
|
||||||
## How to Use
|
## How to Use
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,4 @@
|
||||||
### de_DE.axaml: 98.70%
|
### de_DE.axaml: 100.00%
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Missing Keys</summary>
|
|
||||||
|
|
||||||
- Text.Diff.SaveAsPatch
|
|
||||||
- Text.Diff.VisualLines.All
|
|
||||||
- Text.Hotkeys.Repo.CreateBranchOnCommit
|
|
||||||
- Text.Hotkeys.Repo.Fetch
|
|
||||||
- Text.Hotkeys.Repo.Pull
|
|
||||||
- Text.Hotkeys.Repo.Push
|
|
||||||
- Text.IssueLinkCM.OpenInBrowser
|
|
||||||
- Text.IssueLinkCM.CopyLink
|
|
||||||
- Text.Preference.Appearance.EditorFontSize
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### es_ES.axaml: 100.00%
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
@ -26,7 +8,19 @@
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### fr_FR.axaml: 86.58%
|
### es_ES.axaml: 99.57%
|
||||||
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Missing Keys</summary>
|
||||||
|
|
||||||
|
- Text.Preference.Appearance.FontSize
|
||||||
|
- Text.Preference.Appearance.FontSize.Default
|
||||||
|
- Text.Preference.Appearance.FontSize.Editor
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### fr_FR.axaml: 86.31%
|
||||||
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
@ -99,7 +93,9 @@
|
||||||
- Text.Preference.AI.Model
|
- Text.Preference.AI.Model
|
||||||
- Text.Preference.AI.Name
|
- Text.Preference.AI.Name
|
||||||
- Text.Preference.AI.Server
|
- Text.Preference.AI.Server
|
||||||
- Text.Preference.Appearance.EditorFontSize
|
- Text.Preference.Appearance.FontSize
|
||||||
|
- Text.Preference.Appearance.FontSize.Default
|
||||||
|
- Text.Preference.Appearance.FontSize.Editor
|
||||||
- Text.Preference.General.ShowAuthorTime
|
- Text.Preference.General.ShowAuthorTime
|
||||||
- Text.Preference.Integration
|
- Text.Preference.Integration
|
||||||
- Text.Preference.Shell
|
- Text.Preference.Shell
|
||||||
|
@ -128,13 +124,15 @@
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### pt_BR.axaml: 100.00%
|
### pt_BR.axaml: 99.57%
|
||||||
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Missing Keys</summary>
|
<summary>Missing Keys</summary>
|
||||||
|
|
||||||
|
- Text.Preference.Appearance.FontSize
|
||||||
|
- Text.Preference.Appearance.FontSize.Default
|
||||||
|
- Text.Preference.Appearance.FontSize.Editor
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=Source Git
|
Name=SourceGit
|
||||||
Comment=Open-source & Free Git GUI Client
|
Comment=Open-source & Free Git GUI Client
|
||||||
Exec=/opt/sourcegit/sourcegit
|
Exec=/opt/sourcegit/sourcegit
|
||||||
Icon=/usr/share/icons/sourcegit.png
|
Icon=/usr/share/icons/sourcegit.png
|
||||||
|
|
|
@ -5,8 +5,8 @@ Summary: Open-source & Free Git Gui Client
|
||||||
License: MIT
|
License: MIT
|
||||||
URL: https://sourcegit-scm.github.io/
|
URL: https://sourcegit-scm.github.io/
|
||||||
Source: https://github.com/sourcegit-scm/sourcegit/archive/refs/tags/v%_version.tar.gz
|
Source: https://github.com/sourcegit-scm/sourcegit/archive/refs/tags/v%_version.tar.gz
|
||||||
Requires: (libX11 or libX11-6)
|
Requires: libX11.so.6()(%{__isa_bits}bit)
|
||||||
Requires: (libSM or libSM6)
|
Requires: libSM.so.6()(%{__isa_bits}bit)
|
||||||
|
|
||||||
%define _build_id_links none
|
%define _build_id_links none
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,6 @@ set -o
|
||||||
set -u
|
set -u
|
||||||
set pipefail
|
set pipefail
|
||||||
|
|
||||||
if [[ -z "$VERSION" ]]; then
|
|
||||||
echo "Provide the version as environment variable VERSION"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$RUNTIME" ]]; then
|
|
||||||
echo "Provide the runtime as environment variable RUNTIME"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
arch=
|
arch=
|
||||||
appimage_arch=
|
appimage_arch=
|
||||||
target=
|
target=
|
||||||
|
|
|
@ -5,16 +5,6 @@ set -o
|
||||||
set -u
|
set -u
|
||||||
set pipefail
|
set pipefail
|
||||||
|
|
||||||
if [[ -z "$VERSION" ]]; then
|
|
||||||
echo "Provide the version as environment variable VERSION"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$RUNTIME" ]]; then
|
|
||||||
echo "Provide the runtime as environment variable RUNTIME"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
mkdir -p SourceGit.app/Contents/Resources
|
mkdir -p SourceGit.app/Contents/Resources
|
||||||
|
|
|
@ -5,16 +5,6 @@ set -o
|
||||||
set -u
|
set -u
|
||||||
set pipefail
|
set pipefail
|
||||||
|
|
||||||
if [[ -z "$VERSION" ]]; then
|
|
||||||
echo "Provide the version as environment variable VERSION"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$RUNTIME" ]]; then
|
|
||||||
echo "Provide the runtime as environment variable RUNTIME"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
rm -rf SourceGit/*.pdb
|
rm -rf SourceGit/*.pdb
|
||||||
|
|
|
@ -48,8 +48,18 @@
|
||||||
var cmd = new Command();
|
var cmd = new Command();
|
||||||
cmd.WorkingDirectory = repo;
|
cmd.WorkingDirectory = repo;
|
||||||
cmd.Context = repo;
|
cmd.Context = repo;
|
||||||
cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
|
||||||
cmd.Args = $"push {remote} --delete {name}";
|
bool exists = new Remote(repo).HasBranch(remote, name);
|
||||||
|
if (exists)
|
||||||
|
{
|
||||||
|
cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||||
|
cmd.Args = $"push {remote} --delete {name}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmd.Args = $"branch -D -r {remote}/{name}";
|
||||||
|
}
|
||||||
|
|
||||||
return cmd.Exec();
|
return cmd.Exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,7 @@ namespace SourceGit.Commands
|
||||||
_oldLine = int.Parse(match.Groups[1].Value);
|
_oldLine = int.Parse(match.Groups[1].Value);
|
||||||
_newLine = int.Parse(match.Groups[2].Value);
|
_newLine = int.Parse(match.Groups[2].Value);
|
||||||
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
|
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace SourceGit.Commands
|
||||||
{
|
{
|
||||||
outputHandler?.Invoke(e.Data);
|
outputHandler?.Invoke(e.Data);
|
||||||
builder.AppendLine(e.Data);
|
builder.AppendLine(e.Data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace SourceGit.Commands
|
||||||
if (noTags)
|
if (noTags)
|
||||||
Args += "--no-tags ";
|
Args += "--no-tags ";
|
||||||
else
|
else
|
||||||
Args += "--force ";
|
Args += "--tags ";
|
||||||
|
|
||||||
if (prune)
|
if (prune)
|
||||||
Args += "--prune ";
|
Args += "--prune ";
|
||||||
|
|
|
@ -45,5 +45,14 @@
|
||||||
Args = "remote set-url" + (isPush ? " --push " : " ") + $"{name} {url}";
|
Args = "remote set-url" + (isPush ? " --push " : " ") + $"{name} {url}";
|
||||||
return Exec();
|
return Exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasBranch(string remote, string branch)
|
||||||
|
{
|
||||||
|
SSHKey = new Config(WorkingDirectory).Get($"remote.{remote}.sshkey");
|
||||||
|
Args = $"ls-remote {remote} {branch}";
|
||||||
|
|
||||||
|
var rs = ReadToEnd();
|
||||||
|
return rs.IsSuccess && rs.StdOut.Trim().Length > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
60
src/Models/Filter.cs
Normal file
60
src/Models/Filter.cs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace SourceGit.Models
|
||||||
|
{
|
||||||
|
public enum FilterType
|
||||||
|
{
|
||||||
|
LocalBranch = 0,
|
||||||
|
LocalBranchFolder,
|
||||||
|
RemoteBranch,
|
||||||
|
RemoteBranchFolder,
|
||||||
|
Tag,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FilterMode
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Included,
|
||||||
|
Excluded,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Filter : ObservableObject
|
||||||
|
{
|
||||||
|
public string Pattern
|
||||||
|
{
|
||||||
|
get => _pattern;
|
||||||
|
set => SetProperty(ref _pattern, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterType Type
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
} = FilterType.LocalBranch;
|
||||||
|
|
||||||
|
public FilterMode Mode
|
||||||
|
{
|
||||||
|
get => _mode;
|
||||||
|
set => SetProperty(ref _mode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsBranch
|
||||||
|
{
|
||||||
|
get => Type != FilterType.Tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Filter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Filter(string pattern, FilterType type, FilterMode mode)
|
||||||
|
{
|
||||||
|
_pattern = pattern;
|
||||||
|
_mode = mode;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _pattern = string.Empty;
|
||||||
|
private FilterMode _mode = FilterMode.None;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,9 @@
|
||||||
using Avalonia.Collections;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Avalonia.Collections;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
|
||||||
namespace SourceGit.Models
|
namespace SourceGit.Models
|
||||||
{
|
{
|
||||||
|
@ -76,11 +81,11 @@ namespace SourceGit.Models
|
||||||
set;
|
set;
|
||||||
} = true;
|
} = true;
|
||||||
|
|
||||||
public AvaloniaList<string> Filters
|
public AvaloniaList<Filter> HistoriesFilters
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
} = new AvaloniaList<string>();
|
} = new AvaloniaList<Filter>();
|
||||||
|
|
||||||
public AvaloniaList<CommitTemplate> CommitTemplates
|
public AvaloniaList<CommitTemplate> CommitTemplates
|
||||||
{
|
{
|
||||||
|
@ -148,6 +153,177 @@ namespace SourceGit.Models
|
||||||
set;
|
set;
|
||||||
} = "---";
|
} = "---";
|
||||||
|
|
||||||
|
public FilterMode GetHistoriesFilterMode(string pattern, FilterType type)
|
||||||
|
{
|
||||||
|
foreach (var filter in HistoriesFilters)
|
||||||
|
{
|
||||||
|
if (filter.Type != type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
|
||||||
|
return filter.Mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilterMode.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UpdateHistoriesFilter(string pattern, FilterType type, FilterMode mode)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < HistoriesFilters.Count; i++)
|
||||||
|
{
|
||||||
|
var filter = HistoriesFilters[i];
|
||||||
|
if (filter.Type != type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
if (mode == FilterMode.None)
|
||||||
|
{
|
||||||
|
HistoriesFilters.RemoveAt(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode != filter.Mode)
|
||||||
|
{
|
||||||
|
filter.Mode = mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode != FilterMode.None)
|
||||||
|
{
|
||||||
|
HistoriesFilters.Add(new Filter(pattern, type, mode));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BuildHistoriesFilter()
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
|
var excludedBranches = new List<string>();
|
||||||
|
var excludedRemotes = new List<string>();
|
||||||
|
var excludedTags = new List<string>();
|
||||||
|
var includedBranches = new List<string>();
|
||||||
|
var includedRemotes = new List<string>();
|
||||||
|
var includedTags = new List<string>();
|
||||||
|
foreach (var filter in HistoriesFilters)
|
||||||
|
{
|
||||||
|
if (filter.Type == FilterType.LocalBranch)
|
||||||
|
{
|
||||||
|
var name = filter.Pattern.Substring(11);
|
||||||
|
var b = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
|
||||||
|
|
||||||
|
if (filter.Mode == FilterMode.Included)
|
||||||
|
includedBranches.Add(b);
|
||||||
|
else if (filter.Mode == FilterMode.Excluded)
|
||||||
|
excludedBranches.Add(b);
|
||||||
|
}
|
||||||
|
else if (filter.Type == FilterType.LocalBranchFolder)
|
||||||
|
{
|
||||||
|
if (filter.Mode == FilterMode.Included)
|
||||||
|
includedBranches.Add($"{filter.Pattern.Substring(11)}/*");
|
||||||
|
else if (filter.Mode == FilterMode.Excluded)
|
||||||
|
excludedBranches.Add($"{filter.Pattern.Substring(11)}/*");
|
||||||
|
}
|
||||||
|
else if (filter.Type == FilterType.RemoteBranch)
|
||||||
|
{
|
||||||
|
var name = filter.Pattern.Substring(13);
|
||||||
|
var r = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
|
||||||
|
|
||||||
|
if (filter.Mode == FilterMode.Included)
|
||||||
|
includedRemotes.Add(r);
|
||||||
|
else if (filter.Mode == FilterMode.Excluded)
|
||||||
|
excludedRemotes.Add(r);
|
||||||
|
}
|
||||||
|
else if (filter.Type == FilterType.RemoteBranchFolder)
|
||||||
|
{
|
||||||
|
if (filter.Mode == FilterMode.Included)
|
||||||
|
includedRemotes.Add($"{filter.Pattern.Substring(13)}/*");
|
||||||
|
else if (filter.Mode == FilterMode.Excluded)
|
||||||
|
excludedRemotes.Add($"{filter.Pattern.Substring(13)}/*");
|
||||||
|
}
|
||||||
|
else if (filter.Type == FilterType.Tag)
|
||||||
|
{
|
||||||
|
var name = filter.Pattern;
|
||||||
|
var t = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
|
||||||
|
|
||||||
|
if (filter.Mode == FilterMode.Included)
|
||||||
|
includedTags.Add(t);
|
||||||
|
else if (filter.Mode == FilterMode.Excluded)
|
||||||
|
excludedTags.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var b in excludedBranches)
|
||||||
|
{
|
||||||
|
builder.Append("--exclude=");
|
||||||
|
builder.Append(b);
|
||||||
|
builder.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includedBranches.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var b in includedBranches)
|
||||||
|
{
|
||||||
|
builder.Append("--branches=");
|
||||||
|
builder.Append(b);
|
||||||
|
builder.Append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (excludedBranches.Count > 0)
|
||||||
|
{
|
||||||
|
builder.Append("--branches ");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var r in excludedRemotes)
|
||||||
|
{
|
||||||
|
builder.Append("--exclude=");
|
||||||
|
builder.Append(r);
|
||||||
|
builder.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includedRemotes.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var r in includedRemotes)
|
||||||
|
{
|
||||||
|
builder.Append("--remotes=");
|
||||||
|
builder.Append(r);
|
||||||
|
builder.Append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (excludedRemotes.Count > 0)
|
||||||
|
{
|
||||||
|
builder.Append("--remotes ");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in excludedTags)
|
||||||
|
{
|
||||||
|
builder.Append("--exclude=");
|
||||||
|
builder.Append(t);
|
||||||
|
builder.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includedTags.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var t in includedTags)
|
||||||
|
{
|
||||||
|
builder.Append("--tags=");
|
||||||
|
builder.Append(t);
|
||||||
|
builder.Append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (excludedTags.Count > 0)
|
||||||
|
{
|
||||||
|
builder.Append("--tags ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public void PushCommitMessage(string message)
|
public void PushCommitMessage(string message)
|
||||||
{
|
{
|
||||||
var existIdx = CommitMessages.IndexOf(message);
|
var existIdx = CommitMessages.IndexOf(message);
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
namespace SourceGit.Models
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace SourceGit.Models
|
||||||
{
|
{
|
||||||
public class Tag
|
public class Tag : ObservableObject
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; } = string.Empty;
|
||||||
public string SHA { get; set; }
|
public string SHA { get; set; } = string.Empty;
|
||||||
public string Message { get; set; }
|
public string Message { get; set; } = string.Empty;
|
||||||
public bool IsFiltered { get; set; }
|
|
||||||
|
public FilterMode FilterMode
|
||||||
|
{
|
||||||
|
get => _filterMode;
|
||||||
|
set => SetProperty(ref _filterMode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FilterMode _filterMode = FilterMode.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
<x:String x:Key="Text.Cancel" xml:space="preserve">ABBRECHEN</x:String>
|
<x:String x:Key="Text.Cancel" xml:space="preserve">ABBRECHEN</x:String>
|
||||||
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Auf diese Revision zurücksetzen</x:String>
|
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Auf diese Revision zurücksetzen</x:String>
|
||||||
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Auf Vorgänger-Revision zurücksetzen</x:String>
|
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Auf Vorgänger-Revision zurücksetzen</x:String>
|
||||||
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Generiere Commit-Nachricht</x:String>
|
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Generiere Commit-Nachricht</x:String>
|
||||||
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">ANZEIGE MODUS ÄNDERN</x:String>
|
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">ANZEIGE MODUS ÄNDERN</x:String>
|
||||||
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Zeige als Datei- und Ordnerliste</x:String>
|
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Zeige als Datei- und Ordnerliste</x:String>
|
||||||
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Zeige als Pfadliste</x:String>
|
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Zeige als Pfadliste</x:String>
|
||||||
|
@ -240,6 +240,7 @@
|
||||||
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Nächste Änderung</x:String>
|
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Nächste Änderung</x:String>
|
||||||
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN</x:String>
|
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN</x:String>
|
||||||
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Vorherige Änderung</x:String>
|
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Vorherige Änderung</x:String>
|
||||||
|
<x:String x:Key="Text.Diff.SaveAsPatch" xml:space="preserve">Als Patch speichern</x:String>
|
||||||
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Zeige versteckte Symbole</x:String>
|
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Zeige versteckte Symbole</x:String>
|
||||||
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Nebeneinander</x:String>
|
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Nebeneinander</x:String>
|
||||||
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SUBMODUL</x:String>
|
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SUBMODUL</x:String>
|
||||||
|
@ -248,6 +249,7 @@
|
||||||
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Syntax Hervorhebung</x:String>
|
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Syntax Hervorhebung</x:String>
|
||||||
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Zeilenumbruch</x:String>
|
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Zeilenumbruch</x:String>
|
||||||
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Öffne in Merge Tool</x:String>
|
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Öffne in Merge Tool</x:String>
|
||||||
|
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">Alle Zeilen anzeigen</x:String>
|
||||||
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Weniger Zeilen anzeigen</x:String>
|
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Weniger Zeilen anzeigen</x:String>
|
||||||
<x:String x:Key="Text.Diff.VisualLines.Incr" xml:space="preserve">Mehr Zeilen anzeigen</x:String>
|
<x:String x:Key="Text.Diff.VisualLines.Incr" xml:space="preserve">Mehr Zeilen anzeigen</x:String>
|
||||||
<x:String x:Key="Text.Diff.Welcome" xml:space="preserve">WÄHLE EINE DATEI AUS UM ÄNDERUNGEN ANZUZEIGEN</x:String>
|
<x:String x:Key="Text.Diff.Welcome" xml:space="preserve">WÄHLE EINE DATEI AUS UM ÄNDERUNGEN ANZUZEIGEN</x:String>
|
||||||
|
@ -364,8 +366,12 @@
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Gestagte Änderungen committen</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Gestagte Änderungen committen</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Gestagte Änderungen committen und pushen</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Gestagte Änderungen committen und pushen</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Alle Änderungen stagen und committen</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Alle Änderungen stagen und committen</x:String>
|
||||||
|
<x:String x:Key="Text.Hotkeys.Repo.CreateBranchOnCommit" xml:space="preserve">Neuen Branch basierend auf ausgewählten Commit erstellen</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Ausgewählte Änderungen verwerfen</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Ausgewählte Änderungen verwerfen</x:String>
|
||||||
|
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, wird direkt ausgeführt</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard Modus (Standard)</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard Modus (Standard)</x:String>
|
||||||
|
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Pull, wird direkt ausgeführt</x:String>
|
||||||
|
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Push, wird direkt ausgeführt</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Erzwinge Neuladen des Repositorys</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Erzwinge Neuladen des Repositorys</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Ausgewählte Änderungen stagen/unstagen</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Ausgewählte Änderungen stagen/unstagen</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit-Suchmodus</x:String>
|
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit-Suchmodus</x:String>
|
||||||
|
@ -389,6 +395,8 @@
|
||||||
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Interaktiver Rebase</x:String>
|
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Interaktiver Rebase</x:String>
|
||||||
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Ziel Branch:</x:String>
|
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Ziel Branch:</x:String>
|
||||||
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">Auf:</x:String>
|
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">Auf:</x:String>
|
||||||
|
<x:String x:Key="Text.IssueLinkCM.OpenInBrowser" xml:space="preserve">In Browser öffnen</x:String>
|
||||||
|
<x:String x:Key="Text.IssueLinkCM.CopyLink" xml:space="preserve">Link kopieren</x:String>
|
||||||
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">FEHLER</x:String>
|
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">FEHLER</x:String>
|
||||||
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">INFO</x:String>
|
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">INFO</x:String>
|
||||||
<x:String x:Key="Text.Merge" xml:space="preserve">Branch mergen</x:String>
|
<x:String x:Key="Text.Merge" xml:space="preserve">Branch mergen</x:String>
|
||||||
|
@ -429,7 +437,9 @@
|
||||||
<x:String x:Key="Text.Preference.AI.Model" xml:space="preserve">Modell</x:String>
|
<x:String x:Key="Text.Preference.AI.Model" xml:space="preserve">Modell</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">DARSTELLUNG</x:String>
|
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">DARSTELLUNG</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Standardschriftart</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Standardschriftart</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Standardschriftgröße</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">Schriftgröße</x:String>
|
||||||
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">Standard</x:String>
|
||||||
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">Texteditor</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace-Schriftart</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace-Schriftart</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Verwende die Monospace-Schriftart nur im Texteditor</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Verwende die Monospace-Schriftart nur im Texteditor</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Design</x:String>
|
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Design</x:String>
|
||||||
|
|
|
@ -434,8 +434,9 @@
|
||||||
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Server</x:String>
|
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Server</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APPEARANCE</x:String>
|
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APPEARANCE</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Default Font</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Default Font</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Default Font Size</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">Font Size</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Editor Font Size</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">Default</x:String>
|
||||||
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">Editor</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace Font</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace Font</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Only use monospace font in text editor</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Only use monospace font in text editor</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Theme</x:String>
|
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Theme</x:String>
|
||||||
|
|
|
@ -438,8 +438,6 @@
|
||||||
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Servidor</x:String>
|
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Servidor</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APARIENCIA</x:String>
|
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APARIENCIA</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Fuente por defecto</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Fuente por defecto</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Tamaño de fuente por defecto</x:String>
|
|
||||||
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Tamaño de fuente del editor</x:String>
|
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Fuente Monospace</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Fuente Monospace</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Usar solo fuente monospace en el editor de texto</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Usar solo fuente monospace en el editor de texto</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Tema</x:String>
|
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Tema</x:String>
|
||||||
|
|
|
@ -371,7 +371,6 @@
|
||||||
<x:String x:Key="Text.Preference" xml:space="preserve">Préférences</x:String>
|
<x:String x:Key="Text.Preference" xml:space="preserve">Préférences</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APPARENCE</x:String>
|
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APPARENCE</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Police par défaut</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Police par défaut</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Taille de police par défaut</x:String>
|
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Police monospace</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Police monospace</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">N'utiliser que des polices monospace pour l'éditeur de texte</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">N'utiliser que des polices monospace pour l'éditeur de texte</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Thème</x:String>
|
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Thème</x:String>
|
||||||
|
|
|
@ -460,8 +460,6 @@
|
||||||
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Servidor</x:String>
|
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Servidor</x:String>
|
||||||
<x:String x:Key="Text.Preference.AI" xml:space="preserve">INTELIGÊNCIA ARTIFICIAL</x:String>
|
<x:String x:Key="Text.Preference.AI" xml:space="preserve">INTELIGÊNCIA ARTIFICIAL</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Fonte Padrão</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Fonte Padrão</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Tamanho da fonte padrão</x:String>
|
|
||||||
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Tamanho da fonte do editor</x:String>
|
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Fonte Monoespaçada</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Fonte Monoespaçada</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Usar fonte monoespaçada apenas no editor de texto</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Usar fonte monoespaçada apenas no editor de texto</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Tema</x:String>
|
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Tema</x:String>
|
||||||
|
|
|
@ -438,8 +438,9 @@
|
||||||
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Сервер</x:String>
|
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Сервер</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">ВИД</x:String>
|
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">ВИД</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Шрифт по-умолчанию</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Шрифт по-умолчанию</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Размер шрифта по-умолчанию</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">Размер шрифта</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Размер шрифта редактора</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">По-умолчанию</x:String>
|
||||||
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">Редактор</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Моноширный шрифт</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Моноширный шрифт</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">В текстовом редакторе используется только моноширный шрифт</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">В текстовом редакторе используется только моноширный шрифт</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Тема</x:String>
|
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Тема</x:String>
|
||||||
|
|
|
@ -437,7 +437,9 @@
|
||||||
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">服务地址</x:String>
|
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">服务地址</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">外观配置</x:String>
|
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">外观配置</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">缺省字体</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">缺省字体</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">默认字体大小</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">字体大小</x:String>
|
||||||
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">默认</x:String>
|
||||||
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">代码编辑器</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">代码字体大小</x:String>
|
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">代码字体大小</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">等宽字体</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">等宽字体</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">仅在文本编辑器中使用等宽字体</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">仅在文本编辑器中使用等宽字体</x:String>
|
||||||
|
|
|
@ -437,8 +437,9 @@
|
||||||
<x:String x:Key="Text.Preference.AI.GenerateSubjectPrompt" xml:space="preserve">產生提交訊息提示詞</x:String>
|
<x:String x:Key="Text.Preference.AI.GenerateSubjectPrompt" xml:space="preserve">產生提交訊息提示詞</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">外觀設定</x:String>
|
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">外觀設定</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">預設字型</x:String>
|
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">預設字型</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">預設字型大小</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">字型大小</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">程式碼字型大小</x:String>
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">預設</x:String>
|
||||||
|
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">程式碼</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">等寬字型</x:String>
|
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">等寬字型</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">僅在文字編輯器中使用等寬字型</x:String>
|
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">僅在文字編輯器中使用等寬字型</x:String>
|
||||||
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">佈景主題</x:String>
|
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">佈景主題</x:String>
|
||||||
|
|
|
@ -168,12 +168,13 @@
|
||||||
<Setter Property="TextBlock.TextDecorations" Value=""/>
|
<Setter Property="TextBlock.TextDecorations" Value=""/>
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<ControlTemplate>
|
<ControlTemplate>
|
||||||
<Grid Effect="drop-shadow(0 0 8 #80000000)">
|
<Grid Effect="drop-shadow(0 0 8 #30000000)">
|
||||||
<Border Margin="8"
|
<Border Margin="8"
|
||||||
Padding="8,6"
|
Padding="8,6"
|
||||||
CornerRadius="4"
|
CornerRadius="4"
|
||||||
Background="{DynamicResource Brush.Popup}"
|
Background="{DynamicResource Brush.Popup}"
|
||||||
BorderThickness="0"
|
BorderBrush="{DynamicResource Brush.Border2}"
|
||||||
|
BorderThickness="1"
|
||||||
MaxWidth="{TemplateBinding MaxWidth}"
|
MaxWidth="{TemplateBinding MaxWidth}"
|
||||||
MinHeight="{TemplateBinding MinHeight}"
|
MinHeight="{TemplateBinding MinHeight}"
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
|
HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
|
||||||
|
@ -1037,35 +1038,6 @@
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="ToggleButton.filter">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
<Setter Property="Padding" Value="0"/>
|
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
|
||||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
|
||||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<ControlTemplate>
|
|
||||||
<Border Background="Transparent">
|
|
||||||
<Path x:Name="PART_IndicatorIcon"
|
|
||||||
Width="12"
|
|
||||||
Data="{StaticResource Icons.Filter}"
|
|
||||||
Fill="Transparent"
|
|
||||||
StrokeThickness="1"
|
|
||||||
Stroke="{DynamicResource Brush.FG2}"
|
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ToggleButton.filter:pressed">
|
|
||||||
<Setter Property="RenderTransform" Value="scale(1)"/>
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ToggleButton.filter:checked /template/ Path#PART_IndicatorIcon">
|
|
||||||
<Setter Property="Fill" Value="{DynamicResource Brush.FG2}"/>
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ToggleButton.filter:pointerover /template/ Path#PART_IndicatorIcon">
|
|
||||||
<Setter Property="Stroke" Value="{DynamicResource Brush.Accent}"/>
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ToggleButton.tree_expander">
|
<Style Selector="ToggleButton.tree_expander">
|
||||||
<Setter Property="Margin" Value="0" />
|
<Setter Property="Margin" Value="0" />
|
||||||
<Setter Property="Width" Value="9" />
|
<Setter Property="Width" Value="9" />
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Collections;
|
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
@ -13,15 +11,16 @@ namespace SourceGit.ViewModels
|
||||||
public class BranchTreeNode : ObservableObject
|
public class BranchTreeNode : ObservableObject
|
||||||
{
|
{
|
||||||
public string Name { get; private set; } = string.Empty;
|
public string Name { get; private set; } = string.Empty;
|
||||||
|
public string Path { get; private set; } = string.Empty;
|
||||||
public object Backend { get; private set; } = null;
|
public object Backend { get; private set; } = null;
|
||||||
public int Depth { get; set; } = 0;
|
public int Depth { get; set; } = 0;
|
||||||
public bool IsSelected { get; set; } = false;
|
public bool IsSelected { get; set; } = false;
|
||||||
public List<BranchTreeNode> Children { get; private set; } = new List<BranchTreeNode>();
|
public List<BranchTreeNode> Children { get; private set; } = new List<BranchTreeNode>();
|
||||||
|
|
||||||
public bool IsFiltered
|
public Models.FilterMode FilterMode
|
||||||
{
|
{
|
||||||
get => _isFiltered;
|
get => _filterMode;
|
||||||
set => SetProperty(ref _isFiltered, value);
|
set => SetProperty(ref _filterMode, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsExpanded
|
public bool IsExpanded
|
||||||
|
@ -51,7 +50,7 @@ namespace SourceGit.ViewModels
|
||||||
get => Backend is Models.Branch b ? b.FriendlyName : null;
|
get => Backend is Models.Branch b ? b.FriendlyName : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _isFiltered = false;
|
private Models.FilterMode _filterMode = Models.FilterMode.None;
|
||||||
private bool _isExpanded = false;
|
private bool _isExpanded = false;
|
||||||
private CornerRadius _cornerRadius = new CornerRadius(4);
|
private CornerRadius _cornerRadius = new CornerRadius(4);
|
||||||
|
|
||||||
|
@ -60,18 +59,25 @@ namespace SourceGit.ViewModels
|
||||||
public List<BranchTreeNode> Locals => _locals;
|
public List<BranchTreeNode> Locals => _locals;
|
||||||
public List<BranchTreeNode> Remotes => _remotes;
|
public List<BranchTreeNode> Remotes => _remotes;
|
||||||
|
|
||||||
|
public Builder(Models.RepositorySettings settings)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
public void Run(List<Models.Branch> branches, List<Models.Remote> remotes, bool bForceExpanded)
|
public void Run(List<Models.Branch> branches, List<Models.Remote> remotes, bool bForceExpanded)
|
||||||
{
|
{
|
||||||
var folders = new Dictionary<string, BranchTreeNode>();
|
var folders = new Dictionary<string, BranchTreeNode>();
|
||||||
|
|
||||||
foreach (var remote in remotes)
|
foreach (var remote in remotes)
|
||||||
{
|
{
|
||||||
var path = $"remote/{remote.Name}";
|
var path = $"refs/remotes/{remote.Name}";
|
||||||
var node = new BranchTreeNode()
|
var node = new BranchTreeNode()
|
||||||
{
|
{
|
||||||
Name = remote.Name,
|
Name = remote.Name,
|
||||||
|
Path = path,
|
||||||
Backend = remote,
|
Backend = remote,
|
||||||
IsExpanded = bForceExpanded || _expanded.Contains(path),
|
IsExpanded = bForceExpanded || _expanded.Contains(path),
|
||||||
|
FilterMode = _settings.GetHistoriesFilterMode(path, Models.FilterType.RemoteBranchFolder)
|
||||||
};
|
};
|
||||||
|
|
||||||
folders.Add(path, node);
|
folders.Add(path, node);
|
||||||
|
@ -80,16 +86,15 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
foreach (var branch in branches)
|
foreach (var branch in branches)
|
||||||
{
|
{
|
||||||
var isFiltered = _filters.Contains(branch.FullName);
|
|
||||||
if (branch.IsLocal)
|
if (branch.IsLocal)
|
||||||
{
|
{
|
||||||
MakeBranchNode(branch, _locals, folders, "local", isFiltered, bForceExpanded);
|
MakeBranchNode(branch, _locals, folders, "refs/heads", bForceExpanded);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var remote = _remotes.Find(x => x.Name == branch.Remote);
|
var remote = _remotes.Find(x => x.Name == branch.Remote);
|
||||||
if (remote != null)
|
if (remote != null)
|
||||||
MakeBranchNode(branch, remote.Children, folders, $"remote/{remote.Name}", isFiltered, bForceExpanded);
|
MakeBranchNode(branch, remote.Children, folders, $"refs/remotes/{remote.Name}", bForceExpanded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,42 +103,33 @@ namespace SourceGit.ViewModels
|
||||||
SortNodes(_remotes);
|
SortNodes(_remotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFilters(AvaloniaList<string> filters)
|
public void CollectExpandedNodes(List<BranchTreeNode> nodes)
|
||||||
{
|
|
||||||
_filters.AddRange(filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CollectExpandedNodes(List<BranchTreeNode> nodes, bool isLocal)
|
|
||||||
{
|
|
||||||
CollectExpandedNodes(nodes, isLocal ? "local" : "remote");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CollectExpandedNodes(List<BranchTreeNode> nodes, string prefix)
|
|
||||||
{
|
{
|
||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
if (node.Backend is Models.Branch)
|
if (node.Backend is Models.Branch)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var path = prefix + "/" + node.Name;
|
|
||||||
if (node.IsExpanded)
|
if (node.IsExpanded)
|
||||||
_expanded.Add(path);
|
_expanded.Add(node.Path);
|
||||||
|
|
||||||
CollectExpandedNodes(node.Children, path);
|
CollectExpandedNodes(node.Children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MakeBranchNode(Models.Branch branch, List<BranchTreeNode> roots, Dictionary<string, BranchTreeNode> folders, string prefix, bool isFiltered, bool bForceExpanded)
|
private void MakeBranchNode(Models.Branch branch, List<BranchTreeNode> roots, Dictionary<string, BranchTreeNode> folders, string prefix, bool bForceExpanded)
|
||||||
{
|
{
|
||||||
|
var fullpath = $"{prefix}/{branch.Name}";
|
||||||
var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal);
|
var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal);
|
||||||
if (sepIdx == -1 || branch.IsDetachedHead)
|
if (sepIdx == -1 || branch.IsDetachedHead)
|
||||||
{
|
{
|
||||||
roots.Add(new BranchTreeNode()
|
roots.Add(new BranchTreeNode()
|
||||||
{
|
{
|
||||||
Name = branch.Name,
|
Name = branch.Name,
|
||||||
|
Path = fullpath,
|
||||||
Backend = branch,
|
Backend = branch,
|
||||||
IsExpanded = false,
|
IsExpanded = false,
|
||||||
IsFiltered = isFiltered,
|
FilterMode = _settings.GetHistoriesFilterMode(fullpath, branch.IsLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +152,9 @@ namespace SourceGit.ViewModels
|
||||||
lastFolder = new BranchTreeNode()
|
lastFolder = new BranchTreeNode()
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
|
Path = folder,
|
||||||
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
|
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
|
||||||
|
FilterMode = _settings.GetHistoriesFilterMode(folder, branch.IsLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder),
|
||||||
};
|
};
|
||||||
roots.Add(lastFolder);
|
roots.Add(lastFolder);
|
||||||
folders.Add(folder, lastFolder);
|
folders.Add(folder, lastFolder);
|
||||||
|
@ -166,7 +164,9 @@ namespace SourceGit.ViewModels
|
||||||
var cur = new BranchTreeNode()
|
var cur = new BranchTreeNode()
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
|
Path = folder,
|
||||||
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
|
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
|
||||||
|
FilterMode = _settings.GetHistoriesFilterMode(folder, branch.IsLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder),
|
||||||
};
|
};
|
||||||
lastFolder.Children.Add(cur);
|
lastFolder.Children.Add(cur);
|
||||||
folders.Add(folder, cur);
|
folders.Add(folder, cur);
|
||||||
|
@ -179,10 +179,11 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
lastFolder?.Children.Add(new BranchTreeNode()
|
lastFolder?.Children.Add(new BranchTreeNode()
|
||||||
{
|
{
|
||||||
Name = Path.GetFileName(branch.Name),
|
Name = System.IO.Path.GetFileName(branch.Name),
|
||||||
|
Path = fullpath,
|
||||||
Backend = branch,
|
Backend = branch,
|
||||||
IsExpanded = false,
|
IsExpanded = false,
|
||||||
IsFiltered = isFiltered,
|
FilterMode = _settings.GetHistoriesFilterMode(fullpath, branch.IsLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,10 +204,10 @@ namespace SourceGit.ViewModels
|
||||||
SortNodes(node.Children);
|
SortNodes(node.Children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly Models.RepositorySettings _settings = null;
|
||||||
private readonly List<BranchTreeNode> _locals = new List<BranchTreeNode>();
|
private readonly List<BranchTreeNode> _locals = new List<BranchTreeNode>();
|
||||||
private readonly List<BranchTreeNode> _remotes = new List<BranchTreeNode>();
|
private readonly List<BranchTreeNode> _remotes = new List<BranchTreeNode>();
|
||||||
private readonly HashSet<string> _expanded = new HashSet<string>();
|
private readonly HashSet<string> _expanded = new HashSet<string>();
|
||||||
private readonly List<string> _filters = new List<string>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch);
|
var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch);
|
||||||
if (b != null)
|
if (b != null)
|
||||||
_repo.AutoAddBranchFilterPostCheckout(b);
|
_repo.UpdateHistoriesFilterAfterCheckout(b);
|
||||||
|
|
||||||
_repo.MarkBranchesDirtyManually();
|
_repo.MarkBranchesDirtyManually();
|
||||||
_repo.SetWatcherEnabled(true);
|
_repo.SetWatcherEnabled(true);
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace SourceGit.ViewModels
|
||||||
var trimmedUrl = url;
|
var trimmedUrl = url;
|
||||||
if (url.EndsWith(".git"))
|
if (url.EndsWith(".git"))
|
||||||
trimmedUrl = url.Substring(0, url.Length - 4);
|
trimmedUrl = url.Substring(0, url.Length - 4);
|
||||||
|
|
||||||
if (url.StartsWith("https://github.com/", StringComparison.Ordinal))
|
if (url.StartsWith("https://github.com/", StringComparison.Ordinal))
|
||||||
WebLinks.Add(new Models.CommitLink() { Name = $"Github ({trimmedUrl.Substring(19)})", URLPrefix = $"{url}/commit/" });
|
WebLinks.Add(new Models.CommitLink() { Name = $"Github ({trimmedUrl.Substring(19)})", URLPrefix = $"{url}/commit/" });
|
||||||
else if (url.StartsWith("https://gitlab.", StringComparison.Ordinal))
|
else if (url.StartsWith("https://gitlab.", StringComparison.Ordinal))
|
||||||
|
@ -169,6 +169,11 @@ namespace SourceGit.ViewModels
|
||||||
SearchChangeFilter = string.Empty;
|
SearchChangeFilter = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Models.Commit GetParent(string sha)
|
||||||
|
{
|
||||||
|
return new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
|
||||||
|
}
|
||||||
|
|
||||||
public List<Models.Object> GetRevisionFilesUnderFolder(string parentFolder)
|
public List<Models.Object> GetRevisionFilesUnderFolder(string parentFolder)
|
||||||
{
|
{
|
||||||
return new Commands.QueryRevisionObjects(_repo.FullPath, _commit.SHA, parentFolder).Result();
|
return new Commands.QueryRevisionObjects(_repo.FullPath, _commit.SHA, parentFolder).Result();
|
||||||
|
@ -381,10 +386,13 @@ namespace SourceGit.ViewModels
|
||||||
var openWith = new MenuItem();
|
var openWith = new MenuItem();
|
||||||
openWith.Header = App.Text("OpenWith");
|
openWith.Header = App.Text("OpenWith");
|
||||||
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
|
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
|
||||||
openWith.IsEnabled = File.Exists(fullPath);
|
|
||||||
openWith.Click += (_, ev) =>
|
openWith.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
Native.OS.OpenWithDefaultEditor(fullPath);
|
var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? "";
|
||||||
|
var fileExt = Path.GetExtension(fullPath) ?? "";
|
||||||
|
var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}");
|
||||||
|
Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, tmpFile);
|
||||||
|
Native.OS.OpenWithDefaultEditor(tmpFile);
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
if (CheckoutAfterCreated)
|
if (CheckoutAfterCreated)
|
||||||
{
|
{
|
||||||
_repo.AutoAddBranchFilterPostCheckout(new Models.Branch()
|
_repo.UpdateHistoriesFilterAfterCheckout(new Models.Branch()
|
||||||
{
|
{
|
||||||
FullName = $"refs/heads/{_name}",
|
FullName = $"refs/heads/{_name}",
|
||||||
Upstream = BasedOn is Models.Branch { IsLocal: false } remoteBranch ? remoteBranch.FullName : string.Empty,
|
Upstream = BasedOn is Models.Branch { IsLocal: false } remoteBranch ? remoteBranch.FullName : string.Empty,
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null)
|
if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null)
|
||||||
{
|
{
|
||||||
SetProgressDescription("Deleting tracking remote branch...");
|
SetProgressDescription("Deleting remote-tracking branch...");
|
||||||
Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name);
|
Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SourceGit.ViewModels
|
namespace SourceGit.ViewModels
|
||||||
|
@ -57,10 +58,17 @@ namespace SourceGit.ViewModels
|
||||||
var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, _name);
|
var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, _name);
|
||||||
CallUIThread(() =>
|
CallUIThread(() =>
|
||||||
{
|
{
|
||||||
if (succ && _repo.Settings.Filters.Contains(oldName))
|
if (succ)
|
||||||
{
|
{
|
||||||
_repo.Settings.Filters.Remove(oldName);
|
foreach (var filter in _repo.Settings.HistoriesFilters)
|
||||||
_repo.Settings.Filters.Add($"refs/heads/{_name}");
|
{
|
||||||
|
if (filter.Type == Models.FilterType.LocalBranch &&
|
||||||
|
filter.Pattern.Equals(oldName, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
filter.Pattern = $"refs/heads/{_name}";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_repo.MarkBranchesDirtyManually();
|
_repo.MarkBranchesDirtyManually();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -587,18 +588,6 @@ namespace SourceGit.ViewModels
|
||||||
Filter = string.Empty;
|
Filter = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearHistoriesFilter()
|
|
||||||
{
|
|
||||||
_settings.Filters.Clear();
|
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
RefreshBranches();
|
|
||||||
RefreshTags();
|
|
||||||
RefreshCommits();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearSearchCommitFilter()
|
public void ClearSearchCommitFilter()
|
||||||
{
|
{
|
||||||
SearchCommitFilter = string.Empty;
|
SearchCommitFilter = string.Empty;
|
||||||
|
@ -696,53 +685,21 @@ namespace SourceGit.ViewModels
|
||||||
NavigateToCommit(_currentBranch.Head);
|
NavigateToCommit(_currentBranch.Head);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AutoAddBranchFilterPostCheckout(Models.Branch local)
|
public void ClearHistoriesFilter()
|
||||||
{
|
{
|
||||||
if (_settings.Filters.Count == 0 || _settings.Filters.Contains(local.FullName))
|
_settings.HistoriesFilters.Clear();
|
||||||
return;
|
|
||||||
|
|
||||||
var hasLeft = false;
|
Task.Run(() =>
|
||||||
foreach (var b in _branches)
|
|
||||||
{
|
{
|
||||||
if (!b.FullName.Equals(local.FullName, StringComparison.Ordinal) &&
|
RefreshBranches();
|
||||||
!b.FullName.Equals(local.Upstream, StringComparison.Ordinal) &&
|
RefreshTags();
|
||||||
!_settings.Filters.Contains(b.FullName))
|
RefreshCommits();
|
||||||
{
|
});
|
||||||
hasLeft = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasLeft)
|
|
||||||
_settings.Filters.Clear();
|
|
||||||
else if (string.IsNullOrEmpty(local.Upstream) || _settings.Filters.Contains(local.Upstream))
|
|
||||||
_settings.Filters.Add(local.FullName);
|
|
||||||
else
|
|
||||||
_settings.Filters.AddRange([local.FullName, local.Upstream]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateFilters(List<string> filters, bool toggle)
|
public void UpdateHistoriesFilterAfterCheckout(Models.Branch local)
|
||||||
{
|
{
|
||||||
var changed = false;
|
// TODO:
|
||||||
if (toggle)
|
|
||||||
{
|
|
||||||
foreach (var filter in filters)
|
|
||||||
{
|
|
||||||
if (!_settings.Filters.Contains(filter))
|
|
||||||
{
|
|
||||||
_settings.Filters.Add(filter);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var filter in filters)
|
|
||||||
changed |= _settings.Filters.Remove(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
Task.Run(RefreshCommits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StashAll(bool autoStart)
|
public void StashAll(bool autoStart)
|
||||||
|
@ -834,7 +791,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
var tags = new Commands.QueryTags(_fullpath).Result();
|
var tags = new Commands.QueryTags(_fullpath).Result();
|
||||||
foreach (var tag in tags)
|
foreach (var tag in tags)
|
||||||
tag.IsFiltered = _settings.Filters.Contains(tag.Name);
|
tag.FilterMode = _settings.GetHistoriesFilterMode(tag.Name, Models.FilterType.Tag);
|
||||||
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
@ -847,49 +804,21 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true);
|
Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true);
|
||||||
|
|
||||||
var limits = $"-{Preference.Instance.MaxHistoryCommits} ";
|
var builder = new StringBuilder();
|
||||||
|
builder.Append($"-{Preference.Instance.MaxHistoryCommits} ");
|
||||||
if (_enableReflog)
|
if (_enableReflog)
|
||||||
limits += "--reflog ";
|
builder.Append("--reflog ");
|
||||||
if (_enableFirstParentInHistories)
|
if (_enableFirstParentInHistories)
|
||||||
limits += "--first-parent ";
|
builder.Append("--first-parent ");
|
||||||
|
|
||||||
var validFilters = new List<string>();
|
var invalidFilters = new List<Models.Filter>();
|
||||||
foreach (var filter in _settings.Filters)
|
var filters = _settings.BuildHistoriesFilter();
|
||||||
{
|
if (string.IsNullOrEmpty(filters))
|
||||||
if (filter.StartsWith("refs/", StringComparison.Ordinal))
|
builder.Append("--branches --remotes --tags");
|
||||||
{
|
|
||||||
if (_branches.FindIndex(x => x.FullName == filter) >= 0)
|
|
||||||
validFilters.Add(filter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_tags.FindIndex(t => t.Name == filter) >= 0)
|
|
||||||
validFilters.Add(filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validFilters.Count > 0)
|
|
||||||
{
|
|
||||||
limits += string.Join(" ", validFilters);
|
|
||||||
|
|
||||||
if (_settings.Filters.Count != validFilters.Count)
|
|
||||||
{
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
|
||||||
{
|
|
||||||
_settings.Filters.Clear();
|
|
||||||
_settings.Filters.AddRange(validFilters);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
builder.Append(filters);
|
||||||
if (_settings.Filters.Count != 0)
|
|
||||||
Dispatcher.UIThread.Invoke(() => _settings.Filters.Clear());
|
|
||||||
|
|
||||||
limits += "--exclude=refs/stash --all";
|
var commits = new Commands.QueryCommits(_fullpath, builder.ToString()).Result();
|
||||||
}
|
|
||||||
|
|
||||||
var commits = new Commands.QueryCommits(_fullpath, limits).Result();
|
|
||||||
var graph = Models.CommitGraph.Parse(commits, _enableFirstParentInHistories);
|
var graph = Models.CommitGraph.Parse(commits, _enableFirstParentInHistories);
|
||||||
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
@ -2061,13 +1990,11 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
private BranchTreeNode.Builder BuildBranchTree(List<Models.Branch> branches, List<Models.Remote> remotes)
|
private BranchTreeNode.Builder BuildBranchTree(List<Models.Branch> branches, List<Models.Remote> remotes)
|
||||||
{
|
{
|
||||||
var builder = new BranchTreeNode.Builder();
|
var builder = new BranchTreeNode.Builder(_settings);
|
||||||
builder.SetFilters(_settings.Filters);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_filter))
|
if (string.IsNullOrEmpty(_filter))
|
||||||
{
|
{
|
||||||
builder.CollectExpandedNodes(_localBranchTrees, true);
|
builder.CollectExpandedNodes(_localBranchTrees);
|
||||||
builder.CollectExpandedNodes(_remoteBranchTrees, false);
|
builder.CollectExpandedNodes(_remoteBranchTrees);
|
||||||
builder.Run(branches, remotes, false);
|
builder.Run(branches, remotes, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -22,16 +22,6 @@ namespace SourceGit.ViewModels
|
||||||
get => Tag == null;
|
get => Tag == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsFiltered
|
|
||||||
{
|
|
||||||
get => Tag?.IsFiltered ?? false;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (Tag != null)
|
|
||||||
Tag.IsFiltered = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsExpanded
|
public bool IsExpanded
|
||||||
{
|
{
|
||||||
get => _isExpanded;
|
get => _isExpanded;
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
<Style Selector="ListBoxItem" x:DataType="vm:BranchTreeNode">
|
<Style Selector="ListBoxItem" x:DataType="vm:BranchTreeNode">
|
||||||
<Setter Property="CornerRadius" Value="{Binding CornerRadius}"/>
|
<Setter Property="CornerRadius" Value="{Binding CornerRadius}"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBoxItem:pointerover v|FilterModeSwitchButton">
|
||||||
|
<Setter Property="IsNoneVisible" Value="True"/>
|
||||||
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
|
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
|
@ -44,7 +48,7 @@
|
||||||
<!-- Content Area (allows double-click) -->
|
<!-- Content Area (allows double-click) -->
|
||||||
<Grid Grid.Column="1"
|
<Grid Grid.Column="1"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
ColumnDefinitions="18,*,Auto,Auto"
|
ColumnDefinitions="18,*,Auto,20"
|
||||||
DoubleTapped="OnDoubleTappedBranchNode">
|
DoubleTapped="OnDoubleTappedBranchNode">
|
||||||
|
|
||||||
<!-- Icon -->
|
<!-- Icon -->
|
||||||
|
@ -67,15 +71,8 @@
|
||||||
Foreground="{DynamicResource Brush.BadgeFG}"
|
Foreground="{DynamicResource Brush.BadgeFG}"
|
||||||
Background="{DynamicResource Brush.Badge}"/>
|
Background="{DynamicResource Brush.Badge}"/>
|
||||||
|
|
||||||
<!-- Filter Toggle Button -->
|
<!-- Filter Mode Switcher -->
|
||||||
<ToggleButton Grid.Column="3"
|
<v:FilterModeSwitchButton Grid.Column="3" Mode="{Binding FilterMode}"/>
|
||||||
Classes="filter"
|
|
||||||
Margin="0,0,8,0"
|
|
||||||
Background="Transparent"
|
|
||||||
IsVisible="{Binding IsBranch}"
|
|
||||||
IsChecked="{Binding IsFiltered}"
|
|
||||||
Click="OnToggleFilterClicked"
|
|
||||||
ToolTip.Tip="{DynamicResource Text.Filter}"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
|
@ -428,28 +428,6 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleFilterClicked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (DataContext is ViewModels.Repository repo &&
|
|
||||||
sender is ToggleButton toggle &&
|
|
||||||
toggle.DataContext is ViewModels.BranchTreeNode { Backend: Models.Branch branch } node)
|
|
||||||
{
|
|
||||||
bool filtered = toggle.IsChecked == true;
|
|
||||||
List<string> filters = [branch.FullName];
|
|
||||||
if (branch.IsLocal && !string.IsNullOrEmpty(branch.Upstream))
|
|
||||||
{
|
|
||||||
filters.Add(branch.Upstream);
|
|
||||||
|
|
||||||
node.IsFiltered = filtered;
|
|
||||||
UpdateUpstreamFilterState(repo.RemoteBranchTrees, branch.Upstream, filtered);
|
|
||||||
}
|
|
||||||
|
|
||||||
repo.UpdateFilters(filters, filtered);
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MakeRows(List<ViewModels.BranchTreeNode> rows, List<ViewModels.BranchTreeNode> nodes, int depth)
|
private void MakeRows(List<ViewModels.BranchTreeNode> rows, List<ViewModels.BranchTreeNode> nodes, int depth)
|
||||||
{
|
{
|
||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
|
@ -477,23 +455,6 @@ namespace SourceGit.Views
|
||||||
CollectBranchesInNode(outs, sub);
|
CollectBranchesInNode(outs, sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UpdateUpstreamFilterState(List<ViewModels.BranchTreeNode> collection, string upstream, bool isFiltered)
|
|
||||||
{
|
|
||||||
foreach (var node in collection)
|
|
||||||
{
|
|
||||||
if (node.Backend is Models.Branch b && b.FullName == upstream)
|
|
||||||
{
|
|
||||||
node.IsFiltered = isFiltered;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.Backend is Models.Remote r && upstream.StartsWith($"refs/remotes/{r.Name}/", StringComparison.Ordinal))
|
|
||||||
return UpdateUpstreamFilterState(node.Children, upstream, isFiltered);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _disableSelectionChangingEvent = false;
|
private bool _disableSelectionChangingEvent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,28 @@
|
||||||
TextDecorations="Underline"
|
TextDecorations="Underline"
|
||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
Margin="0,0,16,0"
|
Margin="0,0,16,0"
|
||||||
PointerPressed="OnSHAPressed"/>
|
PointerEntered="OnSHAPointerEntered"
|
||||||
|
PointerPressed="OnSHAPressed">
|
||||||
|
<TextBlock.Styles>
|
||||||
|
<Style Selector="ToolTip">
|
||||||
|
<Setter Property="MaxWidth" Value="600"/>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Styles>
|
||||||
|
|
||||||
|
<TextBlock.DataTemplates>
|
||||||
|
<DataTemplate DataType="m:Commit">
|
||||||
|
<StackPanel MinWidth="400" Orientation="Vertical">
|
||||||
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
|
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
|
||||||
|
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="2" Classes="primary" Text="{Binding CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Classes="primary" Margin="0,8,0,0" Text="{Binding Subject}" TextWrapping="Wrap"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</TextBlock.DataTemplates>
|
||||||
|
</TextBlock>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
@ -113,6 +115,29 @@ namespace SourceGit.Views
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void OnSHAPointerEntered(object sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha } ctl)
|
||||||
|
{
|
||||||
|
var tooltip = ToolTip.GetTip(ctl);
|
||||||
|
if (tooltip is Models.Commit commit && commit.SHA == sha)
|
||||||
|
{
|
||||||
|
ToolTip.SetIsOpen(ctl, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var c = await Task.Run(() => detail.GetParent(sha));
|
||||||
|
if (c != null)
|
||||||
|
{
|
||||||
|
ToolTip.SetTip(ctl, c);
|
||||||
|
ToolTip.SetIsOpen(ctl, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnSHAPressed(object sender, PointerPressedEventArgs e)
|
private void OnSHAPressed(object sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha })
|
if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha })
|
||||||
|
|
41
src/Views/FilterModeSwitchButton.axaml
Normal file
41
src/Views/FilterModeSwitchButton.axaml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:m="using:SourceGit.Models"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="SourceGit.Views.FilterModeSwitchButton"
|
||||||
|
x:Name="ThisControl">
|
||||||
|
<Button Classes="icon_button"
|
||||||
|
Width="12" Height="12"
|
||||||
|
Padding="0"
|
||||||
|
Background="Transparent"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Click="OnChangeFilterModeButtonClicked">
|
||||||
|
<Grid>
|
||||||
|
<Path Width="12" Height="12"
|
||||||
|
Data="{StaticResource Icons.Eye}"
|
||||||
|
Fill="{DynamicResource Brush.FG2}">
|
||||||
|
<Path.IsVisible>
|
||||||
|
<MultiBinding Converter="{x:Static BoolConverters.And}">
|
||||||
|
<Binding Path="#ThisControl.Mode" Converter="{x:Static ObjectConverters.Equal}" ConverterParameter="{x:Static m:FilterMode.None}"/>
|
||||||
|
<MultiBinding Converter="{x:Static BoolConverters.Or}">
|
||||||
|
<Binding Path="#ThisControl.IsNoneVisible"/>
|
||||||
|
<Binding Path="#ThisControl.IsContextMenuOpening"/>
|
||||||
|
</MultiBinding>
|
||||||
|
</MultiBinding>
|
||||||
|
</Path.IsVisible>
|
||||||
|
</Path>
|
||||||
|
|
||||||
|
<Path Width="12" Height="12"
|
||||||
|
Data="{StaticResource Icons.Filter}"
|
||||||
|
Fill="{DynamicResource Brush.Accent}"
|
||||||
|
IsVisible="{Binding #ThisControl.Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Included}}"/>
|
||||||
|
|
||||||
|
<Path Width="12" Height="12"
|
||||||
|
Data="{StaticResource Icons.EyeClose}"
|
||||||
|
Fill="{DynamicResource Brush.Accent}"
|
||||||
|
IsVisible="{Binding #ThisControl.Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Excluded}}"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
|
</UserControl>
|
256
src/Views/FilterModeSwitchButton.axaml.cs
Normal file
256
src/Views/FilterModeSwitchButton.axaml.cs
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
|
||||||
|
namespace SourceGit.Views
|
||||||
|
{
|
||||||
|
public partial class FilterModeSwitchButton : UserControl
|
||||||
|
{
|
||||||
|
public static readonly StyledProperty<Models.FilterMode> ModeProperty =
|
||||||
|
AvaloniaProperty.Register<FilterModeSwitchButton, Models.FilterMode>(nameof(Mode));
|
||||||
|
|
||||||
|
public Models.FilterMode Mode
|
||||||
|
{
|
||||||
|
get => GetValue(ModeProperty);
|
||||||
|
set => SetValue(ModeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> IsNoneVisibleProperty =
|
||||||
|
AvaloniaProperty.Register<FilterModeSwitchButton, bool>(nameof(IsNoneVisible));
|
||||||
|
|
||||||
|
public bool IsNoneVisible
|
||||||
|
{
|
||||||
|
get => GetValue(IsNoneVisibleProperty);
|
||||||
|
set => SetValue(IsNoneVisibleProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> IsContextMenuOpeningProperty =
|
||||||
|
AvaloniaProperty.Register<FilterModeSwitchButton, bool>(nameof(IsContextMenuOpening));
|
||||||
|
|
||||||
|
public bool IsContextMenuOpening
|
||||||
|
{
|
||||||
|
get => GetValue(IsContextMenuOpeningProperty);
|
||||||
|
set => SetValue(IsContextMenuOpeningProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterModeSwitchButton()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChangeFilterModeButtonClicked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var repoView = this.FindAncestorOfType<Repository>();
|
||||||
|
if (repoView == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var repo = repoView.DataContext as ViewModels.Repository;
|
||||||
|
if (repo == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var button = sender as Button;
|
||||||
|
if (button == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (DataContext is Models.Tag tag)
|
||||||
|
{
|
||||||
|
var mode = tag.FilterMode;
|
||||||
|
|
||||||
|
var none = new MenuItem();
|
||||||
|
none.Icon = App.CreateMenuIcon("Icons.Eye");
|
||||||
|
none.Header = "Default";
|
||||||
|
none.IsEnabled = mode != Models.FilterMode.None;
|
||||||
|
none.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
UpdateTagFilterMode(repo, tag, Models.FilterMode.None);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var include = new MenuItem();
|
||||||
|
include.Icon = App.CreateMenuIcon("Icons.Filter");
|
||||||
|
include.Header = "Filter";
|
||||||
|
include.IsEnabled = mode != Models.FilterMode.Included;
|
||||||
|
include.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
UpdateTagFilterMode(repo, tag, Models.FilterMode.Included);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var exclude = new MenuItem();
|
||||||
|
exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
|
||||||
|
exclude.Header = "Hide";
|
||||||
|
exclude.IsEnabled = mode != Models.FilterMode.Excluded;
|
||||||
|
exclude.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
UpdateTagFilterMode(repo, tag, Models.FilterMode.Excluded);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var menu = new ContextMenu();
|
||||||
|
menu.Items.Add(none);
|
||||||
|
menu.Items.Add(include);
|
||||||
|
menu.Items.Add(exclude);
|
||||||
|
|
||||||
|
if (mode == Models.FilterMode.None)
|
||||||
|
{
|
||||||
|
IsContextMenuOpening = true;
|
||||||
|
menu.Closed += (_, _) => IsContextMenuOpening = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.Open(button);
|
||||||
|
}
|
||||||
|
else if (DataContext is ViewModels.BranchTreeNode node)
|
||||||
|
{
|
||||||
|
var mode = node.FilterMode;
|
||||||
|
|
||||||
|
var none = new MenuItem();
|
||||||
|
none.Icon = App.CreateMenuIcon("Icons.Eye");
|
||||||
|
none.Header = "Default";
|
||||||
|
none.IsEnabled = mode != Models.FilterMode.None;
|
||||||
|
none.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
UpdateBranchFilterMode(repo, node, Models.FilterMode.None);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var include = new MenuItem();
|
||||||
|
include.Icon = App.CreateMenuIcon("Icons.Filter");
|
||||||
|
include.Header = "Filter";
|
||||||
|
include.IsEnabled = mode != Models.FilterMode.Included;
|
||||||
|
include.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
UpdateBranchFilterMode(repo, node, Models.FilterMode.Included);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var exclude = new MenuItem();
|
||||||
|
exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
|
||||||
|
exclude.Header = "Hide";
|
||||||
|
exclude.IsEnabled = mode != Models.FilterMode.Excluded;
|
||||||
|
exclude.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
UpdateBranchFilterMode(repo, node, Models.FilterMode.Excluded);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var menu = new ContextMenu();
|
||||||
|
menu.Items.Add(none);
|
||||||
|
menu.Items.Add(include);
|
||||||
|
menu.Items.Add(exclude);
|
||||||
|
|
||||||
|
if (mode == Models.FilterMode.None)
|
||||||
|
{
|
||||||
|
IsContextMenuOpening = true;
|
||||||
|
menu.Closed += (_, _) => IsContextMenuOpening = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.Open(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTagFilterMode(ViewModels.Repository repo, Models.Tag tag, Models.FilterMode mode)
|
||||||
|
{
|
||||||
|
var changed = repo.Settings.UpdateHistoriesFilter(tag.Name, Models.FilterType.Tag, mode);
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
tag.FilterMode = mode;
|
||||||
|
Task.Run(repo.RefreshCommits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBranchFilterMode(ViewModels.Repository repo, ViewModels.BranchTreeNode node, Models.FilterMode mode)
|
||||||
|
{
|
||||||
|
var isLocal = node.Path.StartsWith("refs/heads/", StringComparison.Ordinal);
|
||||||
|
var type = isLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
|
||||||
|
var tree = isLocal ? repo.LocalBranchTrees : repo.RemoteBranchTrees;
|
||||||
|
|
||||||
|
if (node.Backend is Models.Branch branch)
|
||||||
|
{
|
||||||
|
var changed = repo.Settings.UpdateHistoriesFilter(node.Path, type, mode);
|
||||||
|
if (!changed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node.FilterMode = mode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var changed = repo.Settings.UpdateHistoriesFilter(node.Path, isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder, mode);
|
||||||
|
if (!changed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node.FilterMode = mode;
|
||||||
|
ResetChildrenBranchNodeFilterMode(repo, node, isLocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentType = isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
|
||||||
|
var cur = node;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var lastSepIdx = cur.Path.LastIndexOf('/');
|
||||||
|
if (lastSepIdx <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var parentPath = cur.Path.Substring(0, lastSepIdx);
|
||||||
|
var parent = FindParentNode(tree, parentPath);
|
||||||
|
if (parent == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
repo.Settings.UpdateHistoriesFilter(parent.Path, parentType, Models.FilterMode.None);
|
||||||
|
parent.FilterMode = Models.FilterMode.None;
|
||||||
|
cur = parent;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
Task.Run(repo.RefreshCommits);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetChildrenBranchNodeFilterMode(ViewModels.Repository repo, ViewModels.BranchTreeNode node, bool isLocal)
|
||||||
|
{
|
||||||
|
foreach (var child in node.Children)
|
||||||
|
{
|
||||||
|
child.FilterMode = Models.FilterMode.None;
|
||||||
|
|
||||||
|
if (child.IsBranch)
|
||||||
|
{
|
||||||
|
var type = isLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
|
||||||
|
repo.Settings.UpdateHistoriesFilter(child.Path, type, Models.FilterMode.None);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var type = isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
|
||||||
|
repo.Settings.UpdateHistoriesFilter(child.Path, type, Models.FilterMode.None);
|
||||||
|
ResetChildrenBranchNodeFilterMode(repo, child, isLocal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ViewModels.BranchTreeNode FindParentNode(List<ViewModels.BranchTreeNode> nodes, string parent)
|
||||||
|
{
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
if (node.IsBranch)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (node.Path.Equals(parent, StringComparison.Ordinal))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
if (parent.StartsWith(node.Path, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var founded = FindParentNode(node.Children, parent);
|
||||||
|
if (founded != null)
|
||||||
|
return founded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,35 +192,26 @@ namespace SourceGit.Views
|
||||||
if (string.IsNullOrEmpty(subject))
|
if (string.IsNullOrEmpty(subject))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var offset = 0;
|
|
||||||
var keywordMatch = REG_KEYWORD_FORMAT1().Match(subject);
|
var keywordMatch = REG_KEYWORD_FORMAT1().Match(subject);
|
||||||
if (!keywordMatch.Success)
|
if (!keywordMatch.Success)
|
||||||
keywordMatch = REG_KEYWORD_FORMAT2().Match(subject);
|
keywordMatch = REG_KEYWORD_FORMAT2().Match(subject);
|
||||||
|
|
||||||
if (keywordMatch.Success)
|
var rules = IssueTrackerRules ?? [];
|
||||||
{
|
|
||||||
var keyword = new Run(subject.Substring(0, keywordMatch.Length));
|
|
||||||
keyword.FontWeight = FontWeight.Bold;
|
|
||||||
Inlines.Add(keyword);
|
|
||||||
|
|
||||||
offset = keywordMatch.Length;
|
|
||||||
subject = subject.Substring(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rules = IssueTrackerRules;
|
|
||||||
if (rules == null || rules.Count == 0)
|
|
||||||
{
|
|
||||||
Inlines.Add(new Run(subject));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var matches = new List<Models.Hyperlink>();
|
var matches = new List<Models.Hyperlink>();
|
||||||
foreach (var rule in rules)
|
foreach (var rule in rules)
|
||||||
rule.Matches(matches, subject);
|
rule.Matches(matches, subject);
|
||||||
|
|
||||||
if (matches.Count == 0)
|
if (matches.Count == 0)
|
||||||
{
|
{
|
||||||
Inlines.Add(new Run(subject));
|
if (keywordMatch.Success)
|
||||||
|
{
|
||||||
|
Inlines.Add(new Run(subject.Substring(0, keywordMatch.Length)) { FontWeight = FontWeight.Bold });
|
||||||
|
Inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Inlines.Add(new Run(subject));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,18 +223,44 @@ namespace SourceGit.Views
|
||||||
foreach (var match in matches)
|
foreach (var match in matches)
|
||||||
{
|
{
|
||||||
if (match.Start > pos)
|
if (match.Start > pos)
|
||||||
inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
|
{
|
||||||
|
if (keywordMatch.Success && pos < keywordMatch.Length)
|
||||||
|
{
|
||||||
|
if (keywordMatch.Length < match.Start)
|
||||||
|
{
|
||||||
|
inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
|
||||||
|
inlines.Add(new Run(subject.Substring(keywordMatch.Length, match.Start - keywordMatch.Length)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inlines.Add(new Run(subject.Substring(pos, match.Start - pos)) { FontWeight = FontWeight.Bold });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var link = new Run(subject.Substring(match.Start, match.Length));
|
var link = new Run(subject.Substring(match.Start, match.Length));
|
||||||
link.Classes.Add("issue_link");
|
link.Classes.Add("issue_link");
|
||||||
inlines.Add(link);
|
inlines.Add(link);
|
||||||
|
|
||||||
pos = match.Start + match.Length;
|
pos = match.Start + match.Length;
|
||||||
match.Start += offset; // Because we use this index of whole subject to detect mouse event.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos < subject.Length)
|
if (pos < subject.Length)
|
||||||
inlines.Add(new Run(subject.Substring(pos)));
|
{
|
||||||
|
if (keywordMatch.Success && pos < keywordMatch.Length)
|
||||||
|
{
|
||||||
|
inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
|
||||||
|
inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inlines.Add(new Run(subject.Substring(pos)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Inlines.AddRange(inlines);
|
Inlines.AddRange(inlines);
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Appearance}"/>
|
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Appearance}"/>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32,32,Auto" ColumnDefinitions="Auto,*">
|
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32,Auto" ColumnDefinitions="Auto,*">
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||||
Text="{DynamicResource Text.Preference.Appearance.Theme}"
|
Text="{DynamicResource Text.Preference.Appearance.Theme}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
|
@ -158,34 +158,43 @@
|
||||||
Text="{Binding MonospaceFontFamily, Mode=TwoWay}"/>
|
Text="{Binding MonospaceFontFamily, Mode=TwoWay}"/>
|
||||||
|
|
||||||
<TextBlock Grid.Row="3" Grid.Column="0"
|
<TextBlock Grid.Row="3" Grid.Column="0"
|
||||||
Text="{DynamicResource Text.Preference.Appearance.DefaultFontSize}"
|
Text="{DynamicResource Text.Preference.Appearance.FontSize}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Margin="0,0,16,0"/>
|
Margin="0,0,16,0"/>
|
||||||
<NumericUpDown Grid.Row="3" Grid.Column="1"
|
<Grid Grid.Row="3" Grid.Column="1" ColumnDefinitions="*,8,*">
|
||||||
|
<NumericUpDown Grid.Column="0"
|
||||||
Minimum="10" Maximum="18" Increment="0.5"
|
Minimum="10" Maximum="18" Increment="0.5"
|
||||||
Height="28"
|
Height="28"
|
||||||
Padding="4"
|
Padding="4"
|
||||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
|
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
|
||||||
CornerRadius="3"
|
CornerRadius="3"
|
||||||
Value="{Binding DefaultFontSize, Mode=TwoWay}"/>
|
Value="{Binding DefaultFontSize, Mode=TwoWay}">
|
||||||
|
<NumericUpDown.InnerLeftContent>
|
||||||
|
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource Brush.Border1}">
|
||||||
|
<TextBlock Margin="4,0" Text="{DynamicResource Text.Preference.Appearance.FontSize.Default}"/>
|
||||||
|
</Border>
|
||||||
|
</NumericUpDown.InnerLeftContent>
|
||||||
|
</NumericUpDown>
|
||||||
|
<NumericUpDown Grid.Column="2"
|
||||||
|
Minimum="10" Maximum="18" Increment="0.5"
|
||||||
|
Height="28"
|
||||||
|
Padding="4"
|
||||||
|
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
|
||||||
|
CornerRadius="3"
|
||||||
|
Value="{Binding EditorFontSize, Mode=TwoWay}">
|
||||||
|
<NumericUpDown.InnerLeftContent>
|
||||||
|
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource Brush.Border1}">
|
||||||
|
<TextBlock Margin="4,0" Text="{DynamicResource Text.Preference.Appearance.FontSize.Editor}"/>
|
||||||
|
</Border>
|
||||||
|
</NumericUpDown.InnerLeftContent>
|
||||||
|
</NumericUpDown>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<TextBlock Grid.Row="4" Grid.Column="0"
|
<TextBlock Grid.Row="4" Grid.Column="0"
|
||||||
Text="{DynamicResource Text.Preference.Appearance.EditorFontSize}"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Margin="0,0,16,0"/>
|
|
||||||
<NumericUpDown Grid.Row="4" Grid.Column="1"
|
|
||||||
Minimum="10" Maximum="18" Increment="0.5"
|
|
||||||
Height="28"
|
|
||||||
Padding="4"
|
|
||||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
|
|
||||||
CornerRadius="3"
|
|
||||||
Value="{Binding EditorFontSize, Mode=TwoWay}"/>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="5" Grid.Column="0"
|
|
||||||
Text="{DynamicResource Text.Preference.Appearance.ThemeOverrides}"
|
Text="{DynamicResource Text.Preference.Appearance.ThemeOverrides}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Margin="0,0,16,0"/>
|
Margin="0,0,16,0"/>
|
||||||
<TextBox Grid.Row="5" Grid.Column="1"
|
<TextBox Grid.Row="4" Grid.Column="1"
|
||||||
Height="28"
|
Height="28"
|
||||||
CornerRadius="3"
|
CornerRadius="3"
|
||||||
Text="{Binding ThemeOverrides, Mode=TwoWay}">
|
Text="{Binding ThemeOverrides, Mode=TwoWay}">
|
||||||
|
@ -196,16 +205,16 @@
|
||||||
</TextBox.InnerRightContent>
|
</TextBox.InnerRightContent>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
|
|
||||||
<CheckBox Grid.Row="6" Grid.Column="1"
|
<CheckBox Grid.Row="5" Grid.Column="1"
|
||||||
Content="{DynamicResource Text.Preference.Appearance.OnlyUseMonoFontInEditor}"
|
Content="{DynamicResource Text.Preference.Appearance.OnlyUseMonoFontInEditor}"
|
||||||
IsChecked="{Binding OnlyUseMonoFontInEditor, Mode=TwoWay}"/>
|
IsChecked="{Binding OnlyUseMonoFontInEditor, Mode=TwoWay}"/>
|
||||||
|
|
||||||
<CheckBox Grid.Row="7" Grid.Column="1"
|
<CheckBox Grid.Row="6" Grid.Column="1"
|
||||||
Height="32"
|
Height="32"
|
||||||
Content="{DynamicResource Text.Preference.Appearance.UseFixedTabWidth}"
|
Content="{DynamicResource Text.Preference.Appearance.UseFixedTabWidth}"
|
||||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth, Mode=TwoWay}"/>
|
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth, Mode=TwoWay}"/>
|
||||||
|
|
||||||
<CheckBox Grid.Row="8" Grid.Column="1"
|
<CheckBox Grid.Row="7" Grid.Column="1"
|
||||||
Height="32"
|
Height="32"
|
||||||
Content="{DynamicResource Text.Preference.Appearance.UseNativeWindowFrame}"
|
Content="{DynamicResource Text.Preference.Appearance.UseNativeWindowFrame}"
|
||||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSystemWindowFrame, Mode=OneTime}"
|
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSystemWindowFrame, Mode=OneTime}"
|
||||||
|
|
|
@ -256,7 +256,7 @@
|
||||||
<ListBox Grid.Row="7"
|
<ListBox Grid.Row="7"
|
||||||
x:Name="SubmoduleList"
|
x:Name="SubmoduleList"
|
||||||
Height="0"
|
Height="0"
|
||||||
Margin="8,0,4,0"
|
Margin="12,0,4,0"
|
||||||
Classes="repo_left_content_list"
|
Classes="repo_left_content_list"
|
||||||
ItemsSource="{Binding VisibleSubmodules}"
|
ItemsSource="{Binding VisibleSubmodules}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
|
@ -312,7 +312,7 @@
|
||||||
<ListBox Grid.Row="9"
|
<ListBox Grid.Row="9"
|
||||||
x:Name="WorktreeList"
|
x:Name="WorktreeList"
|
||||||
Height="0"
|
Height="0"
|
||||||
Margin="8,0,4,0"
|
Margin="12,0,4,0"
|
||||||
Classes="repo_left_content_list"
|
Classes="repo_left_content_list"
|
||||||
ItemsSource="{Binding Worktrees}"
|
ItemsSource="{Binding Worktrees}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
|
@ -577,14 +577,14 @@
|
||||||
<Border.IsVisible>
|
<Border.IsVisible>
|
||||||
<MultiBinding Converter="{x:Static BoolConverters.And}">
|
<MultiBinding Converter="{x:Static BoolConverters.And}">
|
||||||
<Binding Path="SelectedViewIndex" Converter="{x:Static c:IntConverters.IsZero}"/>
|
<Binding Path="SelectedViewIndex" Converter="{x:Static c:IntConverters.IsZero}"/>
|
||||||
<Binding Path="Settings.Filters.Count" Converter="{x:Static c:IntConverters.IsGreaterThanZero}"/>
|
<Binding Path="Settings.HistoriesFilters.Count" Converter="{x:Static c:IntConverters.IsGreaterThanZero}"/>
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Border.IsVisible>
|
</Border.IsVisible>
|
||||||
|
|
||||||
<Grid Height="28" ColumnDefinitions="Auto,*,Auto">
|
<Grid Height="28" ColumnDefinitions="Auto,*,Auto">
|
||||||
<TextBlock Grid.Column="0" Margin="8,0,0,0" Classes="table_header" Text="{DynamicResource Text.Repository.FilterCommitPrefix}"/>
|
<TextBlock Grid.Column="0" Margin="8,0,0,0" Classes="table_header" Text="{DynamicResource Text.Repository.FilterCommitPrefix}"/>
|
||||||
|
|
||||||
<ItemsControl Grid.Column="1" Margin="8,0,0,0" ItemsSource="{Binding Settings.Filters}">
|
<ItemsControl Grid.Column="1" Margin="8,0,0,0" ItemsSource="{Binding Settings.HistoriesFilters}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<VirtualizingStackPanel Orientation="Horizontal" VerticalAlignment="Center"/>
|
<VirtualizingStackPanel Orientation="Horizontal" VerticalAlignment="Center"/>
|
||||||
|
@ -592,10 +592,24 @@
|
||||||
</ItemsControl.ItemsPanel>
|
</ItemsControl.ItemsPanel>
|
||||||
|
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate DataType="m:Filter">
|
||||||
<Border Height="20" Margin="0,0,6,0" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" CornerRadius="12">
|
<Grid Height="20" Margin="0,0,6,0">
|
||||||
<TextBlock Classes="primary" Text="{Binding Converter={x:Static c:StringConverters.TrimRefsPrefix}}" Margin="8,0"/>
|
<Border BorderThickness="1"
|
||||||
</Border>
|
BorderBrush="Green"
|
||||||
|
CornerRadius="12"
|
||||||
|
IsVisible="{Binding Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Included}}"/>
|
||||||
|
|
||||||
|
<Border BorderThickness="1"
|
||||||
|
BorderBrush="Red"
|
||||||
|
CornerRadius="12"
|
||||||
|
IsVisible="{Binding Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Excluded}}"/>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="8,0">
|
||||||
|
<Path Width="10" Height="10" Data="{StaticResource Icons.Branch}" IsVisible="{Binding IsBranch}"/>
|
||||||
|
<Path Width="10" Height="10" Data="{StaticResource Icons.Tag}" IsVisible="{Binding !IsBranch}"/>
|
||||||
|
<TextBlock Classes="primary" Text="{Binding Pattern, Converter={x:Static c:StringConverters.TrimRefsPrefix}}" Margin="4,0,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace SourceGit.Views
|
||||||
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
|
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
|
||||||
if (!startDirectly && OperatingSystem.IsMacOS())
|
if (!startDirectly && OperatingSystem.IsMacOS())
|
||||||
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
|
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
|
||||||
|
|
||||||
repo.Fetch(startDirectly);
|
repo.Fetch(startDirectly);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ namespace SourceGit.Views
|
||||||
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
|
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
|
||||||
if (!startDirectly && OperatingSystem.IsMacOS())
|
if (!startDirectly && OperatingSystem.IsMacOS())
|
||||||
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
|
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
|
||||||
|
|
||||||
repo.Pull(startDirectly);
|
repo.Pull(startDirectly);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ namespace SourceGit.Views
|
||||||
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
|
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
|
||||||
if (!startDirectly && OperatingSystem.IsMacOS())
|
if (!startDirectly && OperatingSystem.IsMacOS())
|
||||||
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
|
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
|
||||||
|
|
||||||
repo.Push(startDirectly);
|
repo.Push(startDirectly);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
<Style Selector="ListBoxItem">
|
<Style Selector="ListBoxItem">
|
||||||
<Setter Property="CornerRadius" Value="4"/>
|
<Setter Property="CornerRadius" Value="4"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBoxItem:pointerover v|FilterModeSwitchButton">
|
||||||
|
<Setter Property="IsNoneVisible" Value="True"/>
|
||||||
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
|
|
||||||
<UserControl.DataTemplates>
|
<UserControl.DataTemplates>
|
||||||
|
@ -43,15 +47,14 @@
|
||||||
Classes="primary"
|
Classes="primary"
|
||||||
Text="{Binding FullPath, Converter={x:Static c:PathConverters.PureFileName}}"
|
Text="{Binding FullPath, Converter={x:Static c:PathConverters.PureFileName}}"
|
||||||
Margin="8,0,0,0"/>
|
Margin="8,0,0,0"/>
|
||||||
|
|
||||||
<ToggleButton Grid.Column="3"
|
<ContentControl Grid.Column="3" Content="{Binding Tag}">
|
||||||
Classes="filter"
|
<ContentControl.DataTemplates>
|
||||||
Margin="0,0,8,0"
|
<DataTemplate DataType="m:Tag">
|
||||||
Background="Transparent"
|
<v:FilterModeSwitchButton Mode="{Binding FilterMode}"/>
|
||||||
Click="OnToggleFilterClicked"
|
</DataTemplate>
|
||||||
IsChecked="{Binding IsFiltered, Mode=TwoWay}"
|
</ContentControl.DataTemplates>
|
||||||
IsVisible="{Binding !IsFolder}"
|
</ContentControl>
|
||||||
ToolTip.Tip="{DynamicResource Text.Filter}"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
|
@ -60,32 +63,28 @@
|
||||||
|
|
||||||
<DataTemplate DataType="vm:TagCollectionAsList">
|
<DataTemplate DataType="vm:TagCollectionAsList">
|
||||||
<ListBox Classes="repo_left_content_list"
|
<ListBox Classes="repo_left_content_list"
|
||||||
|
Margin="12,0,0,0"
|
||||||
ItemsSource="{Binding Tags}"
|
ItemsSource="{Binding Tags}"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
SelectionChanged="OnRowSelectionChanged">
|
SelectionChanged="OnRowSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate DataType="m:Tag">
|
<DataTemplate DataType="m:Tag">
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto"
|
<Grid ColumnDefinitions="Auto,*,20"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
ContextRequested="OnRowContextRequested"
|
ContextRequested="OnRowContextRequested"
|
||||||
ToolTip.Tip="{Binding Message}">
|
ToolTip.Tip="{Binding Message}">
|
||||||
<Path Grid.Column="0"
|
<Path Grid.Column="0"
|
||||||
Width="10" Height="10"
|
Margin="4,0,0,0"
|
||||||
Margin="8,0,0,0"
|
Width="12" Height="12"
|
||||||
Data="{StaticResource Icons.Tag}"/>
|
Data="{StaticResource Icons.Tag}"/>
|
||||||
|
|
||||||
<TextBlock Grid.Column="1"
|
<TextBlock Grid.Column="1"
|
||||||
Classes="primary"
|
Classes="primary"
|
||||||
Text="{Binding Name}"
|
Text="{Binding Name}"
|
||||||
Margin="8,0,0,0"/>
|
Margin="8,0,0,0"
|
||||||
|
TextTrimming="CharacterEllipsis"/>
|
||||||
|
|
||||||
<ToggleButton Grid.Column="2"
|
<v:FilterModeSwitchButton Grid.Column="2" Mode="{Binding FilterMode}"/>
|
||||||
Classes="filter"
|
|
||||||
Margin="0,0,8,0"
|
|
||||||
Background="Transparent"
|
|
||||||
Click="OnToggleFilterClicked"
|
|
||||||
IsChecked="{Binding IsFiltered, Mode=TwoWay}"
|
|
||||||
ToolTip.Tip="{DynamicResource Text.Filter}"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.Tag != null)
|
if (node.Tag != null)
|
||||||
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Tag");
|
CreateContent(new Thickness(0, 0, 0, 0), "Icons.Tag");
|
||||||
else if (node.IsExpanded)
|
else if (node.IsExpanded)
|
||||||
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder.Open");
|
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder.Open");
|
||||||
else
|
else
|
||||||
|
@ -247,23 +247,6 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleFilterClicked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is ToggleButton toggle && DataContext is ViewModels.Repository repo)
|
|
||||||
{
|
|
||||||
var target = null as Models.Tag;
|
|
||||||
if (toggle.DataContext is ViewModels.TagTreeNode node)
|
|
||||||
target = node.Tag;
|
|
||||||
else if (toggle.DataContext is Models.Tag tag)
|
|
||||||
target = tag;
|
|
||||||
|
|
||||||
if (target != null)
|
|
||||||
repo.UpdateFilters([target.Name], toggle.IsChecked == true);
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MakeTreeRows(List<ViewModels.TagTreeNode> rows, List<ViewModels.TagTreeNode> nodes)
|
private void MakeTreeRows(List<ViewModels.TagTreeNode> rows, List<ViewModels.TagTreeNode> nodes)
|
||||||
{
|
{
|
||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue