refactor(P5b-6): 옵션/탭/충돌/결합 핸들러 5개 → 선언적 바인딩·커맨드 (의존성 0)
새 패키지 없이 회귀 없는 핸들러 제거/전환: - 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 버튼.
This commit is contained in:
parent
a05bbcf709
commit
ccba168f9a
2 changed files with 38 additions and 50 deletions
|
|
@ -107,8 +107,7 @@
|
||||||
Margin="0,12,0,0"
|
Margin="0,12,0,0"
|
||||||
Content="단일 파일로 결합 (큐 전체 → 한 파일)"
|
Content="단일 파일로 결합 (큐 전체 → 한 파일)"
|
||||||
IsEnabled="False"
|
IsEnabled="False"
|
||||||
Checked="OnCombineToggleChanged"
|
Command="{Binding CombineToggleCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
||||||
Unchecked="OnCombineToggleChanged"/>
|
|
||||||
<TextBlock x:Name="CombineHint" Margin="0,4,0,0"
|
<TextBlock x:Name="CombineHint" Margin="0,4,0,0"
|
||||||
Style="{StaticResource FsCaptionStyle}"
|
Style="{StaticResource FsCaptionStyle}"
|
||||||
Text="PDF/TIFF/GIF 출력에 한해 큐의 이미지들을 한 파일로 결합합니다"/>
|
Text="PDF/TIFF/GIF 출력에 한해 큐의 이미지들을 한 파일로 결합합니다"/>
|
||||||
|
|
@ -129,14 +128,13 @@
|
||||||
<TextBlock x:Name="QualityValueText"
|
<TextBlock x:Name="QualityValueText"
|
||||||
FontFamily="{StaticResource FsFontMono}" FontSize="12"
|
FontFamily="{StaticResource FsFontMono}" FontSize="12"
|
||||||
Foreground="{StaticResource FsAccentBlue}"
|
Foreground="{StaticResource FsAccentBlue}"
|
||||||
Text="85%"/>
|
Text="{Binding Options.Quality, RelativeSource={RelativeSource AncestorType=Window}, StringFormat={}{0}%}"/>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Slider x:Name="QualitySlider" Margin="0,12,0,0"
|
<Slider x:Name="QualitySlider" Margin="0,12,0,0"
|
||||||
Style="{StaticResource FsSliderStyle}"
|
Style="{StaticResource FsSliderStyle}"
|
||||||
Minimum="1" Maximum="100"
|
Minimum="1" Maximum="100"
|
||||||
Value="{Binding Options.Quality, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"
|
Value="{Binding Options.Quality, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"/>
|
||||||
ValueChanged="OnQualityChanged"/>
|
|
||||||
<Grid Margin="0,4,0,0">
|
<Grid Margin="0,4,0,0">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
|
|
@ -178,17 +176,17 @@
|
||||||
<UniformGrid Rows="1" Columns="3">
|
<UniformGrid Rows="1" Columns="3">
|
||||||
<ToggleButton x:Name="ConflictSkipBtn" Content="Skip"
|
<ToggleButton x:Name="ConflictSkipBtn" Content="Skip"
|
||||||
Style="{StaticResource FsSegmentStyle}"
|
Style="{StaticResource FsSegmentStyle}"
|
||||||
Click="OnConflictSegmentClick"
|
Command="{Binding ConflictRuleCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||||
Tag="Skip"/>
|
CommandParameter="Skip"/>
|
||||||
<ToggleButton x:Name="ConflictRenameBtn" Content="Rename"
|
<ToggleButton x:Name="ConflictRenameBtn" Content="Rename"
|
||||||
Style="{StaticResource FsSegmentStyle}"
|
Style="{StaticResource FsSegmentStyle}"
|
||||||
IsChecked="True"
|
IsChecked="True"
|
||||||
Click="OnConflictSegmentClick"
|
Command="{Binding ConflictRuleCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||||
Tag="Rename"/>
|
CommandParameter="Rename"/>
|
||||||
<ToggleButton x:Name="ConflictReplaceBtn" Content="Replace"
|
<ToggleButton x:Name="ConflictReplaceBtn" Content="Replace"
|
||||||
Style="{StaticResource FsSegmentStyle}"
|
Style="{StaticResource FsSegmentStyle}"
|
||||||
Click="OnConflictSegmentClick"
|
Command="{Binding ConflictRuleCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||||
Tag="Replace"/>
|
CommandParameter="Replace"/>
|
||||||
</UniformGrid>
|
</UniformGrid>
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
@ -202,8 +200,7 @@
|
||||||
<TextBlock Text="AI 작업" Style="{StaticResource FsLabelStyle}" VerticalAlignment="Center"/>
|
<TextBlock Text="AI 작업" Style="{StaticResource FsLabelStyle}" VerticalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ComboBox x:Name="AiTaskCombo" Margin="0,8,0,0"
|
<ComboBox x:Name="AiTaskCombo" Margin="0,8,0,0"
|
||||||
SelectedIndex="0"
|
SelectedIndex="0">
|
||||||
SelectionChanged="OnAiTaskChanged">
|
|
||||||
<ComboBoxItem Content="요약"/>
|
<ComboBoxItem Content="요약"/>
|
||||||
<ComboBoxItem Content="번역"/>
|
<ComboBoxItem Content="번역"/>
|
||||||
<ComboBoxItem Content="교정"/>
|
<ComboBoxItem Content="교정"/>
|
||||||
|
|
@ -211,8 +208,18 @@
|
||||||
<TextBlock x:Name="AiTaskHint" Margin="0,6,0,0"
|
<TextBlock x:Name="AiTaskHint" Margin="0,6,0,0"
|
||||||
Style="{StaticResource FsCaptionStyle}"
|
Style="{StaticResource FsCaptionStyle}"
|
||||||
Text="텍스트(txt·md·docx) 출력 시 LLM이 적용합니다"/>
|
Text="텍스트(txt·md·docx) 출력 시 LLM이 적용합니다"/>
|
||||||
<StackPanel x:Name="AiTargetLangPanel" Margin="0,10,0,0"
|
<StackPanel x:Name="AiTargetLangPanel" Margin="0,10,0,0">
|
||||||
Visibility="Collapsed">
|
<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}"
|
<TextBlock Text="대상 언어" Style="{StaticResource FsCaptionStyle}"
|
||||||
Margin="0,0,0,4"/>
|
Margin="0,0,0,4"/>
|
||||||
<TextBox x:Name="AiTargetLangBox"
|
<TextBox x:Name="AiTargetLangBox"
|
||||||
|
|
@ -338,7 +345,8 @@
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<ToggleButton x:Name="TabActiveBtn"
|
<ToggleButton x:Name="TabActiveBtn"
|
||||||
Style="{StaticResource FsTabPillStyle}"
|
Style="{StaticResource FsTabPillStyle}"
|
||||||
Click="OnTabClick" Tag="Active">
|
Command="{Binding TabCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||||
|
CommandParameter="Active">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="Active Queue" VerticalAlignment="Center"/>
|
<TextBlock Text="Active Queue" VerticalAlignment="Center"/>
|
||||||
<Border Margin="8,0,0,0" Style="{StaticResource FsTabBadgeStyle}">
|
<Border Margin="8,0,0,0" Style="{StaticResource FsTabBadgeStyle}">
|
||||||
|
|
@ -351,7 +359,8 @@
|
||||||
<ToggleButton x:Name="TabPastBtn" Margin="8,0,0,0"
|
<ToggleButton x:Name="TabPastBtn" Margin="8,0,0,0"
|
||||||
IsChecked="True"
|
IsChecked="True"
|
||||||
Style="{StaticResource FsTabPillStyle}"
|
Style="{StaticResource FsTabPillStyle}"
|
||||||
Click="OnTabClick" Tag="Past">
|
Command="{Binding TabCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||||
|
CommandParameter="Past">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="Past Results" VerticalAlignment="Center"/>
|
<TextBlock Text="Past Results" VerticalAlignment="Center"/>
|
||||||
<Border Margin="8,0,0,0" Style="{StaticResource FsTabBadgeStyle}">
|
<Border Margin="8,0,0,0" Style="{StaticResource FsTabBadgeStyle}">
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
||||||
public ICommand PreviewOpenFolderCommand { get; }
|
public ICommand PreviewOpenFolderCommand { get; }
|
||||||
public ICommand RemoveQueueItemCommand { get; }
|
public ICommand RemoveQueueItemCommand { get; }
|
||||||
public ICommand OpenFolderCommand { get; }
|
public ICommand OpenFolderCommand { get; }
|
||||||
|
public ICommand TabCommand { get; }
|
||||||
|
public ICommand ConflictRuleCommand { get; }
|
||||||
|
public ICommand CombineToggleCommand { get; }
|
||||||
|
|
||||||
public MainWindow(ConversionEngine engine, ISettingsStore settings, IReadOnlyList<string>? initialFiles = null)
|
public MainWindow(ConversionEngine engine, ISettingsStore settings, IReadOnlyList<string>? initialFiles = null)
|
||||||
{
|
{
|
||||||
|
|
@ -72,6 +75,9 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
||||||
PreviewOpenFolderCommand = new RelayCommand(_ => OnPreviewOpenFolder(this, new RoutedEventArgs()));
|
PreviewOpenFolderCommand = new RelayCommand(_ => OnPreviewOpenFolder(this, new RoutedEventArgs()));
|
||||||
RemoveQueueItemCommand = new RelayCommand(p => RemoveQueueItem(p as QueueItem));
|
RemoveQueueItemCommand = new RelayCommand(p => RemoveQueueItem(p as QueueItem));
|
||||||
OpenFolderCommand = new RelayCommand(p => OpenFolderForPath(p as string));
|
OpenFolderCommand = new RelayCommand(p => OpenFolderForPath(p as string));
|
||||||
|
TabCommand = new RelayCommand(p => ShowTab(p as string ?? "Past"));
|
||||||
|
ConflictRuleCommand = new RelayCommand(p => SetConflictRule(p as string));
|
||||||
|
CombineToggleCommand = new RelayCommand(_ => UpdateCombineState(SelectedOutputExtension));
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
|
@ -147,14 +153,6 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
||||||
|
|
||||||
// ============== Tabs ==============
|
// ============== Tabs ==============
|
||||||
|
|
||||||
private void OnTabClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is ToggleButton tb && tb.Tag is string tag)
|
|
||||||
{
|
|
||||||
ShowTab(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowTab(string tag)
|
private void ShowTab(string tag)
|
||||||
{
|
{
|
||||||
TabActiveBtn.IsChecked = tag == "Active";
|
TabActiveBtn.IsChecked = tag == "Active";
|
||||||
|
|
@ -270,32 +268,18 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
||||||
|
|
||||||
// ============== Sidebar inputs ==============
|
// ============== Sidebar inputs ==============
|
||||||
|
|
||||||
private void OnQualityChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
private void SetConflictRule(string? tag)
|
||||||
{
|
{
|
||||||
if (QualityValueText is null) return;
|
_conflictRule = tag switch
|
||||||
QualityValueText.Text = $"{(int)e.NewValue}%";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnConflictSegmentClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is not ToggleButton clicked) return;
|
|
||||||
ConflictSkipBtn.IsChecked = clicked == ConflictSkipBtn;
|
|
||||||
ConflictRenameBtn.IsChecked = clicked == ConflictRenameBtn;
|
|
||||||
ConflictReplaceBtn.IsChecked = clicked == ConflictReplaceBtn;
|
|
||||||
_conflictRule = (clicked.Tag as string) switch
|
|
||||||
{
|
{
|
||||||
"Skip" => NameCollision.Skip,
|
"Skip" => NameCollision.Skip,
|
||||||
"Replace" => NameCollision.Overwrite,
|
"Replace" => NameCollision.Overwrite,
|
||||||
_ => NameCollision.AppendNumber,
|
_ => NameCollision.AppendNumber,
|
||||||
};
|
};
|
||||||
}
|
// 세그먼트 토글 그룹의 상호배제(하나만 체크).
|
||||||
|
ConflictSkipBtn.IsChecked = tag == "Skip";
|
||||||
private void OnAiTaskChanged(object sender, SelectionChangedEventArgs e)
|
ConflictRenameBtn.IsChecked = tag == "Rename";
|
||||||
{
|
ConflictReplaceBtn.IsChecked = tag == "Replace";
|
||||||
// 번역(인덱스 1)일 때만 대상 언어 입력을 표시
|
|
||||||
if (AiTargetLangPanel is null) return;
|
|
||||||
AiTargetLangPanel.Visibility =
|
|
||||||
(AiTaskCombo?.SelectedIndex == 1) ? Visibility.Visible : Visibility.Collapsed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPickOutputFolderClick(object sender, RoutedEventArgs e)
|
private void OnPickOutputFolderClick(object sender, RoutedEventArgs e)
|
||||||
|
|
@ -1052,11 +1036,6 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCombineToggleChanged(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
UpdateCombineState(SelectedOutputExtension);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnOutputFormatChanged(object sender, SelectionChangedEventArgs e)
|
private void OnOutputFormatChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_suppressFormatChanged) return;
|
if (_suppressFormatChanged) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue