Added feature to display LFS images in the file browser & file history

This commit is contained in:
Henrik Andersson 2025-06-05 12:45:00 +02:00
parent eebadd67a1
commit 6def15212c
7 changed files with 157 additions and 17 deletions

View file

@ -230,9 +230,23 @@ namespace SourceGit.ViewModels
var matchLFS = REG_LFS_FORMAT().Match(content);
if (matchLFS.Success)
{
var obj = new Models.RevisionLFSObject() { Object = new Models.LFSObject() };
obj.Object.Oid = matchLFS.Groups[1].Value;
obj.Object.Size = long.Parse(matchLFS.Groups[2].Value);
var lfsObj = new Models.RevisionLFSObject() { Object = new Models.LFSObject
{
Oid = matchLFS.Groups[1].Value,
Size = long.Parse(matchLFS.Groups[2].Value)
}};
var ext = Path.GetExtension(file.Path);
var obj = null as object;
if (IMG_EXTS.Contains(ext))
{
var imageType = ext!.Substring(1).ToUpper(CultureInfo.CurrentCulture);
obj = new RevisionLFSImageObject(_repo.FullPath, lfsObj, imageType);
}
else
{
obj = lfsObj;
}
Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = obj);
}
else

View file

@ -103,10 +103,23 @@ namespace SourceGit.ViewModels
var matchLFS = REG_LFS_FORMAT().Match(content);
if (matchLFS.Success)
{
var lfs = new Models.RevisionLFSObject() { Object = new() };
lfs.Object.Oid = matchLFS.Groups[1].Value;
lfs.Object.Size = long.Parse(matchLFS.Groups[2].Value);
Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, lfs));
var lfs = new Models.RevisionLFSObject() { Object = new Models.LFSObject {
Oid = matchLFS.Groups[1].Value,
Size = long.Parse(matchLFS.Groups[2].Value)
} };
var ext = Path.GetExtension(_file);
var obj = null as object;
if (IMG_EXTS.Contains(ext))
{
var imageType = Path.GetExtension(_file)!.TrimStart('.').ToUpper(CultureInfo.CurrentCulture);
obj = new RevisionLFSImageObject(_repo.FullPath, lfs, ext);
}
else
{
obj = lfs;
}
Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, obj));
}
else
{

View file

@ -34,7 +34,7 @@ namespace SourceGit.ViewModels
});
}
private (Bitmap, long) BitmapFromLFSObject(string repo, Models.LFSObject lfs)
public static (Bitmap, long) BitmapFromLFSObject(string repo, Models.LFSObject lfs)
{
if (string.IsNullOrEmpty(lfs.Oid) || lfs.Size == 0)
return (null, 0);

View file

@ -0,0 +1,38 @@
using System.Threading.Tasks;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class RevisionLFSImageObject : ObservableObject
{
public Models.RevisionLFSObject LFS
{
get;
}
public Models.RevisionImageFile Image
{
get => _image;
private set => SetProperty(ref _image, value);
}
public RevisionLFSImageObject(string repo, Models.RevisionLFSObject lfs, string ext)
{
LFS = lfs;
Task.Run(() =>
{
var img = new Models.RevisionImageFile
{
ImageType = ext
};
(img.Image, img.FileSize) = SourceGit.ViewModels.LFSImageDiff.BitmapFromLFSObject(repo, LFS.Object);
Dispatcher.UIThread.Invoke(() => Image = img);
});
}
private Models.RevisionImageFile _image;
}
}

View file

@ -49,15 +49,59 @@
</DataTemplate>
<DataTemplate DataType="m:RevisionLFSObject">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.CommitDetail.Files.LFS}" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
<Path Width="64" Height="64" Margin="0,24,0,0" Data="{StaticResource Icons.LFS}" Fill="{DynamicResource Brush.FG2}"/>
<SelectableTextBlock Margin="0,16,0,0" Text="{Binding Object.Oid}" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
<StackPanel Margin="0,8,0,0" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Classes="primary" Text="{Binding Object.Size}" Foreground="{DynamicResource Brush.FG2}"/>
<TextBlock Text="{DynamicResource Text.Bytes}" Margin="8,0,0,0" Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
</StackPanel>
<v:RevisionFileLFSContentViewer/>
</DataTemplate>
<DataTemplate DataType="vm:RevisionLFSImageObject">
<TabControl Margin="0,8,0,0" SelectedIndex="{Binding Source={x:Static vm:Preferences.Instance}, Path=LFSImageDiffActiveIdx, Mode=TwoWay}">
<TabControl.Styles>
<Style Selector="TabControl /template/ ItemsPresenter#PART_ItemsPresenter > WrapPanel">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</TabControl.Styles>
<TabItem>
<TabItem.Header>
<TextBlock Text="LFS" FontWeight="Bold" />
</TabItem.Header>
<ContentControl Content="{Binding LFS}">
<ContentControl.DataTemplates>
<DataTemplate DataType="m:RevisionLFSObject">
<v:RevisionFileLFSContentViewer/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Text="IMAGE" FontWeight="Bold" />
</TabItem.Header>
<ContentControl Content="{Binding Image}">
<Grid RowDefinitions="*,Auto" Margin="0,8" VerticalAlignment="Center" HorizontalAlignment="Center">
<Border Grid.Row="0" Effect="drop-shadow(0 0 8 #A0000000)">
<Border Background="{DynamicResource Brush.Window}">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
<v:ImageView Image="{Binding Image.Image}"/>
</Border>
</Border>
</Border>
<StackPanel Grid.Row="1" Margin="0,8,0,0" Orientation="Horizontal" HorizontalAlignment="Center">
<Border Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center">
<TextBlock Classes="primary" Text="{Binding Image.ImageType}" Margin="8,0" FontSize="10" Foreground="{DynamicResource Brush.BadgeFG}"/>
</Border>
<TextBlock Classes="primary" Text="{Binding Image.ImageSize}" Margin="8,0,0,0"/>
<TextBlock Classes="primary" Text="{Binding Image.FileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
<TextBlock Classes="primary" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
</StackPanel>
</Grid>
</ContentControl>
</TabItem>
</TabControl>
</DataTemplate>
<DataTemplate DataType="m:RevisionSubmodule">

View file

@ -0,0 +1,19 @@
<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.RevisionFileLFSContentViewer"
x:DataType="m:RevisionLFSObject">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.CommitDetail.Files.LFS}" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
<Path Width="64" Height="64" Margin="0,24,0,0" Data="{StaticResource Icons.LFS}" Fill="{DynamicResource Brush.FG2}"/>
<SelectableTextBlock Margin="0,16,0,0" Text="{Binding Object.Oid}" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
<StackPanel Margin="0,8,0,0" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Classes="primary" Text="{Binding Object.Size}" Foreground="{DynamicResource Brush.FG2}"/>
<TextBlock Text="{DynamicResource Text.Bytes}" Margin="8,0,0,0" Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
</StackPanel>
</UserControl>

View file

@ -0,0 +1,12 @@
using Avalonia.Controls;
namespace SourceGit.Views
{
public partial class RevisionFileLFSContentViewer : UserControl
{
public RevisionFileLFSContentViewer()
{
InitializeComponent();
}
}
}