211 lines
8.6 KiB
C#
211 lines
8.6 KiB
C#
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Media;
|
|
using AxCopilot.Services;
|
|
|
|
namespace AxCopilot.Views;
|
|
|
|
/// <summary>
|
|
/// 에이전트 파일 수정 시 변경 전/후 diff를 보여주는 패널.
|
|
/// DiffService의 결과를 색상 하이라이트로 렌더링하고
|
|
/// Accept/Reject 버튼으로 변경 승인/취소를 지원합니다.
|
|
/// </summary>
|
|
public class DiffViewerPanel : Border
|
|
{
|
|
private readonly string _filePath;
|
|
private readonly string _oldContent;
|
|
private readonly string _newContent;
|
|
private readonly List<DiffService.DiffLine> _diffLines;
|
|
|
|
/// <summary>사용자가 Accept를 눌렀을 때 발생합니다.</summary>
|
|
public event EventHandler? Accepted;
|
|
|
|
/// <summary>사용자가 Reject를 눌렀을 때 발생합니다.</summary>
|
|
public event EventHandler? Rejected;
|
|
|
|
public DiffViewerPanel(string filePath, string oldContent, string newContent)
|
|
{
|
|
_filePath = filePath;
|
|
_oldContent = oldContent;
|
|
_newContent = newContent;
|
|
_diffLines = DiffService.ComputeDiff(oldContent, newContent);
|
|
|
|
CornerRadius = new CornerRadius(10);
|
|
Background = new SolidColorBrush(Color.FromRgb(0xFA, 0xFA, 0xFF));
|
|
BorderBrush = new SolidColorBrush(Color.FromRgb(0xE0, 0xE0, 0xEC));
|
|
BorderThickness = new Thickness(1);
|
|
Padding = new Thickness(0);
|
|
Margin = new Thickness(0, 8, 0, 8);
|
|
|
|
Child = BuildContent();
|
|
}
|
|
|
|
private UIElement BuildContent()
|
|
{
|
|
var mainStack = new StackPanel();
|
|
|
|
// 헤더
|
|
var header = new Border
|
|
{
|
|
Background = new SolidColorBrush(Color.FromRgb(0xF0, 0xF2, 0xFF)),
|
|
CornerRadius = new CornerRadius(10, 10, 0, 0),
|
|
Padding = new Thickness(14, 10, 14, 10),
|
|
};
|
|
var headerGrid = new Grid();
|
|
headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
|
headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
|
|
|
|
var summary = DiffService.GetSummary(_diffLines);
|
|
var titlePanel = new StackPanel { Orientation = Orientation.Horizontal };
|
|
titlePanel.Children.Add(new TextBlock
|
|
{
|
|
Text = "\uE89A",
|
|
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
|
FontSize = 13, Foreground = new SolidColorBrush(Color.FromRgb(0x4B, 0x5E, 0xFC)),
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Margin = new Thickness(0, 0, 8, 0),
|
|
});
|
|
titlePanel.Children.Add(new TextBlock
|
|
{
|
|
Text = System.IO.Path.GetFileName(_filePath),
|
|
FontSize = 13, FontWeight = FontWeights.SemiBold,
|
|
Foreground = new SolidColorBrush(Color.FromRgb(0x1A, 0x1B, 0x2E)),
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
});
|
|
titlePanel.Children.Add(new TextBlock
|
|
{
|
|
Text = $" · {summary}",
|
|
FontSize = 11,
|
|
Foreground = new SolidColorBrush(Color.FromRgb(0x88, 0x88, 0xAA)),
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
});
|
|
Grid.SetColumn(titlePanel, 0);
|
|
headerGrid.Children.Add(titlePanel);
|
|
|
|
// Accept / Reject 버튼
|
|
var btnPanel = new StackPanel { Orientation = Orientation.Horizontal };
|
|
var acceptBtn = CreateButton("적용", Color.FromRgb(0x10, 0x7C, 0x10), Colors.White);
|
|
acceptBtn.Click += (_, _) => Accepted?.Invoke(this, EventArgs.Empty);
|
|
btnPanel.Children.Add(acceptBtn);
|
|
|
|
var rejectBtn = CreateButton("취소", Colors.Transparent, Color.FromRgb(0xC5, 0x0F, 0x1F));
|
|
rejectBtn.Click += (_, _) => Rejected?.Invoke(this, EventArgs.Empty);
|
|
btnPanel.Children.Add(rejectBtn);
|
|
|
|
Grid.SetColumn(btnPanel, 1);
|
|
headerGrid.Children.Add(btnPanel);
|
|
|
|
header.Child = headerGrid;
|
|
mainStack.Children.Add(header);
|
|
|
|
// Diff 내용
|
|
var scrollViewer = new ScrollViewer
|
|
{
|
|
MaxHeight = 300,
|
|
VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
|
|
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
|
|
};
|
|
|
|
var diffStack = new StackPanel { Margin = new Thickness(0) };
|
|
|
|
foreach (var line in _diffLines)
|
|
{
|
|
var (bg, fg, prefix) = line.Type switch
|
|
{
|
|
DiffService.DiffType.Added => (
|
|
Color.FromRgb(0xE6, 0xFF, 0xED),
|
|
Color.FromRgb(0x16, 0x6C, 0x34),
|
|
"+"),
|
|
DiffService.DiffType.Removed => (
|
|
Color.FromRgb(0xFF, 0xEB, 0xE9),
|
|
Color.FromRgb(0xCF, 0x22, 0x2E),
|
|
"-"),
|
|
_ => (
|
|
Color.FromRgb(0xFF, 0xFF, 0xFF),
|
|
Color.FromRgb(0x66, 0x66, 0x88),
|
|
" ")
|
|
};
|
|
|
|
var lineNo = line.OldLineNo?.ToString() ?? "";
|
|
var newLineNo = line.NewLineNo?.ToString() ?? "";
|
|
|
|
var linePanel = new Border
|
|
{
|
|
Background = new SolidColorBrush(bg),
|
|
Padding = new Thickness(8, 1, 8, 1),
|
|
};
|
|
|
|
var lineGrid = new Grid();
|
|
lineGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(36) }); // old line
|
|
lineGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(36) }); // new line
|
|
lineGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(16) }); // prefix
|
|
lineGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); // content
|
|
|
|
var oldLineText = new TextBlock
|
|
{
|
|
Text = lineNo, FontSize = 10, FontFamily = new FontFamily("Consolas"),
|
|
Foreground = new SolidColorBrush(Color.FromRgb(0xAA, 0xAA, 0xCC)),
|
|
HorizontalAlignment = HorizontalAlignment.Right, Margin = new Thickness(0, 0, 4, 0),
|
|
};
|
|
Grid.SetColumn(oldLineText, 0);
|
|
lineGrid.Children.Add(oldLineText);
|
|
|
|
var newLineText = new TextBlock
|
|
{
|
|
Text = newLineNo, FontSize = 10, FontFamily = new FontFamily("Consolas"),
|
|
Foreground = new SolidColorBrush(Color.FromRgb(0xAA, 0xAA, 0xCC)),
|
|
HorizontalAlignment = HorizontalAlignment.Right, Margin = new Thickness(0, 0, 4, 0),
|
|
};
|
|
Grid.SetColumn(newLineText, 1);
|
|
lineGrid.Children.Add(newLineText);
|
|
|
|
var prefixText = new TextBlock
|
|
{
|
|
Text = prefix, FontSize = 11, FontFamily = new FontFamily("Consolas"),
|
|
Foreground = new SolidColorBrush(fg), FontWeight = FontWeights.Bold,
|
|
};
|
|
Grid.SetColumn(prefixText, 2);
|
|
lineGrid.Children.Add(prefixText);
|
|
|
|
var contentText = new TextBlock
|
|
{
|
|
Text = line.Content, FontSize = 11, FontFamily = new FontFamily("Consolas"),
|
|
Foreground = new SolidColorBrush(fg),
|
|
TextWrapping = TextWrapping.NoWrap,
|
|
};
|
|
Grid.SetColumn(contentText, 3);
|
|
lineGrid.Children.Add(contentText);
|
|
|
|
linePanel.Child = lineGrid;
|
|
diffStack.Children.Add(linePanel);
|
|
}
|
|
|
|
scrollViewer.Content = diffStack;
|
|
mainStack.Children.Add(scrollViewer);
|
|
|
|
return mainStack;
|
|
}
|
|
|
|
private static Button CreateButton(string text, Color bg, Color fg)
|
|
{
|
|
var btn = new Button { Cursor = System.Windows.Input.Cursors.Hand, Margin = new Thickness(4, 0, 0, 0) };
|
|
var template = new ControlTemplate(typeof(Button));
|
|
var bdFactory = new FrameworkElementFactory(typeof(Border));
|
|
bdFactory.SetValue(Border.BackgroundProperty, new SolidColorBrush(bg));
|
|
bdFactory.SetValue(Border.CornerRadiusProperty, new CornerRadius(6));
|
|
bdFactory.SetValue(Border.PaddingProperty, new Thickness(12, 5, 12, 5));
|
|
if (bg == Colors.Transparent)
|
|
{
|
|
bdFactory.SetValue(Border.BorderBrushProperty, new SolidColorBrush(fg));
|
|
bdFactory.SetValue(Border.BorderThicknessProperty, new Thickness(1));
|
|
}
|
|
var cpFactory = new FrameworkElementFactory(typeof(ContentPresenter));
|
|
cpFactory.SetValue(ContentPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
|
bdFactory.AppendChild(cpFactory);
|
|
template.VisualTree = bdFactory;
|
|
btn.Template = template;
|
|
btn.Content = new TextBlock { Text = text, FontSize = 11, Foreground = new SolidColorBrush(fg), FontWeight = FontWeights.SemiBold };
|
|
return btn;
|
|
}
|
|
}
|