diff --git a/src/Everything2Everything.App/App.xaml.cs b/src/Everything2Everything.App/App.xaml.cs index 95291d4..c4d3140 100644 --- a/src/Everything2Everything.App/App.xaml.cs +++ b/src/Everything2Everything.App/App.xaml.cs @@ -2,19 +2,27 @@ using System.Windows; using Everything2Everything.App.Cli; using Everything2Everything.App.Views; using Everything2Everything.Core; +using Microsoft.Extensions.DependencyInjection; namespace Everything2Everything.App; public partial class App : Application { - /// App·LlmProvider가 공유하는 설정 저장소 (키 저장 즉시 변환에 반영). - public ISettingsStore Settings { get; } = new DpapiSettingsStore(); + private readonly IServiceProvider _services; + + /// App·LlmProvider가 공유하는 설정 저장소 (키 저장 즉시 변환에 반영). DI 컨테이너 단일 싱글턴. + public ISettingsStore Settings { get; } public ConversionEngine Engine { get; } public App() { - Engine = Everything2EverythingBootstrap.CreateDefault(Settings); + // 컴포지션 루트 — Core의 DI 확장(Scrutor 자동등록)으로 Provider/Registry/Engine/Settings를 구성. + var services = new ServiceCollection(); + services.AddEverything2Everything(); + _services = services.BuildServiceProvider(); + Settings = _services.GetRequiredService(); + Engine = _services.GetRequiredService(); } protected override async void OnStartup(StartupEventArgs e) @@ -68,14 +76,14 @@ public partial class App : Application private void ShowMainWindow() { - var window = new MainWindow(); + var window = new MainWindow(Engine, Settings); MainWindow = window; window.Show(); } private void ShowConvertDialog(IReadOnlyList files) { - var window = new Views.MainWindow(files); + var window = new Views.MainWindow(Engine, Settings, files); MainWindow = window; window.Show(); } diff --git a/src/Everything2Everything.App/Views/MainWindow.xaml.cs b/src/Everything2Everything.App/Views/MainWindow.xaml.cs index d73b3a1..52b7a51 100644 --- a/src/Everything2Everything.App/Views/MainWindow.xaml.cs +++ b/src/Everything2Everything.App/Views/MainWindow.xaml.cs @@ -16,6 +16,8 @@ namespace Everything2Everything.App.Views; public partial class MainWindow : Wpf.Ui.Controls.FluentWindow { + private readonly ConversionEngine _engine; + private readonly ISettingsStore _settings; private readonly ObservableCollection _activeQueue = new(); private readonly ObservableCollection _pastResults = new(); private CancellationTokenSource? _cts; @@ -28,10 +30,11 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow public ICommand CloseCommand { get; } public ICommand RefreshCommand { get; } - public MainWindow() : this(null) { } - - public MainWindow(IReadOnlyList? initialFiles) + public MainWindow(ConversionEngine engine, ISettingsStore settings, IReadOnlyList? initialFiles = null) { + _engine = engine; + _settings = settings; + AddFilesCommand = new RelayCommand(_ => PickAndAddFiles()); ProcessQueueCommand = new RelayCommand(_ => OnProcessQueueClick(this, new RoutedEventArgs()), _ => _activeQueue.Count > 0 && _cts is null); @@ -66,7 +69,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow private async Task RefreshCapabilityStatusAsync() { - var engine = ((App)Application.Current).Engine; + var engine = _engine; var notReady = new List(); foreach (var p in engine.Providers.All) { @@ -90,7 +93,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow private void OnSettingsClick(object sender, RoutedEventArgs e) { - var win = new SettingsWindow(((App)Application.Current).Settings) { Owner = this }; + var win = new SettingsWindow(_settings) { Owner = this }; win.ShowDialog(); _ = RefreshCapabilityStatusAsync(); RefreshAvailableOutputFormats(); @@ -304,7 +307,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow var targetLang = AiTargetLangBox?.Text?.Trim(); opts.Ai.TargetLanguage = string.IsNullOrEmpty(targetLang) ? null : targetLang; - opts.VideoPreferGpu = ((App)Application.Current).Settings.Get("video.gpu") != "false"; + opts.VideoPreferGpu = _settings.Get("video.gpu") != "false"; return opts; } @@ -563,7 +566,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow UpdateProcessQueueButton(); ShowProcessingProgress(snapshot.Count); - var engine = ((App)Application.Current).Engine; + var engine = _engine; var options = BuildOptions(); var reporter = new Progress(p => @@ -780,7 +783,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow { try { - ContextMenuRegistrar.Register(((App)Application.Current).Engine); + ContextMenuRegistrar.Register(_engine); MessageBox.Show(this, "컨텍스트 메뉴를 등록했습니다.\n파일 우클릭 → \"추가 옵션 표시\" 또는 \"JPEG로 빠른 변환/변환…\".", "Everything2Everything", MessageBoxButton.OK, MessageBoxImage.Information); @@ -794,7 +797,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow private void OnDiagnoseClick(object sender, RoutedEventArgs e) { - var window = new DiagnoseWindow(((App)Application.Current).Engine) { Owner = this }; + var window = new DiagnoseWindow(_engine) { Owner = this }; window.ShowDialog(); } @@ -934,7 +937,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow private LossClass? WorstLossForQueue(string outputExt) { if (_activeQueue.Count == 0) return null; - var graph = ((App)Application.Current).Engine.Providers.Graph; + var graph = _engine.Providers.Graph; LossClass? worst = null; foreach (var item in _activeQueue) { @@ -971,7 +974,7 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow { if (OutputFormatCombo is null) return; - var engine = ((App)Application.Current).Engine; + var engine = _engine; IReadOnlyCollection available; if (_activeQueue.Count == 0)