[Phase L2-7] 퀵 액션 바 — 최근 실행 항목 칩 표시

Models/QuickActionChip.cs (신규 12줄):
- Title, Symbol, Path, Background 레코드

Services/UsageRankingService.cs:
- GetTopItems(int n) 메서드 추가: 실행 횟수 상위 N개 (경로, 횟수) 반환

ViewModels/LauncherViewModel.cs:
- QuickActionItems (ObservableCollection<QuickActionChip>) 프로퍼티 추가
- ShowQuickActions: 입력 비었을 때 칩 표시 조건
- LoadQuickActions(): 상위 8개 경로 → 파일 존재 확인 → 타입별 아이콘/색상 칩 생성
- OnShown()에서 LoadQuickActions() 호출
- InputText 변경 시 ShowQuickActions 알림

Views/LauncherWindow.xaml:
- 입력 Grid를 2행 구조로 변환 (RowDefinitions 추가)
- Row 1: ItemsControl + WrapPanel + DataTemplate 칩 UI
  - CornerRadius=10 Border, 아이콘+제목 StackPanel
  - 호버 시 AccentColor 테두리, 최대 너비 100px 말줄임

Views/LauncherWindow.Shell.cs:
- QuickActionChip_Click 핸들러: 창 숨김 → 경로 실행 → 사용 통계 기록

빌드: 경고 0, 오류 0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 10:44:02 +09:00
parent 679de30f68
commit f557f53449
5 changed files with 220 additions and 0 deletions

View File

@@ -48,6 +48,15 @@ public partial class LauncherViewModel : INotifyPropertyChanged
/// </summary>
public ICollectionView GroupedResults { get; }
/// <summary>
/// 퀵 액션 바 — 가장 많이 실행한 항목을 입력창 아래 칩으로 표시합니다.
/// 입력창이 비어 있을 때만 표시됩니다.
/// </summary>
public ObservableCollection<QuickActionChip> QuickActionItems { get; } = new();
/// <summary>퀵 액션 칩 표시 조건: 입력이 없고 칩이 하나 이상 있을 때</summary>
public bool ShowQuickActions => string.IsNullOrEmpty(_inputText) && QuickActionItems.Count > 0;
// ─── 기본 프로퍼티 ────────────────────────────────────────────────────────
public string InputText
@@ -66,6 +75,8 @@ public partial class LauncherViewModel : INotifyPropertyChanged
OnPropertyChanged(nameof(ShowMergeHint));
OnPropertyChanged(nameof(MergeHintText));
OnPropertyChanged(nameof(ShowQuickActions));
// 연속 입력 시 이전 검색 즉시 취소 + 50ms 디바운스 후 실제 검색 시작
_searchCts?.Cancel();
_debounceTimer?.Dispose();
@@ -266,6 +277,47 @@ public partial class LauncherViewModel : INotifyPropertyChanged
Results.Clear();
_lastSearchQuery = "";
ClearMerge();
LoadQuickActions();
}
/// <summary>
/// UsageRankingService 상위 항목에서 퀵 액션 칩을 생성합니다.
/// 실제로 존재하는 파일/폴더만 표시하며 최대 8개로 제한합니다.
/// </summary>
public void LoadQuickActions()
{
QuickActionItems.Clear();
var topItems = UsageRankingService.GetTopItems(16); // 여유분 확보 (일부 경로가 없을 수 있음)
var added = 0;
foreach (var (path, _) in topItems)
{
if (added >= 8) break;
var expanded = Environment.ExpandEnvironmentVariables(path);
var isFolder = Directory.Exists(expanded);
var isFile = !isFolder && File.Exists(expanded);
if (!isFolder && !isFile) continue; // 삭제된 항목 건너뜀
var ext = Path.GetExtension(expanded).ToLowerInvariant();
var title = Path.GetFileNameWithoutExtension(expanded);
if (string.IsNullOrEmpty(title)) title = Path.GetFileName(expanded);
var symbol = isFolder ? Symbols.Folder
: ext == ".exe" ? Symbols.App
: ext is ".lnk"
or ".url" ? Symbols.App
: Symbols.File;
var color = isFolder ? Color.FromRgb(0x10, 0x7C, 0x10)
: ext == ".exe" ? Color.FromRgb(0x4B, 0x5E, 0xFC)
: ext is ".lnk"
or ".url" ? Color.FromRgb(0x4B, 0x5E, 0xFC)
: Color.FromRgb(0x5B, 0x4E, 0x7E);
var bg = new SolidColorBrush(Color.FromArgb(0x26, color.R, color.G, color.B));
QuickActionItems.Add(new QuickActionChip(title, symbol, path, bg));
added++;
}
OnPropertyChanged(nameof(ShowQuickActions));
}
// ─── 검색 ────────────────────────────────────────────────────────────────