런처 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
This commit is contained in:
143
src/AxCopilot/Views/QuickLookWindow.xaml.cs
Normal file
143
src/AxCopilot/Views/QuickLookWindow.xaml.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
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"
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user