feature: add tooltip for SHA in commit message presenter (#734)

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo 2024-11-24 21:22:04 +08:00
parent 637f138d63
commit b2e01f0d3e
No known key found for this signature in database
4 changed files with 80 additions and 11 deletions

View file

@ -175,7 +175,7 @@ namespace SourceGit.Models
var body = reader.Result; var body = reader.Result;
if (!rsp.IsSuccessStatusCode) if (!rsp.IsSuccessStatusCode)
{ {
throw new Exception($"AI service returns error code {rsp.StatusCode}. Body: {body??string.Empty}"); throw new Exception($"AI service returns error code {rsp.StatusCode}. Body: {body ?? string.Empty}");
} }
return JsonSerializer.Deserialize(reader.Result, JsonCodeGen.Default.OpenAIChatResponse); return JsonSerializer.Deserialize(reader.Result, JsonCodeGen.Default.OpenAIChatResponse);

View file

@ -211,6 +211,20 @@
<Setter Property="MaxWidth" Value="800"/> <Setter Property="MaxWidth" Value="800"/>
</Style> </Style>
</v:CommitMessagePresenter.Styles> </v:CommitMessagePresenter.Styles>
<v:CommitMessagePresenter.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>
</v:CommitMessagePresenter.DataTemplates>
</v:CommitMessagePresenter> </v:CommitMessagePresenter>
</Grid> </Grid>
</StackPanel> </StackPanel>

View file

@ -1,12 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Avalonia; using Avalonia;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Documents; using Avalonia.Controls.Documents;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Threading;
using Avalonia.VisualTree; using Avalonia.VisualTree;
namespace SourceGit.Views namespace SourceGit.Views
@ -43,7 +45,9 @@ namespace SourceGit.Views
if (change.Property == MessageProperty || change.Property == IssueTrackerRulesProperty) if (change.Property == MessageProperty || change.Property == IssueTrackerRulesProperty)
{ {
Inlines!.Clear(); Inlines!.Clear();
_inlineCommits.Clear();
_matches = null; _matches = null;
_lastHover = null;
ClearHoveredIssueLink(); ClearHoveredIssueLink();
var message = Message; var message = Message;
@ -154,6 +158,10 @@ namespace SourceGit.Views
ToolTip.SetTip(this, match.Link); ToolTip.SetTip(this, match.Link);
ToolTip.SetIsOpen(this, true); ToolTip.SetIsOpen(this, true);
} }
else
{
ProcessHoverCommitLink(match);
}
return; return;
} }
@ -256,6 +264,52 @@ namespace SourceGit.Views
ClearHoveredIssueLink(); ClearHoveredIssueLink();
} }
private void ProcessHoverCommitLink(Models.Hyperlink link)
{
var sha = link.Link;
// If we have already queried this SHA, just use it.
if (_inlineCommits.TryGetValue(sha, out var exist))
{
if (exist != null)
{
ToolTip.SetTip(this, exist);
ToolTip.SetIsOpen(this, true);
}
return;
}
var parentView = this.FindAncestorOfType<CommitBaseInfo>();
if (parentView is { DataContext: ViewModels.CommitDetail detail })
{
// Record the SHA of current viewing commit in the CommitDetail panel to determine if it is changed after
// asynchronous queries.
var lastDetailCommit = detail.Commit.SHA;
Task.Run(() =>
{
var c = detail.GetParent(sha);
Dispatcher.UIThread.Invoke(() =>
{
// Make sure the DataContext of CommitBaseInfo is not changed.
var currentParent = this.FindAncestorOfType<CommitBaseInfo>();
if (currentParent is { DataContext: ViewModels.CommitDetail currentDetail } &&
currentDetail.Commit.SHA == lastDetailCommit)
{
_inlineCommits.Add(sha, c);
// Make sure user still hovers the target SHA.
if (_lastHover == link)
{
ToolTip.SetTip(this, c);
ToolTip.SetIsOpen(this, true);
}
}
});
});
}
}
private void ClearHoveredIssueLink() private void ClearHoveredIssueLink()
{ {
if (_lastHover != null) if (_lastHover != null)
@ -268,5 +322,6 @@ namespace SourceGit.Views
private List<Models.Hyperlink> _matches = null; private List<Models.Hyperlink> _matches = null;
private Models.Hyperlink _lastHover = null; private Models.Hyperlink _lastHover = null;
private Dictionary<string, Models.Commit> _inlineCommits = new();
} }
} }

