diff --git a/src/Models/CommitLink.cs b/src/Models/CommitLink.cs
new file mode 100644
index 00000000..6a421797
--- /dev/null
+++ b/src/Models/CommitLink.cs
@@ -0,0 +1,8 @@
+namespace SourceGit.Models
+{
+ public class CommitLink
+ {
+ public string Name { get; set; } = null;
+ public string URLTemplate { get; set; } = null;
+ }
+}
diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml
index a159d764..5f148b50 100644
--- a/src/Resources/Icons.axaml
+++ b/src/Resources/Icons.axaml
@@ -59,6 +59,7 @@
M40 9 15 23 15 31 9 28 9 20 34 5 24 0 0 14 0 34 25 48 25 28 49 14zM26 29 26 48 49 34 49 15z
M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l132 0 0-128 64 0 0 128 132 0 0 64-132 0 0 128-64 0 0-128-132 0Z
M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l328 0 0 64-328 0Z
+ M 968 418 l -95 94 c -59 59 -146 71 -218 37 L 874 331 a 64 64 0 0 0 0 -90 L 783 150 a 64 64 0 0 0 -90 0 L 475 368 c -34 -71 -22 -159 37 -218 l 94 -94 c 75 -75 196 -75 271 0 l 90 90 c 75 75 75 196 0 271 z M 332 693 a 64 64 0 0 1 0 -90 l 271 -271 c 25 -25 65 -25 90 0 s 25 65 0 90 L 422 693 a 64 64 0 0 1 -90 0 z M 151 783 l 90 90 a 64 64 0 0 0 90 0 l 218 -218 c 34 71 22 159 -37 218 l -86 94 a 192 192 0 0 1 -271 0 l -98 -98 a 192 192 0 0 1 0 -271 l 94 -86 c 59 -59 146 -71 218 -37 L 151 693 a 64 64 0 0 0 0 90 z
M0 33h1024v160H0zM0 432h1024v160H0zM0 831h1024v160H0z
M512 0C233 0 7 223 0 500C6 258 190 64 416 64c230 0 416 200 416 448c0 53 43 96 96 96s96-43 96-96c0-283-229-512-512-512zm0 1023c279 0 505-223 512-500c-6 242-190 436-416 436c-230 0-416-200-416-448c0-53-43-96-96-96s-96 43-96 96c0 283 229 512 512 512z
M976 0h-928A48 48 0 000 48v652a48 48 0 0048 48h416V928H200a48 48 0 000 96h624a48 48 0 000-96H560v-180h416a48 48 0 0048-48V48A48 48 0 00976 0zM928 652H96V96h832v556z
diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs
index ae0e2cb9..04fe4d06 100644
--- a/src/ViewModels/CommitDetail.cs
+++ b/src/ViewModels/CommitDetail.cs
@@ -66,7 +66,7 @@ namespace SourceGit.ViewModels
if (value == null || value.Count != 1)
DiffContext = null;
else
- DiffContext = new DiffContext(_repo, new Models.DiffOption(_commit, value[0]), _diffContext);
+ DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(_commit, value[0]), _diffContext);
}
}
}
@@ -89,15 +89,19 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _viewRevisionFileContent, value);
}
- public AvaloniaList IssueTrackerRules
+ public AvaloniaList WebLinks
{
- get => _issueTrackerRules;
+ get => _repo.TryGetCommitLinks();
}
- public CommitDetail(string repo, AvaloniaList issueTrackerRules)
+ public AvaloniaList IssueTrackerRules
+ {
+ get => _repo.Settings?.IssueTrackerRules;
+ }
+
+ public CommitDetail(Repository repo)
{
_repo = repo;
- _issueTrackerRules = issueTrackerRules;
}
public void Cleanup()
@@ -118,8 +122,7 @@ namespace SourceGit.ViewModels
public void NavigateTo(string commitSHA)
{
- var repo = App.FindOpenedRepository(_repo);
- repo?.NavigateToCommit(commitSHA);
+ _repo?.NavigateToCommit(commitSHA);
}
public void ClearSearchChangeFilter()
@@ -129,7 +132,7 @@ namespace SourceGit.ViewModels
public List GetRevisionFilesUnderFolder(string parentFolder)
{
- return new Commands.QueryRevisionObjects(_repo, _commit.SHA, parentFolder).Result();
+ return new Commands.QueryRevisionObjects(_repo.FullPath, _commit.SHA, parentFolder).Result();
}
public void ViewRevisionFile(Models.Object file)
@@ -145,13 +148,13 @@ namespace SourceGit.ViewModels
case Models.ObjectType.Blob:
Task.Run(() =>
{
- var isBinary = new Commands.IsBinary(_repo, _commit.SHA, file.Path).Result();
+ var isBinary = new Commands.IsBinary(_repo.FullPath, _commit.SHA, file.Path).Result();
if (isBinary)
{
var ext = Path.GetExtension(file.Path);
if (IMG_EXTS.Contains(ext))
{
- var stream = Commands.QueryFileContent.Run(_repo, _commit.SHA, file.Path);
+ var stream = Commands.QueryFileContent.Run(_repo.FullPath, _commit.SHA, file.Path);
var bitmap = stream.Length > 0 ? new Bitmap(stream) : null;
Dispatcher.UIThread.Invoke(() =>
{
@@ -160,7 +163,7 @@ namespace SourceGit.ViewModels
}
else
{
- var size = new Commands.QueryFileSize(_repo, file.Path, _commit.SHA).Result();
+ var size = new Commands.QueryFileSize(_repo.FullPath, file.Path, _commit.SHA).Result();
Dispatcher.UIThread.Invoke(() =>
{
ViewRevisionFileContent = new Models.RevisionBinaryFile() { Size = size };
@@ -170,7 +173,7 @@ namespace SourceGit.ViewModels
return;
}
- var contentStream = Commands.QueryFileContent.Run(_repo, _commit.SHA, file.Path);
+ var contentStream = Commands.QueryFileContent.Run(_repo.FullPath, _commit.SHA, file.Path);
var content = new StreamReader(contentStream).ReadToEnd();
var matchLFS = REG_LFS_FORMAT().Match(content);
if (matchLFS.Success)
@@ -191,7 +194,7 @@ namespace SourceGit.ViewModels
case Models.ObjectType.Commit:
Task.Run(() =>
{
- var submoduleRoot = Path.Combine(_repo, file.Path);
+ var submoduleRoot = Path.Combine(_repo.FullPath, file.Path);
var commit = new Commands.QuerySingleCommit(submoduleRoot, file.SHA).Result();
if (commit != null)
{
@@ -237,7 +240,7 @@ namespace SourceGit.ViewModels
var toolPath = Preference.Instance.ExternalMergeToolPath;
var opt = new Models.DiffOption(_commit, change);
- Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, opt));
+ Task.Run(() => Commands.MergeTool.OpenForDiff(_repo.FullPath, toolType, toolPath, opt));
ev.Handled = true;
};
menu.Items.Add(diffWithMerger);
@@ -249,7 +252,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, ev) =>
{
- var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path, _issueTrackerRules) };
+ var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) };
window.Show();
ev.Handled = true;
};
@@ -259,12 +262,12 @@ namespace SourceGit.ViewModels
blame.Icon = App.CreateMenuIcon("Icons.Blame");
blame.Click += (_, ev) =>
{
- var window = new Views.Blame() { DataContext = new Blame(_repo, change.Path, _commit.SHA) };
+ var window = new Views.Blame() { DataContext = new Blame(_repo.FullPath, change.Path, _commit.SHA) };
window.Show();
ev.Handled = true;
};
- var full = Path.GetFullPath(Path.Combine(_repo, change.Path));
+ var full = Path.GetFullPath(Path.Combine(_repo.FullPath, change.Path));
var explore = new MenuItem();
explore.Header = App.Text("RevealFile");
explore.Icon = App.CreateMenuIcon("Icons.Explore");
@@ -312,7 +315,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, ev) =>
{
- var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path, _issueTrackerRules) };
+ var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path) };
window.Show();
ev.Handled = true;
};
@@ -323,12 +326,12 @@ namespace SourceGit.ViewModels
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
blame.Click += (_, ev) =>
{
- var window = new Views.Blame() { DataContext = new Blame(_repo, file.Path, _commit.SHA) };
+ var window = new Views.Blame() { DataContext = new Blame(_repo.FullPath, file.Path, _commit.SHA) };
window.Show();
ev.Handled = true;
};
- var full = Path.GetFullPath(Path.Combine(_repo, file.Path));
+ var full = Path.GetFullPath(Path.Combine(_repo.FullPath, file.Path));
var explore = new MenuItem();
explore.Header = App.Text("RevealFile");
explore.Icon = App.CreateMenuIcon("Icons.Explore");
@@ -353,7 +356,7 @@ namespace SourceGit.ViewModels
if (selected.Count == 1)
{
var saveTo = Path.Combine(selected[0].Path.LocalPath, Path.GetFileName(file.Path));
- Commands.SaveRevisionFile.Run(_repo, _commit.SHA, file.Path, saveTo);
+ Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, saveTo);
}
ev.Handled = true;
@@ -406,9 +409,9 @@ namespace SourceGit.ViewModels
Task.Run(() =>
{
- var fullMessage = new Commands.QueryCommitFullMessage(_repo, _commit.SHA).Result();
+ var fullMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, _commit.SHA).Result();
var parent = _commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : _commit.Parents[0];
- var cmdChanges = new Commands.CompareRevisions(_repo, parent, _commit.SHA) { Cancel = _cancelToken };
+ var cmdChanges = new Commands.CompareRevisions(_repo.FullPath, parent, _commit.SHA) { Cancel = _cancelToken };
var changes = cmdChanges.Result();
var visible = changes;
if (!string.IsNullOrWhiteSpace(_searchChangeFilter))
@@ -463,8 +466,7 @@ namespace SourceGit.ViewModels
".ico", ".bmp", ".jpg", ".png", ".jpeg"
};
- private string _repo;
- private AvaloniaList _issueTrackerRules = null;
+ private Repository _repo = null;
private int _activePageIndex = 0;
private Models.Commit _commit = null;
private string _fullMessage = string.Empty;
diff --git a/src/ViewModels/FileHistories.cs b/src/ViewModels/FileHistories.cs
index 79696a7e..e1284b2f 100644
--- a/src/ViewModels/FileHistories.cs
+++ b/src/ViewModels/FileHistories.cs
@@ -1,8 +1,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
-using Avalonia.Collections;
using Avalonia.Threading;
-
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
@@ -35,7 +33,7 @@ namespace SourceGit.ViewModels
}
else
{
- DiffContext = new DiffContext(_repo, new Models.DiffOption(value, _file), _diffContext);
+ DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(value, _file), _diffContext);
DetailContext.Commit = value;
}
}
@@ -54,15 +52,15 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _detailContext, value);
}
- public FileHistories(string repo, string file, AvaloniaList issueTrackerRules)
+ public FileHistories(Repository repo, string file)
{
_repo = repo;
_file = file;
- _detailContext = new CommitDetail(repo, issueTrackerRules);
+ _detailContext = new CommitDetail(repo);
Task.Run(() =>
{
- var commits = new Commands.QueryCommits(_repo, $"-n 10000 -- \"{file}\"", false).Result();
+ var commits = new Commands.QueryCommits(_repo.FullPath, $"-n 10000 -- \"{file}\"", false).Result();
Dispatcher.UIThread.Invoke(() =>
{
IsLoading = false;
@@ -73,7 +71,7 @@ namespace SourceGit.ViewModels
});
}
- private readonly string _repo = null;
+ private readonly Repository _repo = null;
private readonly string _file = null;
private bool _isLoading = true;
private List _commits = null;
diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs
index 8f21bf70..4a0a05a0 100644
--- a/src/ViewModels/Histories.cs
+++ b/src/ViewModels/Histories.cs
@@ -93,7 +93,7 @@ namespace SourceGit.ViewModels
}
else
{
- var commitDetail = new CommitDetail(_repo.FullPath, _repo.Settings.IssueTrackerRules);
+ var commitDetail = new CommitDetail(_repo);
commitDetail.Commit = commit;
DetailContext = commitDetail;
}
@@ -121,7 +121,7 @@ namespace SourceGit.ViewModels
}
else
{
- var commitDetail = new CommitDetail(_repo.FullPath, _repo.Settings.IssueTrackerRules);
+ var commitDetail = new CommitDetail(_repo);
commitDetail.Commit = commit;
DetailContext = commitDetail;
}
diff --git a/src/ViewModels/InteractiveRebase.cs b/src/ViewModels/InteractiveRebase.cs
index 32417e01..0c8838e0 100644
--- a/src/ViewModels/InteractiveRebase.cs
+++ b/src/ViewModels/InteractiveRebase.cs
@@ -114,7 +114,7 @@ namespace SourceGit.ViewModels
Current = current;
On = on;
IsLoading = true;
- DetailContext = new CommitDetail(repoPath, repo.Settings.IssueTrackerRules);
+ DetailContext = new CommitDetail(repo);
Task.Run(() =>
{
diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs
index e248967a..6cbe9576 100644
--- a/src/ViewModels/Repository.cs
+++ b/src/ViewModels/Repository.cs
@@ -491,6 +491,25 @@ namespace SourceGit.ViewModels
PopupHost.ShowAndStartPopup(new Cleanup(this));
}
+ public AvaloniaList TryGetCommitLinks()
+ {
+ var rs = new AvaloniaList();
+ foreach (var remote in _remotes)
+ {
+ if (remote.TryGetVisitURL(out var url))
+ {
+ if (url.StartsWith("https://github.com/", StringComparison.Ordinal))
+ rs.Add(new Models.CommitLink() { Name = "Github", URLTemplate = $"{url}/commit/SOURCEGIT_COMMIT_HASH_CODE" });
+ else if (url.StartsWith("https://gitlab.com/", StringComparison.Ordinal))
+ rs.Add(new Models.CommitLink() { Name = "GitLab", URLTemplate = $"{url}/-/commit/SOURCEGIT_COMMIT_HASH_CODE" });
+ else if (url.StartsWith("https://gitee.com/", StringComparison.Ordinal))
+ rs.Add(new Models.CommitLink() { Name = "Gitee", URLTemplate = $"{url}/commit/SOURCEGIT_COMMIT_HASH_CODE" });
+ }
+ }
+
+ return rs;
+ }
+
public void ClearHistoriesFilter()
{
_settings.Filters.Clear();
diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs
index c72900ec..9658eb48 100644
--- a/src/ViewModels/WorkingCopy.cs
+++ b/src/ViewModels/WorkingCopy.cs
@@ -567,7 +567,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, e) =>
{
- var window = new Views.FileHistories() { DataContext = new FileHistories(_repo.FullPath, change.Path, _repo.Settings.IssueTrackerRules) };
+ var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) };
window.Show();
e.Handled = true;
};
diff --git a/src/Views/CommitBaseInfo.axaml b/src/Views/CommitBaseInfo.axaml
index d2c57810..53e194ff 100644
--- a/src/Views/CommitBaseInfo.axaml
+++ b/src/Views/CommitBaseInfo.axaml
@@ -54,7 +54,17 @@
-
+
+
+
+
+
+
diff --git a/src/Views/CommitBaseInfo.axaml.cs b/src/Views/CommitBaseInfo.axaml.cs
index 86451dfe..8c5e3d98 100644
--- a/src/Views/CommitBaseInfo.axaml.cs
+++ b/src/Views/CommitBaseInfo.axaml.cs
@@ -2,20 +2,12 @@ using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input;
+using Avalonia.Interactivity;
namespace SourceGit.Views
{
public partial class CommitBaseInfo : UserControl
{
- public static readonly StyledProperty CanNavigateProperty =
- AvaloniaProperty.Register(nameof(CanNavigate), true);
-
- public bool CanNavigate
- {
- get => GetValue(CanNavigateProperty);
- set => SetValue(CanNavigateProperty, value);
- }
-
public static readonly StyledProperty MessageProperty =
AvaloniaProperty.Register(nameof(Message), string.Empty);
@@ -25,6 +17,15 @@ namespace SourceGit.Views
set => SetValue(MessageProperty, value);
}
+ public static readonly StyledProperty> WebLinksProperty =
+ AvaloniaProperty.Register>(nameof(WebLinks));
+
+ public AvaloniaList WebLinks
+ {
+ get => GetValue(WebLinksProperty);
+ set => SetValue(WebLinksProperty, value);
+ }
+
public static readonly StyledProperty> IssueTrackerRulesProperty =
AvaloniaProperty.Register>(nameof(IssueTrackerRules));
@@ -39,11 +40,43 @@ namespace SourceGit.Views
InitializeComponent();
}
+ private void OnOpenWebLink(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ViewModels.CommitDetail detail)
+ {
+ var links = WebLinks;
+ if (links.Count > 1)
+ {
+ var menu = new ContextMenu();
+
+ foreach (var link in links)
+ {
+ var url = link.URLTemplate.Replace("SOURCEGIT_COMMIT_HASH_CODE", detail.Commit.SHA);
+ var item = new MenuItem() { Header = link.Name };
+ item.Click += (_, ev) =>
+ {
+ Native.OS.OpenBrowser(url);
+ ev.Handled = true;
+ };
+
+ menu.Items.Add(item);
+ }
+
+ (sender as Control)?.OpenContextMenu(menu);
+ }
+ else if (links.Count == 1)
+ {
+ var url = links[0].URLTemplate.Replace("SOURCEGIT_COMMIT_HASH_CODE", detail.Commit.SHA);
+ Native.OS.OpenBrowser(url);
+ }
+ }
+
+ e.Handled = true;
+ }
+
private void OnParentSHAPressed(object sender, PointerPressedEventArgs e)
{
- if (sender is Control { DataContext: string sha } &&
- DataContext is ViewModels.CommitDetail detail &&
- CanNavigate)
+ if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha })
{
detail.NavigateTo(sha);
}
diff --git a/src/Views/CommitDetail.axaml b/src/Views/CommitDetail.axaml
index af733f49..432fa737 100644
--- a/src/Views/CommitDetail.axaml
+++ b/src/Views/CommitDetail.axaml
@@ -21,6 +21,7 @@
diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml
index b573a32d..9e927205 100644
--- a/src/Views/DiffView.axaml
+++ b/src/Views/DiffView.axaml
@@ -176,7 +176,7 @@
-
+
@@ -190,7 +190,7 @@
-
+
diff --git a/src/Views/RevisionFiles.axaml b/src/Views/RevisionFiles.axaml
index 5066195d..aef71e19 100644
--- a/src/Views/RevisionFiles.axaml
+++ b/src/Views/RevisionFiles.axaml
@@ -73,7 +73,7 @@
-
+