1
0
Fork 0

feat(tools): add first-run external tool installer wizard and catalog

첫 실행 시 외부 도구 설치 마법사를 띄우고 7종(FFmpeg·LibreOffice·Pandoc·ImageMagick·H2Orestart·agy·Codex)을 기본 전체 선택 상태로 순차 설치한다.
- Core: ExternalToolCatalog(정적 카탈로그, winget ID 실검증), ExternalToolInstaller(winget 무인 실행·재감지 판정, IExternalCommandRunner 시드로 테스트 가능)
- Core: ExternalToolDetector에 winget FFmpeg 스캔 + Pandoc/ImageMagick 감지 추가
- App: ToolSetupWindow + ToolSetupViewModel, 첫 실행 플래그(setup.tools.done), 설정 창 '외부 도구 설치/검증' 재진입 버튼
- Tests: ExternalToolInstallerTests 5건
- 기존 미커밋 작업(광고 Ads 지원: AdBannerControl/AdLargeCardControl/AdService, AI 백엔드 agy·switchboard·codex 채팅 클라이언트, 관련 테스트) 포함
This commit is contained in:
Yun Chan 2026-09-07 21:16:49 +09:00
parent f00f6567f4
commit 6a41c4a0dc
37 changed files with 2545 additions and 69 deletions

View file

@ -12,6 +12,7 @@ using Everything2Everything.App.Shell;
using Everything2Everything.App.ViewModels;
using Everything2Everything.Core;
using Everything2Everything.Core.Filters;
using Everything2Everything.Core.Ads;
using Everything2Everything.Core.Inspector;
using Everything2Everything.Core.Presets;
using LossClass = Everything2Everything.Core.Providers.LossClass;
@ -134,15 +135,22 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow, INotifyPropertyC
if (_selectedCategory != value)
{
_selectedCategory = value;
if (CategoryFilterCombo != null && CategoryFilterCombo.SelectedIndex != (int)value)
{
CategoryFilterCombo.SelectedIndex = (int)value;
}
ApplyQueueFilters();
}
}
}
public MainWindow(ConversionEngine engine, ISettingsStore settings, IReadOnlyList<string>? initialFiles = null)
public AdViewModel AdVm { get; }
public MainWindow(ConversionEngine engine, ISettingsStore settings, IReadOnlyList<string>? initialFiles = null, IAdService? adService = null)
{
_engine = engine;
_settings = settings;
AdVm = new AdViewModel(adService ?? new AdService());
AddFilesCommand = new RelayCommand(_ => PickAndAddFiles());
ProcessQueueCommand = new RelayCommand(_ => OnProcessQueueClick(this, new RoutedEventArgs()),
@ -828,6 +836,18 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow, INotifyPropertyC
}
}
private void OnCategoryFilterSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (CategoryFilterCombo?.SelectedItem is ComboBoxItem item && item.Tag is string tag)
{
ApplyFilterCategory(tag);
}
else if (CategoryFilterCombo != null && CategoryFilterCombo.SelectedIndex >= 0)
{
SelectedCategory = (FilterCategory)CategoryFilterCombo.SelectedIndex;
}
}
private void ApplyFilterCategory(string? categoryName)
{
if (Enum.TryParse<FilterCategory>(categoryName, true, out var cat))
@ -1540,9 +1560,25 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow, INotifyPropertyC
if (PdfQuickPanel is not null)
PdfQuickPanel.Visibility = isPdf ? Visibility.Visible : Visibility.Collapsed;
var isText = ext is ".txt" or ".md";
if (AiQuickPanel is not null)
AiQuickPanel.Visibility = isText ? Visibility.Visible : Visibility.Collapsed;
if (AiTargetLanguagePanel is not null && AiTaskQuickCombo is not null)
AiTargetLanguagePanel.Visibility = (isText && AiTaskQuickCombo.SelectedIndex == 1)
? Visibility.Visible
: Visibility.Collapsed;
UpdateMediaPanelForFormat(extension);
}
private void OnAiTaskSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (AiTargetLanguagePanel is null || AiTaskQuickCombo is null) return;
AiTargetLanguagePanel.Visibility = AiTaskQuickCombo.SelectedIndex == 1
? Visibility.Visible
: Visibility.Collapsed;
}
/// <summary>출력이 영상/오디오/PDF/이미지일 때 상세 인코딩 폴드아웃 서브패널 노출(Fluent 2 점진적 공개 패턴).</summary>
private void UpdateMediaPanelForFormat(string? extension)
{