View file

@ -476,7 +476,7 @@ namespace SourceGit.Views
get => GetValue(SelectedChunkProperty); get => GetValue(SelectedChunkProperty);
set => SetValue(SelectedChunkProperty, value); set => SetValue(SelectedChunkProperty, value);
} }
public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty = public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty =
AvaloniaProperty.Register<ThemedTextDiffPresenter, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0)); AvaloniaProperty.Register<ThemedTextDiffPresenter, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0));
@ -523,7 +523,7 @@ namespace SourceGit.Views
var firstLineIdx = DisplayRange.StartIdx; var firstLineIdx = DisplayRange.StartIdx;
if (firstLineIdx <= 1) if (firstLineIdx <= 1)
return; return;
var lines = GetLines(); var lines = GetLines();
var firstLineType = lines[firstLineIdx].Type; var firstLineType = lines[firstLineIdx].Type;
var prevLineType = lines[firstLineIdx - 1].Type; var prevLineType = lines[firstLineIdx - 1].Type;
@ -761,7 +761,7 @@ namespace SourceGit.Views
if (start > index) if (start > index)
start = index; start = index;
} }
SetCurrentValue(DisplayRangeProperty, new TextDiffViewRange(start, start + count)); SetCurrentValue(DisplayRangeProperty, new TextDiffViewRange(start, start + count));
} }
@ -1313,9 +1313,9 @@ namespace SourceGit.Views
private ScrollViewer _scrollViewer = null; private ScrollViewer _scrollViewer = null;
} }
public class TextDiffViewMinimap : Control public class TextDiffViewMinimap : Control
{ {
public static readonly StyledProperty<IBrush> AddedLineBrushProperty = public static readonly StyledProperty<IBrush> AddedLineBrushProperty =
AvaloniaProperty.Register<TextDiffViewMinimap, IBrush>(nameof(AddedLineBrush), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0))); AvaloniaProperty.Register<TextDiffViewMinimap, IBrush>(nameof(AddedLineBrush), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
@ -1333,7 +1333,7 @@ namespace SourceGit.Views
get => GetValue(DeletedLineBrushProperty); get => GetValue(DeletedLineBrushProperty);
set => SetValue(DeletedLineBrushProperty, value); set => SetValue(DeletedLineBrushProperty, value);
} }
public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty = public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty =
AvaloniaProperty.Register<TextDiffViewMinimap, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0)); AvaloniaProperty.Register<TextDiffViewMinimap, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0));
@ -1342,7 +1342,7 @@ namespace SourceGit.Views
get => GetValue(DisplayRangeProperty); get => GetValue(DisplayRangeProperty);
set => SetValue(DisplayRangeProperty, value); set => SetValue(DisplayRangeProperty, value);
} }
public static readonly StyledProperty<Color> DisplayRangeColorProperty = public static readonly StyledProperty<Color> DisplayRangeColorProperty =
AvaloniaProperty.Register<TextDiffViewMinimap, Color>(nameof(DisplayRangeColor), Colors.RoyalBlue); AvaloniaProperty.Register<TextDiffViewMinimap, Color>(nameof(DisplayRangeColor), Colors.RoyalBlue);
@ -1376,7 +1376,7 @@ namespace SourceGit.Views
total = diff.Lines.Count; total = diff.Lines.Count;
RenderSingleSide(context, diff.Lines, 0, Bounds.Width); RenderSingleSide(context, diff.Lines, 0, Bounds.Width);
} }
var range = DisplayRange; var range = DisplayRange;
if (range.EndIdx == 0) if (range.EndIdx == 0)
return; return;
@ -1416,7 +1416,7 @@ namespace SourceGit.Views
lastLineTypeStart = i; lastLineTypeStart = i;
} }
} }
RenderBlock(context, lastLineType, lastLineTypeStart, total - lastLineTypeStart, total, x, width); RenderBlock(context, lastLineType, lastLineTypeStart, total - lastLineTypeStart, total, x, width);
} }
@ -1431,7 +1431,7 @@ namespace SourceGit.Views
} }
} }
} }
public partial class TextDiffView : UserControl public partial class TextDiffView : UserControl
{ {
public static readonly StyledProperty<bool> UseSideBySideDiffProperty = public static readonly StyledProperty<bool> UseSideBySideDiffProperty =