From e8ec1350b316ca32aba47ea7e6a3450d17c8772b Mon Sep 17 00:00:00 2001 From: Yun Chan Date: Sat, 15 Aug 2026 15:02:23 +0900 Subject: [PATCH] refactor(3): VideoDownloader.Browser library - tabs/find/search-engine/zoom/bookmark-history stores extracted from App (66 GREEN) --- VideoDownloader.App/AppPaths.cs | 11 ++-------- VideoDownloader.App/MainWindow.xaml.cs | 6 +++--- VideoDownloader.App/SettingsWindow.xaml.cs | 2 +- .../VideoDownloader.App.csproj | 1 + .../BrowserModels.cs | 2 +- .../BrowserStore.cs | 4 ++-- .../FindSession.cs | 2 +- .../SearchEngine.cs | 2 +- .../SearchEngineResolver.cs | 2 +- .../SiteZoomStore.cs | 2 +- .../Tabs/TabItem.cs | 13 +++++++----- .../Tabs/TabManager.cs | 2 +- .../Tabs/TabSessionStore.cs | 2 +- .../VideoDownloader.Browser.csproj | 21 +++++++++++++++++++ VideoDownloader.Core/Platform/CorePaths.cs | 13 ++++++++++++ .../Browser/FindSessionTests.cs | 2 +- .../Browser/SearchEngineResolverTests.cs | 2 +- .../Browser/SiteZoomStoreTests.cs | 2 +- .../Browser/TabManagerTests.cs | 2 +- VideoDownloader.slnx | 1 + 20 files changed, 63 insertions(+), 31 deletions(-) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/BrowserModels.cs (76%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/BrowserStore.cs (96%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/FindSession.cs (99%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/SearchEngine.cs (97%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/SearchEngineResolver.cs (98%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/SiteZoomStore.cs (98%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/Tabs/TabItem.cs (82%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/Tabs/TabManager.cs (99%) rename {VideoDownloader.App/Browser => VideoDownloader.Browser}/Tabs/TabSessionStore.cs (96%) create mode 100644 VideoDownloader.Browser/VideoDownloader.Browser.csproj create mode 100644 VideoDownloader.Core/Platform/CorePaths.cs diff --git a/VideoDownloader.App/AppPaths.cs b/VideoDownloader.App/AppPaths.cs index aaf14f1..1c7f738 100644 --- a/VideoDownloader.App/AppPaths.cs +++ b/VideoDownloader.App/AppPaths.cs @@ -1,14 +1,7 @@ namespace VideoDownloader.App; -/// -/// 앱 데이터 디렉터리 결정. 기본 %AppData%/VideoDownloader. -/// 환경변수 VD_DATA_DIR 로 오버라이드 — E2E 테스트가 실사용자 프로필/설정/세션과 -/// 격리된 임시 디렉터리에서 실행되도록 한다(결정적 테스트를 위한 공식 후크). -/// +/// 앱 데이터 디렉터리(CorePaths 위임) — VD_DATA_DIR 오버라이드 지원. public static class AppPaths { - public static string DataDir => - Environment.GetEnvironmentVariable("VD_DATA_DIR") is { Length: > 0 } env - ? env - : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VideoDownloader"); + public static string DataDir => VideoDownloader.Core.Platform.CorePaths.DataDir; } diff --git a/VideoDownloader.App/MainWindow.xaml.cs b/VideoDownloader.App/MainWindow.xaml.cs index 1f302d0..8362bb6 100644 --- a/VideoDownloader.App/MainWindow.xaml.cs +++ b/VideoDownloader.App/MainWindow.xaml.cs @@ -9,14 +9,14 @@ using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; using Microsoft.Web.WebView2.Core; -using VideoDownloader.App.Browser; -using VideoDownloader.App.Browser.Tabs; +using VideoDownloader.Browser; +using VideoDownloader.Browser.Tabs; using VideoDownloader.App.Core; using VideoDownloader.Core.Detection; using VideoDownloader.App.ViewModels; using VideoDownloader.Core.Config; using Wv2 = Microsoft.Web.WebView2.Wpf; -using TabItem = VideoDownloader.App.Browser.Tabs.TabItem; +using TabItem = VideoDownloader.Browser.Tabs.TabItem; namespace VideoDownloader.App; diff --git a/VideoDownloader.App/SettingsWindow.xaml.cs b/VideoDownloader.App/SettingsWindow.xaml.cs index 34525e2..53602a1 100644 --- a/VideoDownloader.App/SettingsWindow.xaml.cs +++ b/VideoDownloader.App/SettingsWindow.xaml.cs @@ -4,7 +4,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; using Microsoft.Win32; -using VideoDownloader.App.Browser; +using VideoDownloader.Browser; using VideoDownloader.Core.Config; using VideoDownloader.Core.Social; diff --git a/VideoDownloader.App/VideoDownloader.App.csproj b/VideoDownloader.App/VideoDownloader.App.csproj index 358ac62..d6a1ad1 100644 --- a/VideoDownloader.App/VideoDownloader.App.csproj +++ b/VideoDownloader.App/VideoDownloader.App.csproj @@ -21,6 +21,7 @@ + diff --git a/VideoDownloader.App/Browser/BrowserModels.cs b/VideoDownloader.Browser/BrowserModels.cs similarity index 76% rename from VideoDownloader.App/Browser/BrowserModels.cs rename to VideoDownloader.Browser/BrowserModels.cs index b513cd4..60ed3b7 100644 --- a/VideoDownloader.App/Browser/BrowserModels.cs +++ b/VideoDownloader.Browser/BrowserModels.cs @@ -1,4 +1,4 @@ -namespace VideoDownloader.App.Browser; +namespace VideoDownloader.Browser; public record Bookmark(string Title, string Url); diff --git a/VideoDownloader.App/Browser/BrowserStore.cs b/VideoDownloader.Browser/BrowserStore.cs similarity index 96% rename from VideoDownloader.App/Browser/BrowserStore.cs rename to VideoDownloader.Browser/BrowserStore.cs index 159dfd2..495291e 100644 --- a/VideoDownloader.App/Browser/BrowserStore.cs +++ b/VideoDownloader.Browser/BrowserStore.cs @@ -1,13 +1,13 @@ using System.Text.Json; -namespace VideoDownloader.App.Browser; +namespace VideoDownloader.Browser; /// 즐겨찾기/히스토리 JSON 영속화 (%AppData%/VideoDownloader). /// #5 저장/로드 실패를 조용 삼킴하지 않고 browserstore.log 에 기록하며, /// 손상 파일은 백업 후 빈 목록을 반환(다음 저장이 원본을 덮어쓰는 데이터 손실 방지). public static class BrowserStore { - private static string Dir => AppPaths.DataDir; + private static string Dir => VideoDownloader.Core.Platform.CorePaths.DataDir; private static string BookmarksPath => Path.Combine(Dir, "bookmarks.json"); private static string HistoryPath => Path.Combine(Dir, "history.json"); private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true }; diff --git a/VideoDownloader.App/Browser/FindSession.cs b/VideoDownloader.Browser/FindSession.cs similarity index 99% rename from VideoDownloader.App/Browser/FindSession.cs rename to VideoDownloader.Browser/FindSession.cs index 59a31f5..0e37b27 100644 --- a/VideoDownloader.App/Browser/FindSession.cs +++ b/VideoDownloader.Browser/FindSession.cs @@ -1,6 +1,6 @@ using Microsoft.Web.WebView2.Core; -namespace VideoDownloader.App.Browser; +namespace VideoDownloader.Browser; /// 네이티브 Find API 의 최소 추상화(단위 테스트용 fake 교체 가능). public interface IFindApi diff --git a/VideoDownloader.App/Browser/SearchEngine.cs b/VideoDownloader.Browser/SearchEngine.cs similarity index 97% rename from VideoDownloader.App/Browser/SearchEngine.cs rename to VideoDownloader.Browser/SearchEngine.cs index 8138bf3..3898191 100644 --- a/VideoDownloader.App/Browser/SearchEngine.cs +++ b/VideoDownloader.Browser/SearchEngine.cs @@ -1,4 +1,4 @@ -namespace VideoDownloader.App.Browser; +namespace VideoDownloader.Browser; /// 검색엔진 정의. QueryTemplate 의 {0} 이 URL 인코딩된 검색어로 치환된다. public sealed record SearchEngine(string Name, string Keyword, string QueryTemplate); diff --git a/VideoDownloader.App/Browser/SearchEngineResolver.cs b/VideoDownloader.Browser/SearchEngineResolver.cs similarity index 98% rename from VideoDownloader.App/Browser/SearchEngineResolver.cs rename to VideoDownloader.Browser/SearchEngineResolver.cs index a56e306..c7d9a73 100644 --- a/VideoDownloader.App/Browser/SearchEngineResolver.cs +++ b/VideoDownloader.Browser/SearchEngineResolver.cs @@ -1,6 +1,6 @@ using System.Text.RegularExpressions; -namespace VideoDownloader.App.Browser; +namespace VideoDownloader.Browser; /// /// 주소창 입력을 URL 또는 검색 의도로 판별한다(T1-4). diff --git a/VideoDownloader.App/Browser/SiteZoomStore.cs b/VideoDownloader.Browser/SiteZoomStore.cs similarity index 98% rename from VideoDownloader.App/Browser/SiteZoomStore.cs rename to VideoDownloader.Browser/SiteZoomStore.cs index 81f63f3..f064b83 100644 --- a/VideoDownloader.App/Browser/SiteZoomStore.cs +++ b/VideoDownloader.Browser/SiteZoomStore.cs @@ -1,7 +1,7 @@ using System.IO; using System.Text.Json; -namespace VideoDownloader.App.Browser; +namespace VideoDownloader.Browser; /// /// 사이트별 줌 배율 영속 저장소(T1-7). WebView2 는 사이트별 줌 영속을 보장하지 않아 diff --git a/VideoDownloader.App/Browser/Tabs/TabItem.cs b/VideoDownloader.Browser/Tabs/TabItem.cs similarity index 82% rename from VideoDownloader.App/Browser/Tabs/TabItem.cs rename to VideoDownloader.Browser/Tabs/TabItem.cs index 7bc220b..4d7c7ac 100644 --- a/VideoDownloader.App/Browser/Tabs/TabItem.cs +++ b/VideoDownloader.Browser/Tabs/TabItem.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using System.Runtime.CompilerServices; using Microsoft.Web.WebView2.Wpf; -namespace VideoDownloader.App.Browser.Tabs; +namespace VideoDownloader.Browser.Tabs; /// 탭 하나의 상태. View(WebView2 컨트롤)는 앱 레이어에서 주입한다(단위 테스트에선 null). public sealed class TabItem : INotifyPropertyChanged @@ -44,10 +44,13 @@ public sealed class TabItem : INotifyPropertyChanged /// 닫힌 시점의 인덱스(닫힌 탭 복원용). 열려 있는 동안은 무의미. internal int ClosedIndex { get; set; } = -1; - // ---- 탭별 일시 상태(앱 레이어 전용) ---- - internal string? PendingHistoryUrl; // SourceChanged → 타이틀 확정 사이의 기록 대기 URL - internal string? PendingSocialUrl; // 소셜 카드 제목 갱신 대기 URL - internal FindSession? FindSession; // 탭별 페이지 내 검색 세션 (cv 바인딩) + // ---- 탭별 일시 상태(호스트 앱이 사용) ---- + /// SourceChanged → 타이틀 확정 사이의 히스토리 기록 대기 URL. + public string? PendingHistoryUrl { get; set; } + /// 소셜 카드 제목 갱신 대기 URL. + public string? PendingSocialUrl { get; set; } + /// 탭별 페이지 내 검색 세션 (CoreWebView2 바인딩). + public FindSession? FindSession { get; set; } public event PropertyChangedEventHandler? PropertyChanged; diff --git a/VideoDownloader.App/Browser/Tabs/TabManager.cs b/VideoDownloader.Browser/Tabs/TabManager.cs similarity index 99% rename from VideoDownloader.App/Browser/Tabs/TabManager.cs rename to VideoDownloader.Browser/Tabs/TabManager.cs index 8cfde04..4f90806 100644 --- a/VideoDownloader.App/Browser/Tabs/TabManager.cs +++ b/VideoDownloader.Browser/Tabs/TabManager.cs @@ -1,6 +1,6 @@ using System.Collections.ObjectModel; -namespace VideoDownloader.App.Browser.Tabs; +namespace VideoDownloader.Browser.Tabs; /// /// 탭 관리 순수 로직(Phase A). WebView2 생성은 주입된 팩토리/어태처가 담당해 diff --git a/VideoDownloader.App/Browser/Tabs/TabSessionStore.cs b/VideoDownloader.Browser/Tabs/TabSessionStore.cs similarity index 96% rename from VideoDownloader.App/Browser/Tabs/TabSessionStore.cs rename to VideoDownloader.Browser/Tabs/TabSessionStore.cs index c15c733..b193eee 100644 --- a/VideoDownloader.App/Browser/Tabs/TabSessionStore.cs +++ b/VideoDownloader.Browser/Tabs/TabSessionStore.cs @@ -1,7 +1,7 @@ using System.IO; using System.Text.Json; -namespace VideoDownloader.App.Browser.Tabs; +namespace VideoDownloader.Browser.Tabs; /// 세션 JSON 저장소(T1-10). 종료 시 탭 URL 저장, 시작 시 복원. public static class TabSessionStore diff --git a/VideoDownloader.Browser/VideoDownloader.Browser.csproj b/VideoDownloader.Browser/VideoDownloader.Browser.csproj new file mode 100644 index 0000000..82186a3 --- /dev/null +++ b/VideoDownloader.Browser/VideoDownloader.Browser.csproj @@ -0,0 +1,21 @@ + + + net8.0-windows + enable + enable + true + true + VideoDownloader.Browser + + + + + + + + + + + + + diff --git a/VideoDownloader.Core/Platform/CorePaths.cs b/VideoDownloader.Core/Platform/CorePaths.cs new file mode 100644 index 0000000..435e94c --- /dev/null +++ b/VideoDownloader.Core/Platform/CorePaths.cs @@ -0,0 +1,13 @@ +namespace VideoDownloader.Core.Platform; + +/// +/// 앱 데이터 디렉터리 결정(Core 레벨). 기본 %AppData%/VideoDownloader. +/// VD_DATA_DIR 환경변수로 오버라이드 — E2E 테스트 격리 공식 후크. +/// +public static class CorePaths +{ + public static string DataDir => + Environment.GetEnvironmentVariable("VD_DATA_DIR") is { Length: > 0 } env + ? env + : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VideoDownloader"); +} diff --git a/VideoDownloader.Tests/Browser/FindSessionTests.cs b/VideoDownloader.Tests/Browser/FindSessionTests.cs index 5d3c27b..1e7f9aa 100644 --- a/VideoDownloader.Tests/Browser/FindSessionTests.cs +++ b/VideoDownloader.Tests/Browser/FindSessionTests.cs @@ -1,4 +1,4 @@ -using VideoDownloader.App.Browser; +using VideoDownloader.Browser; namespace VideoDownloader.Tests.Browser; diff --git a/VideoDownloader.Tests/Browser/SearchEngineResolverTests.cs b/VideoDownloader.Tests/Browser/SearchEngineResolverTests.cs index 105bffc..bec1d41 100644 --- a/VideoDownloader.Tests/Browser/SearchEngineResolverTests.cs +++ b/VideoDownloader.Tests/Browser/SearchEngineResolverTests.cs @@ -1,4 +1,4 @@ -using VideoDownloader.App.Browser; +using VideoDownloader.Browser; namespace VideoDownloader.Tests.Browser; diff --git a/VideoDownloader.Tests/Browser/SiteZoomStoreTests.cs b/VideoDownloader.Tests/Browser/SiteZoomStoreTests.cs index 72f6f46..d8c8ddd 100644 --- a/VideoDownloader.Tests/Browser/SiteZoomStoreTests.cs +++ b/VideoDownloader.Tests/Browser/SiteZoomStoreTests.cs @@ -1,4 +1,4 @@ -using VideoDownloader.App.Browser; +using VideoDownloader.Browser; namespace VideoDownloader.Tests.Browser; diff --git a/VideoDownloader.Tests/Browser/TabManagerTests.cs b/VideoDownloader.Tests/Browser/TabManagerTests.cs index 8bc7125..1426b89 100644 --- a/VideoDownloader.Tests/Browser/TabManagerTests.cs +++ b/VideoDownloader.Tests/Browser/TabManagerTests.cs @@ -1,4 +1,4 @@ -using VideoDownloader.App.Browser.Tabs; +using VideoDownloader.Browser.Tabs; namespace VideoDownloader.Tests.Browser; diff --git a/VideoDownloader.slnx b/VideoDownloader.slnx index a6b90d2..6268e20 100644 --- a/VideoDownloader.slnx +++ b/VideoDownloader.slnx @@ -1,6 +1,7 @@ +