[Phase L4-4/L4-6] 검색 히스토리 + 계산기 단위변환 단축 문법
L4-4 검색 히스토리 (↑/↓ 키 탐색): - Services/SearchHistoryService.cs (신규 100줄): 50개 FIFO JSON 저장 Add() · GetAll() · Clear(). 2자 미만/중복 최상단 무시 - ViewModels/LauncherViewModel.cs: _historyIndex·_isHistoryNavigation 필드 추가 NavigateHistoryPrev() / NavigateHistoryNext() / SetInputFromHistory() InputText setter: 직접 입력 시 _historyIndex 초기화 ExecuteSelectedAsync: 실행 전 히스토리 저장 (2자 이상) OnShown: _historyIndex = -1 초기화 - Views/LauncherWindow.Keyboard.cs: Key.Up/Down — Results.Count==0 분기: 히스토리 탐색 / 목록 탐색 분기 L4-3 클립보드 핀/카테고리: 기존 완전 구현 확인 (IsPinned, Category, TogglePin, Ctrl+P, #pin/#url/#코드/#경로 필터) L4-6 계산기 단위 변환 단축 문법: - Handlers/UnitConverter.cs: AutoSuggest(): "20km", "100f", "5lb" 등 목표 없이 주요 단위 자동 제안 _suggestions 테이블: 길이/무게/속도/데이터/온도 40개 단위 매핑 DateShortcut: "today+30d", "today-7w" → = 접두어에서 날짜 계산 - Handlers/CalculatorHandler.cs: DateShortcut.TryMatch 분기 추가 (통화 감지 전) UnitConverter.AutoSuggest 분기 추가 (명시 변환 후) - 힌트 텍스트: "20km · 100°F · today+30d" 추가 docs/LAUNCHER_ROADMAP.md: Phase L4 계획 테이블 추가 빌드: 경고 0, 오류 0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,10 @@ public partial class LauncherViewModel : INotifyPropertyChanged
|
||||
private const int DebounceMs = 30; // 30ms 디바운스 — 연속 입력 시 중간 검색 스킵
|
||||
private string _lastSearchQuery = ""; // IME 조합 완성 후 동일 쿼리 재검색 방지용
|
||||
|
||||
// ─── 검색 히스토리 탐색 ──────────────────────────────────────────────────
|
||||
private bool _isHistoryNavigation; // InputText setter에서 히스토리 인덱스 리셋 방지
|
||||
private int _historyIndex = -1; // -1 = 탐색 중 아님
|
||||
|
||||
// ─── 파일 액션 모드 ───────────────────────────────────────────────────────
|
||||
private bool _isActionMode;
|
||||
private LauncherItem? _actionSourceItem;
|
||||
@@ -66,6 +70,8 @@ public partial class LauncherViewModel : INotifyPropertyChanged
|
||||
{
|
||||
if (_inputText == value) return;
|
||||
_inputText = value;
|
||||
// 사용자 직접 입력 시 히스토리 탐색 위치 초기화
|
||||
if (!_isHistoryNavigation) _historyIndex = -1;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(HasActivePrefix));
|
||||
OnPropertyChanged(nameof(ActivePrefixLabel));
|
||||
@@ -276,10 +282,49 @@ public partial class LauncherViewModel : INotifyPropertyChanged
|
||||
if (IsActionMode) { IsActionMode = false; _actionSourceItem = null; }
|
||||
Results.Clear();
|
||||
_lastSearchQuery = "";
|
||||
_historyIndex = -1;
|
||||
ClearMerge();
|
||||
LoadQuickActions();
|
||||
}
|
||||
|
||||
// ─── 검색 히스토리 탐색 ──────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// ↑ 키 — 이전(오래된) 히스토리 항목으로 이동.
|
||||
/// null이면 히스토리 없음.
|
||||
/// </summary>
|
||||
public string? NavigateHistoryPrev()
|
||||
{
|
||||
var history = SearchHistoryService.GetAll();
|
||||
if (history.Count == 0) return null;
|
||||
_historyIndex = Math.Min(_historyIndex + 1, history.Count - 1);
|
||||
return history[_historyIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ↓ 키 — 최신 히스토리 항목으로 이동.
|
||||
/// _historyIndex가 0 이하면 빈 문자열(현재 입력으로 복귀).
|
||||
/// </summary>
|
||||
public string? NavigateHistoryNext()
|
||||
{
|
||||
if (_historyIndex <= 0) { _historyIndex = -1; return ""; }
|
||||
_historyIndex--;
|
||||
var history = SearchHistoryService.GetAll();
|
||||
return _historyIndex >= 0 && _historyIndex < history.Count
|
||||
? history[_historyIndex] : "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 히스토리에서 탐색한 텍스트를 입력창에 설정합니다.
|
||||
/// InputText setter의 히스토리 인덱스 리셋을 억제합니다.
|
||||
/// </summary>
|
||||
public void SetInputFromHistory(string text)
|
||||
{
|
||||
_isHistoryNavigation = true;
|
||||
try { InputText = text; }
|
||||
finally { _isHistoryNavigation = false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UsageRankingService 상위 항목에서 퀵 액션 칩을 생성합니다.
|
||||
/// 실제로 존재하는 파일/폴더만 표시하며 최대 8개로 제한합니다.
|
||||
@@ -405,6 +450,10 @@ public partial class LauncherViewModel : INotifyPropertyChanged
|
||||
|
||||
if (SelectedItem == null) return;
|
||||
|
||||
// 실행 전 검색어 히스토리 저장 (2자 이상, prefix 포함)
|
||||
if (InputText.Trim().Length >= 2)
|
||||
SearchHistoryService.Add(InputText.Trim());
|
||||
|
||||
// 창을 먼저 닫아 체감 속도 확보 → 실행은 백그라운드
|
||||
CloseRequested?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user