새 패키지 없이 회귀 없는 핸들러 제거/전환: - OnQualityChanged 제거 → QualityValueText.Text를 Options.Quality에 StringFormat 바인딩. - OnAiTaskChanged 제거 → AiTargetLangPanel.Visibility를 AiTaskCombo.SelectedIndex DataTrigger로. - OnTabClick 제거 → TabCommand(ToggleButton.Command + CommandParameter "Active"/"Past"). - OnConflictSegmentClick → SetConflictRule + ConflictRuleCommand(CommandParameter "Skip/Rename/Replace"). - OnCombineToggleChanged 제거 → CombineToggleCommand(CheckBox.Command, 토글 시 발화). - 검증: 빌드 0/0, 83 테스트 그린, publish 후 메인 창 크래시 없이 로드(언핸들드 로그 없음). - 잔여: 동적 포맷 콤보 SelectionChanged, 드래그앤드롭, 행 미리보기 클릭(IsInsideButton 가드), 복합 ProcessQueue 버튼.
815 lines
59 KiB
XML
815 lines
59 KiB
XML
<ui:FluentWindow x:Class="Everything2Everything.App.Views.MainWindow"
|
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
|
Title="FormatShift Utility"
|
|
Icon="pack://application:,,,/Assets/app-icon.png"
|
|
Width="1280" Height="960"
|
|
MinWidth="1080" MinHeight="640"
|
|
ExtendsContentIntoTitleBar="True"
|
|
WindowBackdropType="None"
|
|
WindowCornerPreference="Round"
|
|
WindowStartupLocation="CenterScreen"
|
|
AllowDrop="True"
|
|
Drop="OnFilesDropped"
|
|
DragOver="OnDragOver"
|
|
DragLeave="OnDragLeave"
|
|
TextOptions.TextFormattingMode="Display"
|
|
UseLayoutRounding="True">
|
|
<Window.Resources>
|
|
<ResourceDictionary>
|
|
<ResourceDictionary.MergedDictionaries>
|
|
<ResourceDictionary Source="FormatShiftTheme.xaml"/>
|
|
</ResourceDictionary.MergedDictionaries>
|
|
</ResourceDictionary>
|
|
</Window.Resources>
|
|
|
|
<Window.InputBindings>
|
|
<KeyBinding Key="O" Modifiers="Ctrl" Command="{Binding AddFilesCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<KeyBinding Key="Enter" Modifiers="Ctrl" Command="{Binding ProcessQueueCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<KeyBinding Key="Escape" Command="{Binding CloseCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<KeyBinding Key="F5" Command="{Binding RefreshCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
</Window.InputBindings>
|
|
|
|
<Grid Background="{StaticResource FsBgBase}">
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="32"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- Title bar (window controls only) -->
|
|
<ui:TitleBar Grid.Row="0" Title="" ShowMaximize="True" ShowMinimize="True"/>
|
|
|
|
<!-- App body -->
|
|
<Grid Grid.Row="1">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="320"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- ============== SIDEBAR ============== -->
|
|
<Border Grid.Column="0"
|
|
Background="{StaticResource FsBgPanel}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="0,0,1,0">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="56"/>
|
|
<RowDefinition Height="*"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- Sidebar header -->
|
|
<Border Grid.Row="0" BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="0,0,0,1" Padding="24,0">
|
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
|
<Image Width="22" Height="22"
|
|
RenderOptions.BitmapScalingMode="HighQuality"
|
|
Source="pack://application:,,,/Assets/logo-mark.png"/>
|
|
<TextBlock Margin="9,0,0,0" FontSize="14" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextPrimary}"
|
|
FontFamily="{StaticResource FsFontSans}">
|
|
FormatShift
|
|
<Run Foreground="{StaticResource FsTextTertiary}" FontWeight="Medium"
|
|
Text=" Utility"/>
|
|
</TextBlock>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- Sidebar content -->
|
|
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Padding="24,24,24,24">
|
|
<StackPanel>
|
|
<!-- Target Format -->
|
|
<StackPanel Margin="0,0,0,32">
|
|
<TextBlock Text="TARGET FORMAT" Style="{StaticResource FsLabelStyle}"/>
|
|
<Grid Margin="0,8,0,0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Border x:Name="OutputFormatBadge" Grid.Column="0"
|
|
Width="36" Height="28" CornerRadius="4"
|
|
Background="{StaticResource FsFmtJpg}"
|
|
VerticalAlignment="Center">
|
|
<TextBlock x:Name="OutputFormatBadgeText"
|
|
Text="JPG" Foreground="White" FontSize="9"
|
|
FontWeight="SemiBold"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
</Border>
|
|
<ComboBox x:Name="OutputFormatCombo" Grid.Column="1"
|
|
Margin="8,0,0,0" VerticalAlignment="Center"
|
|
SelectionChanged="OnOutputFormatChanged"/>
|
|
</Grid>
|
|
<TextBlock x:Name="OutputFormatHint" Margin="0,6,0,0"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
Text="모든 입력에서 변환 가능한 형식이 표시됩니다"/>
|
|
<CheckBox x:Name="CombineToSingleCheck"
|
|
Margin="0,12,0,0"
|
|
Content="단일 파일로 결합 (큐 전체 → 한 파일)"
|
|
IsEnabled="False"
|
|
Command="{Binding CombineToggleCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<TextBlock x:Name="CombineHint" Margin="0,4,0,0"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
Text="PDF/TIFF/GIF 출력에 한해 큐의 이미지들을 한 파일로 결합합니다"/>
|
|
</StackPanel>
|
|
|
|
<!-- Encoding Quality -->
|
|
<StackPanel x:Name="QualityPanel" Margin="0,0,0,32">
|
|
<Grid>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<TextBlock x:Name="QualityLabelText" Text="ENCODING QUALITY" Style="{StaticResource FsLabelStyle}"/>
|
|
<Border Grid.Column="1" CornerRadius="4"
|
|
Background="{StaticResource FsBgInput}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="1" Padding="6,2">
|
|
<TextBlock x:Name="QualityValueText"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="12"
|
|
Foreground="{StaticResource FsAccentBlue}"
|
|
Text="{Binding Options.Quality, RelativeSource={RelativeSource AncestorType=Window}, StringFormat={}{0}%}"/>
|
|
</Border>
|
|
</Grid>
|
|
<Slider x:Name="QualitySlider" Margin="0,12,0,0"
|
|
Style="{StaticResource FsSliderStyle}"
|
|
Minimum="1" Maximum="100"
|
|
Value="{Binding Options.Quality, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"/>
|
|
<Grid Margin="0,4,0,0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<TextBlock Text="Smaller File" Style="{StaticResource FsCaptionStyle}"/>
|
|
<TextBlock Grid.Column="1" Text="Higher Quality" Style="{StaticResource FsCaptionStyle}"/>
|
|
</Grid>
|
|
</StackPanel>
|
|
|
|
<!-- Output Destination -->
|
|
<StackPanel Margin="0,0,0,32">
|
|
<TextBlock Text="OUTPUT DESTINATION" Style="{StaticResource FsLabelStyle}"/>
|
|
<Grid Margin="0,8,0,0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<TextBox x:Name="OutputPathTextBox"
|
|
Style="{StaticResource FsPathInputStyle}"
|
|
Text="{Binding Options.CustomOutputDirectory, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
|
ToolTip="비워두면 원본 폴더 옆 서브폴더에 저장"/>
|
|
<Button Grid.Column="1" Margin="8,0,0,0" Width="36"
|
|
Content="…" Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding PickOutputFolderCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
</Grid>
|
|
<TextBlock x:Name="OutputDestHint" Margin="0,6,0,0"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
Text="비워두면 원본 옆 _jpg 폴더에 저장됩니다"/>
|
|
</StackPanel>
|
|
|
|
<!-- File Conflict Rule -->
|
|
<StackPanel Margin="0,0,0,32">
|
|
<TextBlock Text="FILE CONFLICT RULE" Style="{StaticResource FsLabelStyle}"/>
|
|
<Border Margin="0,8,0,0"
|
|
Background="{StaticResource FsBgInput}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="1" CornerRadius="6" Padding="2">
|
|
<UniformGrid Rows="1" Columns="3">
|
|
<ToggleButton x:Name="ConflictSkipBtn" Content="Skip"
|
|
Style="{StaticResource FsSegmentStyle}"
|
|
Command="{Binding ConflictRuleCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
CommandParameter="Skip"/>
|
|
<ToggleButton x:Name="ConflictRenameBtn" Content="Rename"
|
|
Style="{StaticResource FsSegmentStyle}"
|
|
IsChecked="True"
|
|
Command="{Binding ConflictRuleCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
CommandParameter="Rename"/>
|
|
<ToggleButton x:Name="ConflictReplaceBtn" Content="Replace"
|
|
Style="{StaticResource FsSegmentStyle}"
|
|
Command="{Binding ConflictRuleCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
CommandParameter="Replace"/>
|
|
</UniformGrid>
|
|
</Border>
|
|
</StackPanel>
|
|
|
|
<!-- AI Task -->
|
|
<StackPanel x:Name="AiTaskPanel" Margin="0,0,0,32">
|
|
<StackPanel Orientation="Horizontal">
|
|
<Image Width="15" Height="15" VerticalAlignment="Center" Margin="0,0,6,0"
|
|
RenderOptions.BitmapScalingMode="HighQuality"
|
|
Source="pack://application:,,,/Assets/glyph-ai.png"/>
|
|
<TextBlock Text="AI 작업" Style="{StaticResource FsLabelStyle}" VerticalAlignment="Center"/>
|
|
</StackPanel>
|
|
<ComboBox x:Name="AiTaskCombo" Margin="0,8,0,0"
|
|
SelectedIndex="0">
|
|
<ComboBoxItem Content="요약"/>
|
|
<ComboBoxItem Content="번역"/>
|
|
<ComboBoxItem Content="교정"/>
|
|
</ComboBox>
|
|
<TextBlock x:Name="AiTaskHint" Margin="0,6,0,0"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
Text="텍스트(txt·md·docx) 출력 시 LLM이 적용합니다"/>
|
|
<StackPanel x:Name="AiTargetLangPanel" Margin="0,10,0,0">
|
|
<StackPanel.Style>
|
|
<Style TargetType="StackPanel">
|
|
<Setter Property="Visibility" Value="Collapsed"/>
|
|
<Style.Triggers>
|
|
<!-- 번역(인덱스 1)일 때만 대상 언어 입력 표시 -->
|
|
<DataTrigger Binding="{Binding SelectedIndex, ElementName=AiTaskCombo}" Value="1">
|
|
<Setter Property="Visibility" Value="Visible"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</StackPanel.Style>
|
|
<TextBlock Text="대상 언어" Style="{StaticResource FsCaptionStyle}"
|
|
Margin="0,0,0,4"/>
|
|
<TextBox x:Name="AiTargetLangBox"
|
|
Style="{StaticResource FsPathInputStyle}"
|
|
Text="영어"
|
|
ToolTip="번역 대상 언어 (예: 영어)"/>
|
|
</StackPanel>
|
|
</StackPanel>
|
|
|
|
<!-- Stats Box -->
|
|
<Border Background="{StaticResource FsBgInput}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="1" CornerRadius="6" Padding="12">
|
|
<Grid>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
<StackPanel>
|
|
<TextBlock Text="PROCESSED TODAY"
|
|
FontFamily="{StaticResource FsFontSans}"
|
|
FontSize="10" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextSecondary}"/>
|
|
<TextBlock x:Name="ProcessedTodayText"
|
|
FontFamily="{StaticResource FsFontMono}"
|
|
FontSize="14"
|
|
Foreground="{StaticResource FsTextPrimary}"
|
|
Text="0" Margin="0,4,0,0"/>
|
|
</StackPanel>
|
|
<StackPanel Grid.Column="1">
|
|
<TextBlock Text="EST. SPACE SAVED"
|
|
FontFamily="{StaticResource FsFontSans}"
|
|
FontSize="10" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextSecondary}"/>
|
|
<TextBlock x:Name="SpaceSavedText"
|
|
FontFamily="{StaticResource FsFontMono}"
|
|
FontSize="14"
|
|
Foreground="{StaticResource FsAccentGreen}"
|
|
Text="0 B" Margin="0,4,0,0"/>
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<!-- Sidebar footer -->
|
|
<Border Grid.Row="2" BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="0,1,0,0" Padding="24">
|
|
<StackPanel>
|
|
<TextBlock x:Name="CapabilityStatusText" Margin="0,0,0,12"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
TextWrapping="Wrap" Visibility="Collapsed"/>
|
|
|
|
<!-- Conversion progress (shown only while processing) -->
|
|
<StackPanel x:Name="ProcessingProgressPanel" Margin="0,0,0,12"
|
|
Visibility="Collapsed">
|
|
<Grid Margin="0,0,0,6">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<TextBlock x:Name="ProcessingFileLabel"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
Foreground="{StaticResource FsTextPrimary}"
|
|
TextTrimming="CharacterEllipsis"
|
|
Text="처리 중…"/>
|
|
<TextBlock x:Name="ProcessingCountLabel" Grid.Column="1"
|
|
Margin="8,0,0,0"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="11"
|
|
Foreground="{StaticResource FsAccentBlue}"
|
|
Text="0 / 0"/>
|
|
</Grid>
|
|
<ProgressBar x:Name="ProcessingProgressBar"
|
|
Height="6" Minimum="0" Maximum="100" Value="0"/>
|
|
<Grid Margin="0,4,0,0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<TextBlock x:Name="ProcessingPercentLabel"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="10"
|
|
Foreground="{StaticResource FsTextSecondary}"
|
|
VerticalAlignment="Center"
|
|
Text="0%"/>
|
|
<Button x:Name="CancelProcessingButton" Grid.Column="1"
|
|
Content="취소" Padding="10,2"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding CancelProcessingCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
</Grid>
|
|
</StackPanel>
|
|
|
|
<Button x:Name="ProcessQueueButton"
|
|
Content="Idle — drop files to begin"
|
|
Style="{StaticResource FsPrimaryButtonStyle}"
|
|
IsEnabled="False"
|
|
Click="OnProcessQueueClick"/>
|
|
</StackPanel>
|
|
</Border>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- ============== MAIN ============== -->
|
|
<Grid Grid.Column="1" Background="{StaticResource FsBgBase}">
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="56"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- Nav bar -->
|
|
<Border Grid.Row="0" BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="0,0,0,1" Padding="24,0">
|
|
<Grid VerticalAlignment="Center">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- Tabs -->
|
|
<Border HorizontalAlignment="Left"
|
|
Background="{StaticResource FsBgPanel}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="1" CornerRadius="20" Padding="4">
|
|
<StackPanel Orientation="Horizontal">
|
|
<ToggleButton x:Name="TabActiveBtn"
|
|
Style="{StaticResource FsTabPillStyle}"
|
|
Command="{Binding TabCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
CommandParameter="Active">
|
|
<StackPanel Orientation="Horizontal">
|
|
<TextBlock Text="Active Queue" VerticalAlignment="Center"/>
|
|
<Border Margin="8,0,0,0" Style="{StaticResource FsTabBadgeStyle}">
|
|
<TextBlock x:Name="TabActiveBadge" Text="0"
|
|
FontSize="10" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextTertiary}"/>
|
|
</Border>
|
|
</StackPanel>
|
|
</ToggleButton>
|
|
<ToggleButton x:Name="TabPastBtn" Margin="8,0,0,0"
|
|
IsChecked="True"
|
|
Style="{StaticResource FsTabPillStyle}"
|
|
Command="{Binding TabCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
CommandParameter="Past">
|
|
<StackPanel Orientation="Horizontal">
|
|
<TextBlock Text="Past Results" VerticalAlignment="Center"/>
|
|
<Border Margin="8,0,0,0" Style="{StaticResource FsTabBadgeStyle}">
|
|
<TextBlock x:Name="TabPastBadge" Text="0"
|
|
FontSize="10" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextTertiary}"/>
|
|
</Border>
|
|
</StackPanel>
|
|
</ToggleButton>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- Actions -->
|
|
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
|
<Button Content="⚙ 설정" Margin="0,0,8,0"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding SettingsCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<Button Content="Register Menu" Margin="0,0,8,0"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding RegisterCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<Button Content="Diagnose" Margin="0,0,8,0"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding DiagnoseCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<Button Content="Export Log" Margin="0,0,8,0"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding ExportLogCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<Button x:Name="ClearAllButton" Content="Clear All"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding ClearAllCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- View content (좌측: 탭 컨텐츠 / 우측: Preview 컬럼) -->
|
|
<Grid Grid.Row="1">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*" MinWidth="360"/>
|
|
<ColumnDefinition Width="380"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- 좌측: Active Queue OR Past Results -->
|
|
<Grid Grid.Column="0">
|
|
<!-- Active Queue view -->
|
|
<Grid x:Name="ActiveQueueView" Visibility="Collapsed">
|
|
<Grid x:Name="DropZoneEmpty">
|
|
<Border Background="{StaticResource FsBgBase}" Padding="32">
|
|
<!-- 점선 드롭존: 절제된 dashed 보더 + 중앙 정렬 안내 -->
|
|
<Grid MaxWidth="440"
|
|
HorizontalAlignment="Center"
|
|
VerticalAlignment="Center">
|
|
<!-- 점선 테두리(드롭존 느낌) -->
|
|
<Rectangle RadiusX="10" RadiusY="10"
|
|
Stroke="{StaticResource FsBorderHairline}"
|
|
StrokeThickness="1.25"
|
|
StrokeDashArray="5 4"
|
|
Fill="#04FFFFFF"/>
|
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
|
|
Margin="48,52">
|
|
<Image Width="128" Height="128"
|
|
HorizontalAlignment="Center"
|
|
RenderOptions.BitmapScalingMode="HighQuality"
|
|
Source="pack://application:,,,/Assets/illus-empty.png"/>
|
|
<TextBlock Margin="0,16,0,0" FontSize="16" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextPrimary}"
|
|
HorizontalAlignment="Center"
|
|
Text="Drop files anywhere to queue"/>
|
|
<TextBlock Margin="0,6,0,0" Style="{StaticResource FsCaptionStyle}"
|
|
HorizontalAlignment="Center"
|
|
TextAlignment="Center"
|
|
Text="이미지 · 문서 · 데이터 · 영상 · 오디오 등 무엇이든"/>
|
|
<Button Margin="0,22,0,0"
|
|
HorizontalAlignment="Center"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Padding="18,8"
|
|
Content="Browse…"
|
|
Command="{Binding AddFilesCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
|
<TextBlock Margin="0,12,0,0" Style="{StaticResource FsCaptionStyle}"
|
|
HorizontalAlignment="Center"
|
|
Foreground="{StaticResource FsTextTertiary}"
|
|
Text="또는 Ctrl+O"/>
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
</Grid>
|
|
<ScrollViewer x:Name="ActiveQueueScroll" VerticalScrollBarVisibility="Auto"
|
|
Padding="24" Visibility="Collapsed">
|
|
<ItemsControl x:Name="ActiveQueueList"
|
|
ItemsSource="{Binding ActiveQueue, RelativeSource={RelativeSource AncestorType=Window}}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate>
|
|
<!-- row hover: FsListRowStyle 느낌(투명→surface hover, hairline 보더) + 좌측 형식색 accent bar -->
|
|
<Border x:Name="QueueRow" Margin="0,0,0,8" Padding="0" CornerRadius="6"
|
|
Background="{StaticResource FsBgPanel}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="1"
|
|
Cursor="Hand"
|
|
PreviewMouseLeftButtonUp="OnQueueRowClick"
|
|
Tag="{Binding}">
|
|
<Grid>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="2"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
<!-- 좌측 2px 세로 accent bar: 해당 파일 형식색 -->
|
|
<Border Grid.Column="0"
|
|
Width="2"
|
|
Background="{Binding FormatBrush}"
|
|
CornerRadius="6,0,0,6"/>
|
|
<Grid Grid.Column="1" Margin="12,10">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="40"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="100"/>
|
|
<ColumnDefinition Width="120"/>
|
|
<ColumnDefinition Width="40"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Image Width="34" Height="34" VerticalAlignment="Center"
|
|
RenderOptions.BitmapScalingMode="HighQuality"
|
|
Source="{Binding GlyphSource}"/>
|
|
<StackPanel Grid.Column="1" Margin="16,0,0,0"
|
|
VerticalAlignment="Center">
|
|
<TextBlock Text="{Binding FileName}"
|
|
Style="{StaticResource FsBodyStyle}"
|
|
FontWeight="Medium"
|
|
TextTrimming="CharacterEllipsis"/>
|
|
<TextBlock Text="{Binding MetaLine}"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
Margin="0,2,0,0"/>
|
|
<ProgressBar Height="3" Margin="0,4,0,0"
|
|
Minimum="0" Maximum="100"
|
|
Value="{Binding ProgressValue, Mode=OneWay}"
|
|
Visibility="{Binding ProgressVisibility, Mode=OneWay}"/>
|
|
</StackPanel>
|
|
<TextBlock Grid.Column="2" Text="{Binding SizeText}"
|
|
Style="{StaticResource FsMonoStyle}"
|
|
HorizontalAlignment="Right"
|
|
VerticalAlignment="Center"/>
|
|
<TextBlock Grid.Column="3" Text="{Binding StateText}"
|
|
FontFamily="{StaticResource FsFontMono}"
|
|
FontSize="12"
|
|
Foreground="{Binding StateBrush}"
|
|
VerticalAlignment="Center"/>
|
|
<Button Grid.Column="4"
|
|
Style="{StaticResource FsIconButtonStyle}"
|
|
Width="28" Height="28"
|
|
VerticalAlignment="Center"
|
|
HorizontalAlignment="Right"
|
|
ToolTip="큐에서 제거"
|
|
Command="{Binding RemoveQueueItemCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
CommandParameter="{Binding}">
|
|
<Path Width="13" Height="13" Stretch="Uniform"
|
|
Stroke="{StaticResource FsTextTertiary}"
|
|
StrokeThickness="2"
|
|
Data="M18,6 L6,18 M6,6 L18,18"/>
|
|
</Button>
|
|
</Grid>
|
|
</Grid>
|
|
</Border>
|
|
<DataTemplate.Triggers>
|
|
<!-- row hover: 배경 살짝 밝게 + hairline 보더 -->
|
|
<Trigger SourceName="QueueRow" Property="IsMouseOver" Value="True">
|
|
<Setter TargetName="QueueRow" Property="Background"
|
|
Value="{StaticResource FsBgSurfaceHover}"/>
|
|
<Setter TargetName="QueueRow" Property="BorderBrush"
|
|
Value="{StaticResource FsBorderHairline}"/>
|
|
</Trigger>
|
|
</DataTemplate.Triggers>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</ScrollViewer>
|
|
</Grid>
|
|
|
|
<!-- Past Results view (default) -->
|
|
<ScrollViewer x:Name="PastResultsView" VerticalScrollBarVisibility="Auto"
|
|
Padding="24">
|
|
<ItemsControl x:Name="PastResultsList"
|
|
ItemsSource="{Binding PastResults, RelativeSource={RelativeSource AncestorType=Window}}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate>
|
|
<StackPanel Margin="0,0,0,40">
|
|
<!-- Date header -->
|
|
<Grid Margin="0,0,0,12">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<TextBlock Text="{Binding DateTitle}"
|
|
FontFamily="{StaticResource FsFontSans}"
|
|
FontSize="14" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextPrimary}"/>
|
|
<Border Grid.Column="1" CornerRadius="20" Padding="10,4"
|
|
Background="#10B98122">
|
|
<TextBlock Text="{Binding SessionSavingsText}"
|
|
FontFamily="{StaticResource FsFontMono}"
|
|
FontSize="12"
|
|
Foreground="{StaticResource FsAccentGreen}"/>
|
|
</Border>
|
|
</Grid>
|
|
<Border Height="1" Background="{StaticResource FsBorderSubtle}"
|
|
Margin="0,0,0,12"/>
|
|
|
|
<!-- Rows -->
|
|
<ItemsControl ItemsSource="{Binding Entries}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate>
|
|
<Border BorderBrush="#0DFFFFFF"
|
|
BorderThickness="0,0,0,1" Padding="0,12"
|
|
Cursor="Hand"
|
|
Background="Transparent"
|
|
PreviewMouseLeftButtonUp="OnPastRowClick"
|
|
Tag="{Binding}">
|
|
<Grid>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="40"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="100"/>
|
|
<ColumnDefinition Width="100"/>
|
|
<ColumnDefinition Width="120"/>
|
|
<ColumnDefinition Width="40"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<Image Width="34" Height="34" VerticalAlignment="Center"
|
|
RenderOptions.BitmapScalingMode="HighQuality"
|
|
Source="{Binding GlyphSource}"/>
|
|
|
|
<StackPanel Grid.Column="1" Margin="16,0,0,0"
|
|
VerticalAlignment="Center">
|
|
<TextBlock Text="{Binding FileName}"
|
|
Style="{StaticResource FsBodyStyle}"
|
|
FontWeight="Medium"
|
|
TextTrimming="CharacterEllipsis"/>
|
|
<TextBlock Text="{Binding MetaLine}"
|
|
Style="{StaticResource FsCaptionStyle}"
|
|
Margin="0,2,0,0"/>
|
|
</StackPanel>
|
|
|
|
<TextBlock Grid.Column="2"
|
|
Text="{Binding SizeText}"
|
|
Style="{StaticResource FsMonoStyle}"
|
|
HorizontalAlignment="Right"
|
|
VerticalAlignment="Center"/>
|
|
|
|
<TextBlock Grid.Column="3"
|
|
Text="{Binding SavingsText}"
|
|
FontFamily="{StaticResource FsFontMono}"
|
|
FontSize="12"
|
|
Foreground="{StaticResource FsAccentGreen}"
|
|
VerticalAlignment="Center"/>
|
|
|
|
<StackPanel Grid.Column="4" Orientation="Horizontal"
|
|
VerticalAlignment="Center">
|
|
<Path Width="12" Height="12" Stretch="Uniform"
|
|
Stroke="{StaticResource FsAccentGreen}"
|
|
StrokeThickness="3"
|
|
Data="M20,6 L9,17 L4,12"/>
|
|
<TextBlock Text="Success" Margin="6,0,0,0"
|
|
FontSize="11" FontWeight="Medium"
|
|
Foreground="{StaticResource FsAccentGreen}"/>
|
|
</StackPanel>
|
|
|
|
<Button Grid.Column="5"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Background="Transparent"
|
|
BorderThickness="0"
|
|
Padding="6"
|
|
Command="{Binding OpenFolderCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
CommandParameter="{Binding RevealPath}"
|
|
ToolTip="출력 파일이 있는 폴더 열기">
|
|
<Path Width="14" Height="14" Stretch="Uniform"
|
|
Stroke="{StaticResource FsTextTertiary}"
|
|
StrokeThickness="2"
|
|
Data="M22,19 C22,20.1 21.1,21 20,21 L4,21 C2.9,21 2,20.1 2,19 L2,5 C2,3.9 2.9,3 4,3 L9,3 L11,6 L20,6 C21.1,6 22,6.9 22,8 Z"/>
|
|
</Button>
|
|
</Grid>
|
|
</Border>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</StackPanel>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</ScrollViewer>
|
|
|
|
</Grid>
|
|
<!-- /좌측 컬럼 끝 -->
|
|
|
|
<!-- 우측: Preview 컬럼 (항상 보임) -->
|
|
<Border Grid.Column="1"
|
|
Background="{StaticResource FsBgPanel}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="1,0,0,0">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- 헤더 -->
|
|
<Border Grid.Row="0" Padding="20,16,20,12"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="0,0,0,1">
|
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
|
<Path Width="14" Height="14" Stretch="Uniform"
|
|
Stroke="{StaticResource FsTextSecondary}" StrokeThickness="2"
|
|
Data="M1,12 C1,12 5,4 12,4 C19,4 23,12 23,12 C23,12 19,20 12,20 C5,20 1,12 1,12 Z M12,9 A3,3 0 1,1 12,15 A3,3 0 1,1 12,9 Z"/>
|
|
<TextBlock Text="PREVIEW" Margin="8,0,0,0"
|
|
Style="{StaticResource FsLabelStyle}"
|
|
VerticalAlignment="Center"/>
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- 이미지 영역 -->
|
|
<Grid Grid.Row="1" Margin="20,16,20,16" x:Name="PreviewImageArea">
|
|
<Border Background="{StaticResource FsBgInput}"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="1" CornerRadius="6">
|
|
<Grid>
|
|
<!-- Empty state -->
|
|
<StackPanel x:Name="PreviewEmpty" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20">
|
|
<Path Width="36" Height="36" Stretch="Uniform"
|
|
Stroke="{StaticResource FsTextTertiary}" StrokeThickness="1.5"
|
|
Data="M1,12 C1,12 5,4 12,4 C19,4 23,12 23,12 C23,12 19,20 12,20 C5,20 1,12 1,12 Z M12,9 A3,3 0 1,1 12,15 A3,3 0 1,1 12,9 Z"/>
|
|
<TextBlock Margin="0,12,0,0" FontSize="13" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextSecondary}"
|
|
HorizontalAlignment="Center"
|
|
Text="No selection"/>
|
|
<TextBlock Margin="0,4,0,0" Style="{StaticResource FsCaptionStyle}"
|
|
HorizontalAlignment="Center" TextAlignment="Center"
|
|
TextWrapping="Wrap" MaxWidth="240"
|
|
Text="Active Queue 항목을 클릭하면 여기에 미리보기가 표시됩니다."/>
|
|
</StackPanel>
|
|
|
|
<!-- Loading -->
|
|
<StackPanel x:Name="PreviewLoading" Visibility="Collapsed"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center">
|
|
<ProgressBar IsIndeterminate="True" Width="180" Height="3"
|
|
Foreground="{StaticResource FsAccentBlue}"
|
|
Background="{StaticResource FsBgSurface}"/>
|
|
<TextBlock Margin="0,12,0,0" Style="{StaticResource FsCaptionStyle}"
|
|
HorizontalAlignment="Center"
|
|
Text="미리보기 생성 중…"/>
|
|
</StackPanel>
|
|
|
|
<!-- Image -->
|
|
<Image x:Name="PreviewImage" Stretch="Uniform" Margin="16"
|
|
Visibility="Collapsed"/>
|
|
|
|
<!-- Reason -->
|
|
<StackPanel x:Name="PreviewReason" Visibility="Collapsed"
|
|
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20">
|
|
<Image x:Name="PreviewGlyph" Width="84" Height="84"
|
|
HorizontalAlignment="Center" Visibility="Collapsed"
|
|
RenderOptions.BitmapScalingMode="HighQuality"/>
|
|
<Path x:Name="PreviewWarnIcon" Width="32" Height="32" Stretch="Uniform"
|
|
Stroke="{StaticResource FsAccentAmber}" StrokeThickness="1.5"
|
|
Data="M12,2 L22,20 L2,20 Z M12,9 L12,14 M12,17 L12,17.01"/>
|
|
<TextBlock x:Name="PreviewReasonText" Margin="0,12,0,0"
|
|
Style="{StaticResource FsBodyStyle}"
|
|
FontSize="12"
|
|
HorizontalAlignment="Center" TextAlignment="Center"
|
|
TextWrapping="Wrap" MaxWidth="280"/>
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
</Grid>
|
|
|
|
<!-- 메타 -->
|
|
<Border Grid.Row="2" Padding="20,12,20,20"
|
|
BorderBrush="{StaticResource FsBorderSubtle}"
|
|
BorderThickness="0,1,0,0">
|
|
<StackPanel>
|
|
<TextBlock x:Name="PreviewFileName"
|
|
Style="{StaticResource FsBodyStyle}"
|
|
FontWeight="SemiBold" TextWrapping="NoWrap"
|
|
TextTrimming="CharacterEllipsis"
|
|
Text="—"/>
|
|
<TextBlock x:Name="PreviewFilePath" Margin="0,4,0,0"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="11"
|
|
Foreground="{StaticResource FsTextTertiary}"
|
|
TextTrimming="CharacterEllipsis" MaxHeight="32"/>
|
|
|
|
<Border Margin="0,12,0,12" Height="1"
|
|
Background="{StaticResource FsBorderSubtle}"/>
|
|
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<TextBlock Grid.Row="0" Grid.Column="0" Text="Format"
|
|
Style="{StaticResource FsCaptionStyle}" Margin="0,0,0,4"/>
|
|
<TextBlock x:Name="PreviewFormatText" Grid.Row="0" Grid.Column="1"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="12"
|
|
Foreground="{StaticResource FsTextPrimary}" Margin="0,0,0,4"/>
|
|
|
|
<TextBlock Grid.Row="1" Grid.Column="0" Text="Size"
|
|
Style="{StaticResource FsCaptionStyle}" Margin="0,0,0,4"/>
|
|
<TextBlock x:Name="PreviewSizeText" Grid.Row="1" Grid.Column="1"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="12"
|
|
Foreground="{StaticResource FsTextPrimary}" Margin="0,0,0,4"/>
|
|
|
|
<TextBlock Grid.Row="2" Grid.Column="0" Text="Dimensions"
|
|
Style="{StaticResource FsCaptionStyle}" Margin="0,0,0,4"/>
|
|
<TextBlock x:Name="PreviewDimText" Grid.Row="2" Grid.Column="1"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="12"
|
|
Foreground="{StaticResource FsTextPrimary}" Text="—"
|
|
Margin="0,0,0,4"/>
|
|
|
|
<TextBlock Grid.Row="3" Grid.Column="0" Text="Pages"
|
|
Style="{StaticResource FsCaptionStyle}"/>
|
|
<TextBlock x:Name="PreviewPageText" Grid.Row="3" Grid.Column="1"
|
|
FontFamily="{StaticResource FsFontMono}" FontSize="12"
|
|
Foreground="{StaticResource FsTextPrimary}" Text="—"/>
|
|
</Grid>
|
|
|
|
<Button Content="Open in Explorer" Margin="0,16,0,0"
|
|
Style="{StaticResource FsSecondaryButtonStyle}"
|
|
Command="{Binding PreviewOpenFolderCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
|
HorizontalAlignment="Stretch"/>
|
|
</StackPanel>
|
|
</Border>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- Drop hint overlay (전체 덮음) -->
|
|
<Border x:Name="DropHintOverlay" Visibility="Collapsed" Grid.ColumnSpan="2"
|
|
Background="#CC090A0C" IsHitTestVisible="False">
|
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
|
<Path Width="64" Height="64" Stretch="Uniform"
|
|
Stroke="{StaticResource FsAccentBlue}" StrokeThickness="2"
|
|
Data="M21,15 L21,19 C21,20.1 20.1,21 19,21 L5,21 C3.9,21 3,20.1 3,19 L3,15 M7,10 L12,15 L17,10 M12,15 L12,3"/>
|
|
<TextBlock Text="Drop to add to queue" Margin="0,16,0,0"
|
|
FontSize="18" FontWeight="SemiBold"
|
|
Foreground="{StaticResource FsTextPrimary}"
|
|
HorizontalAlignment="Center"/>
|
|
</StackPanel>
|
|
</Border>
|
|
</Grid>
|
|
</Grid>
|
|
</Grid>
|
|
</Grid>
|
|
</ui:FluentWindow>
|