feat: P4-P8 한방 마무리 — 자체서명 MSIX, 영구저장, 단축키, capability 알림
P4 — 자체 서명 MSIX 자동화 - packaging/BuildAndSign.ps1: 인증서 생성→PFX export→MSIX 빌드→서명을 한 스크립트로 일관 처리. 기존 인증서 있으면 재사용. - Install-EverythingToJpeg.ps1: 기본 비밀번호 'EverythingToJpegDev' 자동 사용 (사용자 5대 PC 본인 사용 한정). - 검증: 53MB 서명된 MSIX 산출, signtool 정상 통과(DigiCert TimeStamp 박힘). P6 — Past Results 영구 저장 - HistoryStorage.cs: %LocalAppData%\EverythingToJpeg\history.jsonl 에 변환 결과 append. 시작 시 로드해서 _pastResults에 채움. - 첫 실행에만 데모 시드, 이후엔 실데이터만 표시. - Past Results의 Clear All은 영구 파일도 함께 삭제 (확인 다이얼로그 추가). P7 — 정리 + 단축키 - 사용 안 하는 ConvertWindow.xaml/.cs 폐기 (코드 600줄 제거). - KeyBinding 4개: Ctrl+O 파일 추가, Ctrl+Enter 변환, Esc 닫기, F5 새로고침. - RelayCommand 헬퍼 클래스로 단축키 ICommand 패턴 구현. P8 — Capability 자동 안내 - 시작 시 RequiresExternal Provider들의 가용성 비동기 체크. - 외부 도구 미설치 형식이 있으면 사이드바 footer에 "⚠ N개 형식이 외부 도구를 기다립니다 (Diagnose 참조)" 한 줄 표시. README — Phase 1~8 전체 진척, 단축키 표 정리. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
00d1eeff96
commit
784167ccff
8 changed files with 276 additions and 709 deletions
|
|
@ -20,16 +20,27 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
|||
private CancellationTokenSource? _cts;
|
||||
private NameCollision _conflictRule = NameCollision.AppendNumber;
|
||||
|
||||
public ICommand AddFilesCommand { get; }
|
||||
public ICommand ProcessQueueCommand { get; }
|
||||
public ICommand CloseCommand { get; }
|
||||
public ICommand RefreshCommand { get; }
|
||||
|
||||
public MainWindow() : this(null) { }
|
||||
|
||||
public MainWindow(IReadOnlyList<string>? initialFiles)
|
||||
{
|
||||
AddFilesCommand = new RelayCommand(_ => PickAndAddFiles());
|
||||
ProcessQueueCommand = new RelayCommand(_ => OnProcessQueueClick(this, new RoutedEventArgs()),
|
||||
_ => _activeQueue.Count > 0 && _cts is null);
|
||||
CloseCommand = new RelayCommand(_ => Close());
|
||||
RefreshCommand = new RelayCommand(_ => ApplyAppDataStats());
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
ActiveQueueList.ItemsSource = _activeQueue;
|
||||
PastResultsList.ItemsSource = _pastResults;
|
||||
|
||||
SeedDemoHistory();
|
||||
LoadHistory();
|
||||
UpdateBadges();
|
||||
UpdateProcessQueueButton();
|
||||
|
||||
|
|
@ -45,6 +56,47 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
|||
|
||||
UpdateActiveQueueVisibility();
|
||||
ApplyAppDataStats();
|
||||
|
||||
_ = RefreshCapabilityStatusAsync();
|
||||
}
|
||||
|
||||
private async Task RefreshCapabilityStatusAsync()
|
||||
{
|
||||
var engine = ((App)Application.Current).Engine;
|
||||
var notReady = new List<string>();
|
||||
foreach (var p in engine.Providers.All)
|
||||
{
|
||||
if (p.Capability.Status == EverythingToJpeg.Core.Providers.ProviderStatus.RequiresExternal)
|
||||
{
|
||||
var availability = await p.CheckAvailabilityAsync();
|
||||
if (!availability.IsReady)
|
||||
notReady.Add(p.Capability.DisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
if (notReady.Count == 0)
|
||||
{
|
||||
CapabilityStatusText.Visibility = Visibility.Collapsed;
|
||||
return;
|
||||
}
|
||||
|
||||
CapabilityStatusText.Text = $"⚠ {notReady.Count}개 형식이 외부 도구를 기다립니다 (Diagnose 참조)";
|
||||
CapabilityStatusText.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void PickAndAddFiles()
|
||||
{
|
||||
var dlg = new Microsoft.Win32.OpenFileDialog
|
||||
{
|
||||
Multiselect = true,
|
||||
Title = "변환할 파일 추가",
|
||||
Filter = "지원 파일|*.png;*.jpg;*.jpeg;*.gif;*.bmp;*.tif;*.tiff;*.webp;*.avif;*.heic;*.heif;*.psd;*.dng;*.nef;*.cr2;*.cr3;*.arw;*.raf;*.orf;*.rw2;*.srw;*.pef;*.pdf;*.docx;*.doc;*.html;*.htm;*.hwp;*.hwpx|모든 파일|*.*",
|
||||
};
|
||||
if (dlg.ShowDialog(this) == true)
|
||||
{
|
||||
AddToQueue(dlg.FileNames);
|
||||
ShowTab("Active");
|
||||
}
|
||||
}
|
||||
|
||||
// ============== Tabs ==============
|
||||
|
|
@ -517,6 +569,12 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
|||
// ============== History ==============
|
||||
|
||||
private void AddToHistory(HistoryEntry entry)
|
||||
{
|
||||
AddToHistoryGroups(entry);
|
||||
HistoryStorage.Append(entry);
|
||||
}
|
||||
|
||||
private void AddToHistoryGroups(HistoryEntry entry)
|
||||
{
|
||||
var label = FormatDateLabel(entry.Date);
|
||||
var group = _pastResults.FirstOrDefault(g => g.DateTitle == label);
|
||||
|
|
@ -528,6 +586,21 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
|||
group.Add(HistoryRow.From(entry));
|
||||
}
|
||||
|
||||
private void LoadHistory()
|
||||
{
|
||||
var entries = HistoryStorage.Load();
|
||||
if (entries.Count == 0)
|
||||
{
|
||||
// 첫 실행: 데모 데이터로 시각적 가이드 제공
|
||||
SeedDemoHistory();
|
||||
return;
|
||||
}
|
||||
|
||||
// 가장 오래된 것부터 추가 (Insert(0)이 누적)
|
||||
foreach (var e in entries.OrderBy(e => e.Timestamp))
|
||||
AddToHistoryGroups(e);
|
||||
}
|
||||
|
||||
private void SeedDemoHistory()
|
||||
{
|
||||
var today = FormatDateLabel(DateOnly.FromDateTime(DateTime.Today));
|
||||
|
|
@ -624,7 +697,14 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
|||
}
|
||||
else if (TabPastBtn.IsChecked == true)
|
||||
{
|
||||
var confirm = MessageBox.Show(this,
|
||||
"Past Results 전체를 삭제하시겠습니까?\n영구 저장된 이력도 함께 삭제됩니다.",
|
||||
"EverythingToJpeg",
|
||||
MessageBoxButton.OKCancel, MessageBoxImage.Question);
|
||||
if (confirm != MessageBoxResult.OK) return;
|
||||
|
||||
_pastResults.Clear();
|
||||
HistoryStorage.Clear();
|
||||
}
|
||||
UpdateBadges();
|
||||
UpdateProcessQueueButton();
|
||||
|
|
@ -789,3 +869,24 @@ internal static class FormatPalette
|
|||
_ => (ext.ToUpperInvariant(), "FsFmtOther"),
|
||||
};
|
||||
}
|
||||
|
||||
internal sealed class RelayCommand : ICommand
|
||||
{
|
||||
private readonly Action<object?> _execute;
|
||||
private readonly Func<object?, bool>? _canExecute;
|
||||
|
||||
public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute = null)
|
||||
{
|
||||
_execute = execute;
|
||||
_canExecute = canExecute;
|
||||
}
|
||||
|
||||
public bool CanExecute(object? parameter) => _canExecute?.Invoke(parameter) ?? true;
|
||||
public void Execute(object? parameter) => _execute(parameter);
|
||||
|
||||
public event EventHandler? CanExecuteChanged
|
||||
{
|
||||
add { CommandManager.RequerySuggested += value; }
|
||||
remove { CommandManager.RequerySuggested -= value; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue