Files
AX-Copilot-Codex/src/AxCopilot/Views/QuickLookWindow.xaml.cs
lacvet f7cafe0cfc 런처 Agent Compare 기능 1차 이식 및 현재 런처 구조 연결
- Agent Compare 기준으로 런처 빠른 실행 칩, 검색 히스토리 탐색, 선택 항목 미리보기 패널을 현재 런처에 이식
- 하단 위젯 바, QuickLook(F3), 화면 OCR(F4), 관련 서비스/partial 파일을 현재 LauncherWindow/LauncherViewModel 구조에 연결
- UsageRankingService 상위 항목 조회와 SearchHistoryService를 추가해 실행 상위 경로/검색 기록이 실제 런처 동작에 반영되도록 정리
- README.md, docs/DEVELOPMENT.md에 이식 범위와 검증 결과를 2026-04-05 11:58 (KST) 기준으로 기록

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 경고 0 / 오류 0
2026-04-05 11:51:43 +09:00

144 lines
4.5 KiB
C#

using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using UglyToad.PdfPig;
namespace AxCopilot.Views;
public partial class QuickLookWindow : Window
{
private static readonly HashSet<string> ImageExts = new(StringComparer.OrdinalIgnoreCase)
{
".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".ico", ".tiff", ".tif"
};
private static readonly HashSet<string> TextExts = new(StringComparer.OrdinalIgnoreCase)
{
".txt", ".md", ".cs", ".vb", ".fs", ".py", ".js", ".ts", ".jsx", ".tsx",
".json", ".xml", ".xaml", ".yaml", ".yml", ".toml", ".ini", ".conf",
".log", ".csv", ".html", ".htm", ".css", ".scss", ".less",
".sql", ".sh", ".bash", ".bat", ".cmd", ".ps1",
".config", ".env", ".gitignore", ".editorconfig",
".java", ".cpp", ".c", ".h", ".hpp", ".rs", ".go", ".rb", ".php", ".swift",
".vue", ".svelte", ".dockerfile"
};
public QuickLookWindow(string path, Window owner)
{
InitializeComponent();
Owner = owner;
KeyDown += OnKeyDown;
Loaded += (_, _) => LoadPreview(path);
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key is Key.Escape or Key.F3)
{
Close();
e.Handled = true;
}
}
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
DragMove();
}
private void BtnClose_Click(object sender, MouseButtonEventArgs e) => Close();
private void LoadPreview(string path)
{
try
{
FileNameText.Text = Path.GetFileName(path);
if (Directory.Exists(path))
{
ShowInfo("\uE838", "폴더", path);
return;
}
if (!File.Exists(path))
{
ShowInfo("\uE783", "파일을 찾을 수 없습니다.", path);
return;
}
var info = new FileInfo(path);
var ext = Path.GetExtension(path);
FooterPath.Text = path;
FooterMeta.Text = $"{FormatSize(info.Length)} · {info.LastWriteTime:yyyy-MM-dd HH:mm}";
if (ImageExts.Contains(ext))
{
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = fs;
image.EndInit();
image.Freeze();
PreviewImage.Source = image;
ImageScrollViewer.Visibility = Visibility.Visible;
FileTypeIcon.Text = "\uE91B";
return;
}
if (string.Equals(ext, ".pdf", StringComparison.OrdinalIgnoreCase))
{
using var doc = PdfDocument.Open(path);
var page = doc.NumberOfPages > 0 ? doc.GetPage(1).Text : "";
PdfPreviewText.Text = page.Length > 1200 ? page[..1200] + "…" : page;
PdfScrollViewer.Visibility = Visibility.Visible;
FileTypeIcon.Text = "\uEA90";
return;
}
if (TextExts.Contains(ext))
{
string text;
try
{
text = File.ReadAllText(path, Encoding.UTF8);
}
catch
{
text = File.ReadAllText(path);
}
PreviewText.Text = text.Length > 4000 ? text[..4000] + "\n…" : text;
TextScrollViewer.Visibility = Visibility.Visible;
FileTypeIcon.Text = "\uE8A5";
return;
}
ShowInfo("\uE7C3", $"파일 · {ext.TrimStart('.').ToUpperInvariant()}", path);
}
catch (Exception ex)
{
ShowInfo("\uEA39", "미리보기를 열지 못했습니다.", ex.Message);
}
}
private void ShowInfo(string icon, string title, string detail)
{
InfoTypeIcon.Text = icon;
InfoTypeName.Text = title;
InfoSubText.Text = detail;
InfoPanel.Visibility = Visibility.Visible;
}
private static string FormatSize(long bytes) => bytes switch
{
< 1024 => $"{bytes} B",
< 1048576 => $"{bytes / 1024.0:F1} KB",
< 1073741824 => $"{bytes / 1048576.0:F1} MB",
_ => $"{bytes / 1073741824.0:F2} GB"
};
}