Phase B (T1-5/T1-6/T2-2/T2-8/T2-12): download manager flyout w/ speed+pause/resume/cancel, bookmark bar, tab sleeping, tab search (open+closed), context menu w/ 'download video from this link' (79 tests GREEN)

This commit is contained in:
Yun Chan 2026-08-15 15:09:59 +09:00
parent af19dba8f4
commit 0caa1111e7
9 changed files with 763 additions and 3 deletions

View file

@ -5,6 +5,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
xmlns:vm="clr-namespace:VideoDownloader.App.ViewModels"
xmlns:local="clr-namespace:VideoDownloader.App"
xmlns:feat="clr-namespace:VideoDownloader.App.Browser.Features"
mc:Ignorable="d"
FontFamily="{StaticResource UiFont}"
Title="Video Downloader" Height="820" Width="1300"
@ -153,6 +155,7 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
@ -186,6 +189,8 @@
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0,0,0">
<Button Name="BookmarksBtn" Style="{StaticResource IconButton}" Content="&#xE734;" ToolTip="즐겨찾기" Margin="0,0,2,0" Click="ToggleBookmarks"/>
<Button Name="HistoryBtn" Style="{StaticResource IconButton}" Content="&#xE823;" ToolTip="방문 기록" Margin="0,0,2,0" Click="ToggleHistory"/>
<Button Name="TabSearchBtn" Style="{StaticResource IconButton}" Content="&#xE721;" ToolTip="탭 검색 (Ctrl+Shift+A)" Margin="0,0,2,0" Click="ToggleTabSearch"/>
<Button Name="DownloadsBtn" Style="{StaticResource IconButton}" Content="&#xE896;" ToolTip="다운로드 (Ctrl+J)" Margin="0,0,2,0" Click="ToggleDownloads"/>
<Button Style="{StaticResource IconButton}" Content="&#xE8B7;" ToolTip="저장 폴더 열기" Margin="0,0,2,0" Click="OpenFolder_Click"/>
<Button Name="LinkBtn" Style="{StaticResource IconButton}" Content="&#xE71B;" ToolTip="링크로 받기 (YouTube·Instagram·X)" Margin="0,0,2,0" Click="ToggleLink"/>
<Button x:Name="PrivateBtn" Style="{StaticResource IconButton}" Content="&#xE72E;" ToolTip="개인정보 보호 모드(InPrivate)" Margin="0,0,2,0" Click="TogglePrivate_Click"/>
@ -210,8 +215,32 @@
</DockPanel>
</Border>
<!-- ===== 북마크바 (T1-6, Ctrl+Shift+B 토글) ===== -->
<Border x:Name="BookmarkBar" Grid.Row="1" Background="{StaticResource PanelBg}"
BorderBrush="{StaticResource BorderSubtle}" BorderThickness="0,0,0,1" Padding="8,3"
Visibility="Collapsed">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<ItemsControl x:Name="BookmarkBarList" ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource FlatButton}" Click="BookmarkBar_Click"
Padding="10,4" Margin="2,1" ToolTip="{Binding Url}">
<TextBlock Text="{Binding Title}" TextTrimming="CharacterEllipsis"
MaxWidth="130" FontSize="12"/>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>
<!-- ===== 탭 스트립 (Phase A) ===== -->
<Border x:Name="TabStripRow" Grid.Row="1" Background="{StaticResource PanelBg}"
<Border x:Name="TabStripRow" Grid.Row="2" Background="{StaticResource PanelBg}"
BorderBrush="{StaticResource BorderSubtle}" BorderThickness="0,0,0,1" Padding="8,4,8,0">
<DockPanel>
<Button x:Name="NewTabBtn" DockPanel.Dock="Right" Style="{StaticResource IconButton}"
@ -271,7 +300,7 @@
</Border>
<!-- ===== 본문 ===== -->
<Grid Grid.Row="2">
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
@ -381,7 +410,7 @@
</Grid>
<!-- ===== 상태 표시줄 ===== -->
<Border x:Name="StatusBar" Grid.Row="3" Background="{StaticResource PanelBg}"
<Border x:Name="StatusBar" Grid.Row="4" Background="{StaticResource PanelBg}"
BorderBrush="{StaticResource BorderSubtle}" BorderThickness="0,1,0,0" Padding="16,5">
<TextBlock Name="StatusText" Foreground="{StaticResource TextMuted}" FontSize="11"
TextTrimming="CharacterEllipsis" Text="준비"/>
@ -473,6 +502,87 @@
</Border>
</Popup>
<!-- ===== 다운로드 플라이아웃 (T1-5) ===== -->
<Popup Name="DownloadsPopup" PlacementTarget="{Binding ElementName=DownloadsBtn}"
Placement="Bottom" HorizontalOffset="-10" VerticalOffset="6"
StaysOpen="False" AllowsTransparency="True" PopupAnimation="Fade">
<Border Background="{StaticResource CardBg}" BorderBrush="{StaticResource BorderBrush}"
BorderThickness="1" CornerRadius="12" Padding="10" Width="420" MaxHeight="460">
<StackPanel>
<DockPanel Margin="6,2,6,8">
<TextBlock Text="다운로드" Foreground="{StaticResource TextPrimary}" FontWeight="SemiBold" VerticalAlignment="Center"/>
<Button DockPanel.Dock="Right" Style="{StaticResource CardActionButton}" Content="완료 항목 지우기"
Click="DownloadsClear_Click" HorizontalAlignment="Right"/>
</DockPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="380">
<ItemsControl Name="DownloadsList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{StaticResource GlassBg}" BorderBrush="{StaticResource BorderSubtle}"
BorderThickness="1" CornerRadius="8" Padding="10" Margin="0,0,0,8">
<StackPanel>
<DockPanel>
<TextBlock DockPanel.Dock="Right" Text="{Binding SpeedText}" Foreground="{StaticResource TextMuted}"
FontSize="11" VerticalAlignment="Center" Margin="8,0,0,0"/>
<TextBlock Text="{Binding FileName}" Foreground="{StaticResource TextPrimary}"
FontSize="12.5" FontWeight="Medium" TextTrimming="CharacterEllipsis"/>
</DockPanel>
<ProgressBar Value="{Binding Percent}" Maximum="100" Height="6" Margin="0,7,0,6"
Style="{StaticResource AccentProgressBar}"/>
<DockPanel>
<TextBlock Text="{Binding State}" Foreground="{StaticResource TextSecondary}" FontSize="11" VerticalAlignment="Center"/>
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
<Button Style="{StaticResource CardActionButton}" Content="일시정지" Click="DlPause_Click" Margin="0,0,5,0"/>
<Button Style="{StaticResource CardActionButton}" Content="재개" Click="DlResume_Click" Margin="0,0,5,0"/>
<Button Style="{StaticResource CardActionButton}" Content="취소" Click="DlCancel_Click"/>
</StackPanel>
</DockPanel>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<TextBlock Text="페이지 내 파일 다운로드가 여기 표시됩니다" Foreground="{StaticResource TextMuted}"
FontSize="11" HorizontalAlignment="Center" Margin="0,4,0,0"
x:Name="DownloadsEmptyHint"/>
</StackPanel>
</Border>
</Popup>
<!-- ===== 탭 검색 팝업 (T2-8, Ctrl+Shift+A) ===== -->
<Popup Name="TabSearchPopup" PlacementTarget="{Binding ElementName=AddressBox}"
Placement="Center" StaysOpen="False" AllowsTransparency="True" PopupAnimation="Fade"
Width="520">
<Border Background="{StaticResource CardBg}" BorderBrush="{StaticResource BorderBrush}"
BorderThickness="1" CornerRadius="12" Padding="10">
<StackPanel>
<Border Background="{StaticResource GlassBg}" BorderBrush="{StaticResource BorderBrush}"
BorderThickness="1" CornerRadius="8" Margin="2,0,2,8">
<TextBox Name="TabSearchBox" Style="{StaticResource DarkTextBox}" BorderThickness="0"
Background="Transparent" Padding="12,9" FontSize="13"
TextChanged="TabSearchBox_TextChanged" PreviewKeyDown="TabSearchBox_PreviewKeyDown"/>
</Border>
<ListBox Name="TabSearchResults" Style="{StaticResource SuggestList}"
ItemContainerStyle="{StaticResource SuggestItem}" MaxHeight="320"
PreviewMouseLeftButtonUp="TabSearchResult_Click">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<DockPanel>
<TextBlock DockPanel.Dock="Right" Text="{Binding IsClosed, Converter={x:Static feat:BoolToClosedConverter.Instance}}"
Foreground="{StaticResource TextMuted}" FontSize="10.5" VerticalAlignment="Center"/>
<TextBlock Text="{Binding Title}" TextTrimming="CharacterEllipsis" FontSize="12.5" FontWeight="Medium"/>
</DockPanel>
<TextBlock Text="{Binding Url}" Foreground="{StaticResource TextMuted}" FontSize="10.5" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Border>
</Popup>
<!-- ===== 링크로 받기 플라이아웃 (YouTube/Instagram/X URL 붙여넣기) ===== -->
<Popup Name="LinkPopup" PlacementTarget="{Binding ElementName=LinkBtn}"
Placement="Bottom" HorizontalOffset="-10" VerticalOffset="6"