Files

707 lines
29 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
namespace AxCopilot.Views;
public class HelpDetailWindow : Window, IComponentConnector
{
private enum TopMenu
{
Overview,
Shortcuts,
Prefixes
}
private const string CatAll = "전체";
private const string CatPopular = "⭐ 인기";
private static readonly (TopMenu Key, string Label, string Icon)[] TopMenus = new(TopMenu, string, string)[3]
{
(TopMenu.Overview, "개요", "\ue946"),
(TopMenu.Shortcuts, "단축키 현황", "\ue765"),
(TopMenu.Prefixes, "예약어 현황", "\ue8f4")
};
private TopMenu _currentTopMenu = TopMenu.Overview;
private readonly List<HelpItemModel> _allItems;
private readonly List<HelpItemModel> _shortcutItems;
private readonly List<HelpItemModel> _prefixItems;
private readonly List<HelpItemModel> _overviewItems;
private readonly string _globalHotkey;
private List<string> _categories = new List<string>();
private int _currentPage;
internal TextBlock SubtitleText;
internal StackPanel TopMenuBar;
internal TextBox SearchBox;
internal WrapPanel CategoryBar;
internal ItemsControl ItemsHost;
internal Button PrevBtn;
internal TextBlock PageIndicator;
internal Button NextBtn;
private bool _contentLoaded;
private Brush ThemeAccent => (TryFindResource("AccentColor") as Brush) ?? ParseColor("#4B5EFC");
private Brush ThemePrimary => (TryFindResource("PrimaryText") as Brush) ?? Brushes.White;
private Brush ThemeSecondary => (TryFindResource("SecondaryText") as Brush) ?? ParseColor("#8899CC");
public HelpDetailWindow(IEnumerable<HelpItemModel> items, int totalCount, string globalHotkey = "Alt+Space")
{
InitializeComponent();
_allItems = items.ToList();
_globalHotkey = globalHotkey;
_overviewItems = new List<HelpItemModel>
{
new HelpItemModel
{
Category = "개요",
Command = "AX Commander",
Title = "키보드 하나로 모든 업무를 제어하는 AX Commander",
Description = "단축키 한 번으로 앱 실행, 파일/폴더 검색, 계산, 클립보드 관리, 화면 캡처, 창 전환, 시스템 제어, 업무 일지, 루틴 자동화, AI 대화까지. 40개+ 명령어를 예약어로 즉시 접근.",
Symbol = "\ue946",
ColorBrush = ParseColor("#4B5EFC")
},
new HelpItemModel
{
Category = "개요",
Command = "사용법",
Title = "예약어 + 키워드 → Enter",
Description = "특수 문자를 맨 앞에 입력하면 해당 기능 모드로 전환됩니다. 예) = 수식, # 클립보드, ? 웹검색, ! AI 대화, cap 캡처. 예약어 없이 입력하면 앱/파일/폴더 검색.",
Symbol = "\ue765",
ColorBrush = ParseColor("#0078D4")
},
new HelpItemModel
{
Category = "개요",
Command = "데이터 보호",
Title = "모든 데이터는 내 PC에만 안전하게 저장",
Description = "설정, 클립보드, 대화 내역, 통계, 로그 등 모든 데이터가 로컬에 암호화 저장됩니다. 다른 PC에서는 열 수 없으며, 보존 기간 만료 시 자동 삭제됩니다.",
Symbol = "\ue8b7",
ColorBrush = ParseColor("#107C10")
},
new HelpItemModel
{
Category = "AI",
Command = "! (AX Agent)",
Title = "AX Agent — AI 어시스턴트와 대화",
Description = "AX Commander에서 ! 를 입력하면 AI 대화가 열립니다. 질문을 바로 물어보거나, 이전 대화를 이어갈 수 있습니다. 대화 주제별 분류, 검색, 사이드바 토글을 지원합니다.",
Example = "! 오늘 회의 요약해줘\n! 이메일 초안 작성해줘",
Symbol = "\ue8bd",
ColorBrush = ParseColor("#8B2FC9")
},
new HelpItemModel
{
Category = "AI",
Command = "3탭 구조",
Title = "Chat · Cowork · Code — 용도별 3탭 구조",
Description = "Chat: 자유로운 AI 대화 — 질문, 번역, 요약, 아이디어 브레인스토밍.\nCowork: 업무 보조 — 파일 읽기/쓰기, 문서 생성(Excel·Word·PPT·HTML), 데이터 분석, 보고서 작성.\nCode: 코딩 도우미 — 개발, 리팩터링, 코드 리뷰, 보안 점검, 테스트 작성. 개발 환경 자동 감지.",
Symbol = "\ue71b",
ColorBrush = ParseColor("#3B82F6")
},
new HelpItemModel
{
Category = "AI",
Command = "AI 서비스",
Title = "사내 AI · 외부 AI 서비스 선택 가능",
Description = "관리자가 설정한 AI 서비스에 자동 연결됩니다. 사내 서버와 외부 서비스 중 선택할 수 있으며, 연결 정보는 암호화되어 보호됩니다.",
Symbol = "\ue968",
ColorBrush = ParseColor("#0078D4")
},
new HelpItemModel
{
Category = "AI",
Command = "실시간 응답",
Title = "AI 응답이 실시간으로 표시",
Description = "AI의 응답이 생성되는 즉시 화면에 표시됩니다. 긴 답변도 기다리지 않고 바로 읽기 시작할 수 있습니다.",
Symbol = "\ue8ab",
ColorBrush = ParseColor("#107C10")
},
new HelpItemModel
{
Category = "AI",
Command = "대화 보호",
Title = "모든 대화 내역이 암호화 저장",
Description = "대화 내역은 내 PC에서만 열람할 수 있도록 암호화됩니다. 다른 PC로 복사해도 열 수 없으며, 보존 기간 만료 시 자동 삭제됩니다.",
Symbol = "\ue72e",
ColorBrush = ParseColor("#C50F1F")
},
new HelpItemModel
{
Category = "AI",
Command = "AI 규칙 설정",
Title = "관리자가 설정한 응답 규칙이 자동 적용",
Description = "관리자가 지정한 역할, 응답 톤, 업무 규칙이 모든 대화에 자동 적용됩니다. AI의 응답 스타일을 일괄 관리할 수 있습니다.",
Symbol = "\ue771",
ColorBrush = ParseColor("#D97706")
},
new HelpItemModel
{
Category = "AI",
Command = "대화 관리",
Title = "분류 · 검색 · 타임라인",
Description = "대화를 주제별로 분류하고, 오늘/이전 타임라인으로 구분합니다. 검색과 카테고리 필터로 빠르게 찾을 수 있습니다.",
Symbol = "\ue8f1",
ColorBrush = ParseColor("#4B5EFC")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "note",
Title = "빠른 메모 저장 · 검색",
Description = "note 뒤에 내용을 입력하면 즉시 메모가 저장됩니다. 나중에 note 키워드로 검색하면 이전 메모를 다시 찾을 수 있습니다. 간단한 아이디어나 할 일을 빠르게 기록하세요.",
Example = "note 내일 보고서 마감\nnote 김부장님 연락처 확인",
Symbol = "\ue70b",
ColorBrush = ParseColor("#D97706")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "journal",
Title = "업무 일지 작성",
Description = "journal 뒤에 내용을 입력하면 날짜별 업무 일지로 자동 기록됩니다. 하루 동안의 업무 내용을 간결하게 쌓아가면 주간 보고나 회고에 활용할 수 있습니다.",
Example = "journal 배포 완료\njournal 클라이언트 미팅 30분",
Symbol = "\ue8f2",
ColorBrush = ParseColor("#0078D4")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "pipe",
Title = "클립보드 텍스트 파이프라인 변환",
Description = "클립보드에 복사된 텍스트를 여러 변환 함수로 한 번에 처리합니다. upper(대문자), lower(소문자), trim(공백 제거), wrap(줄바꿈), sort(정렬) 등을 연결할 수 있습니다.",
Example = "pipe upper | trim | wrap 80",
Symbol = "\ue8ab",
ColorBrush = ParseColor("#107C10")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "diff",
Title = "두 텍스트 비교 (Diff)",
Description = "클립보드의 두 텍스트를 비교하여 차이점을 한눈에 보여줍니다. 코드 변경 사항 확인, 문서 버전 비교 등에 유용합니다.",
Example = "diff",
Symbol = "\ue8fd",
ColorBrush = ParseColor("#6B2C91")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "encode",
Title = "인코딩 · 디코딩 변환",
Description = "Base64, URL, HTML, Unicode 등 다양한 형식으로 텍스트를 인코딩하거나 디코딩합니다. 개발자에게 특히 유용한 변환 도구입니다.",
Example = "encode base64 hello\nencode url 한글 테스트",
Symbol = "\ue943",
ColorBrush = ParseColor("#323130")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "routine",
Title = "반복 작업 루틴 자동화",
Description = "자주 하는 작업 묶음을 루틴으로 등록해 두면 한 번의 명령으로 여러 앱을 동시에 열거나 작업 환경을 구성할 수 있습니다. 출근·퇴근 루틴 등을 만들어 보세요.",
Example = "routine start 출근\nroutine list",
Symbol = "\ue8f5",
ColorBrush = ParseColor("#BE185D")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "stats",
Title = "텍스트 통계 (글자수·단어수·줄수)",
Description = "클립보드에 복사된 텍스트의 글자 수, 단어 수, 줄 수를 즉시 계산합니다. 보고서 분량 체크, SNS 글자 수 제한 확인 등에 활용하세요.",
Example = "stats",
Symbol = "\ue9d9",
ColorBrush = ParseColor("#44546A")
},
new HelpItemModel
{
Category = "업무 보조",
Command = "json",
Title = "JSON 파싱 · 정리 · 미리보기",
Description = "클립보드에 복사된 JSON을 자동으로 파싱하고 읽기 좋은 형태로 정리합니다. 들여쓰기, 키 하이라이트, 복사 기능을 제공합니다.",
Example = "json {\"key\":\"value\"}",
Symbol = "\ue8a5",
ColorBrush = ParseColor("#4B5EFC")
}
};
_shortcutItems = BuildShortcutItems(_globalHotkey);
_prefixItems = _allItems.ToList();
SubtitleText.Text = $"총 {totalCount}개 명령어 · 단축키 {_shortcutItems.Count}개 · 예약어 {_prefixItems.Count}개";
BuildTopMenu();
SwitchTopMenu(TopMenu.Overview);
base.KeyDown += OnKeyDown;
}
private static List<HelpItemModel> BuildShortcutItems(string globalHotkey = "Alt+Space")
{
List<HelpItemModel> list = new List<HelpItemModel>();
string key = globalHotkey.Replace("+", " + ");
list.Add(MakeShortcut("전역", key, "AX Commander 열기/닫기", "어느 창에서든 눌러 AX Commander를 즉시 호출하거나 닫습니다. 설정 일반에서 원하는 키 조합으로 변경할 수 있습니다.", "\ue765", "#4B5EFC"));
list.Add(MakeShortcut("전역", "PrintScreen", "화면 캡처 즉시 실행", "AX Commander를 열지 않고 곧바로 캡처를 시작합니다. 설정 캡처 탭에서 '글로벌 단축키 활성화'를 켜야 동작합니다.", "\ue722", "#BE185D"));
list.Add(MakeShortcut("AX Commander 탐색", "Escape", "창 닫기 / 이전 단계로", "액션 모드(→ 로 진입)에 있을 때는 일반 검색 화면으로 돌아갑니다. 일반 화면이면 AX Commander를 숨깁니다.", "\ue711", "#999999"));
list.Add(MakeShortcut("AX Commander 탐색", "Enter", "선택 항목 실행", "파일·앱이면 열기, URL이면 브라우저 열기, 시스템 명령이면 즉시 실행, 계산기 결과면 클립보드에 복사합니다.", "\ue768", "#107C10"));
list.Add(MakeShortcut("AX Commander 탐색", "Shift + Enter", "대형 텍스트(Large Type) 표시 / 클립보드 병합 실행", "선택된 텍스트·검색어를 화면 전체에 크게 띄웁니다. 클립보드 병합 항목이 있을 때는 선택한 항목들을 줄바꿈으로 합쳐 클립보드에 복사합니다.", "\ue8c1", "#8764B8"));
list.Add(MakeShortcut("AX Commander 탐색", "↑ / ↓", "결과 목록 위/아래 이동", "목록 끝에서 계속 누르면 처음/끝으로 순환합니다.", "\ue74a", "#0078D4"));
list.Add(MakeShortcut("AX Commander 탐색", "PageUp / PageDown", "목록 5칸 빠른 이동", "한 번에 5항목씩 건너뜁니다. 빠른 목록 탐색에 유용합니다.", "\ue74a", "#0078D4"));
list.Add(MakeShortcut("AX Commander 탐색", "Home / End", "목록 처음 / 마지막 항목으로 점프", "입력창 커서가 맨 앞(또는 입력이 없을 때)이면 첫 항목으로, 맨 끝이면 마지막 항목으로 선택이 이동합니다.", "\ue74a", "#0078D4"));
list.Add(MakeShortcut("AX Commander 탐색", "→ (오른쪽 화살표)", "액션 모드 진입", "파일·앱 항목을 선택한 상태에서 → 를 누르면 경로 복사, 탐색기 열기, 관리자 실행, 터미널, 속성, 이름 변경, 삭제 메뉴가 나타납니다.", "\ue76c", "#44546A"));
list.Add(MakeShortcut("AX Commander 탐색", "Tab", "선택 항목 제목으로 자동완성", "현재 선택된 항목의 이름을 입력창에 채웁니다. 이후 계속 타이핑하거나 Enter로 실행합니다.", "\ue748", "#006EAF"));
list.Add(MakeShortcut("AX Commander 탐색", "Shift + ↑/↓", "클립보드 병합 선택", "클립보드 히스토리(# 모드) 에서 여러 항목을 이동하면서 선택/해제합니다. Shift+Enter로 선택한 항목들을 한 번에 붙여넣을 수 있습니다.", "\ue8c1", "#B7791F"));
list.Add(MakeShortcut("런처 기능", "F1", "도움말 창 열기", "이 화면을 직접 엽니다. 'help' 를 입력하는 것과 동일합니다.", "\ue897", "#6B7280"));
list.Add(MakeShortcut("런처 기능", "F2", "선택 파일 이름 변경", "파일·폴더 항목을 선택한 상태에서 누르면 rename [경로] 형태로 입력창에 채워지고 이름 변경 핸들러가 실행됩니다.", "\ue70f", "#6B2C91"));
list.Add(MakeShortcut("런처 기능", "F5", "파일 인덱스 즉시 재구축", "백그라운드에서 파일·앱 인덱싱을 다시 실행합니다. 새 파일을 추가했거나 목록이 오래됐을 때 사용합니다.", "\ue72c", "#059669"));
list.Add(MakeShortcut("런처 기능", "Delete", "최근 실행 목록에서 항목 제거", "recent 목록에 있는 항목을 제거합니다. 확인 다이얼로그가 표시되며 OK를 눌러야 실제로 제거됩니다.", "\ue74d", "#DC2626"));
list.Add(MakeShortcut("런처 기능", "Ctrl + ,", "설정 창 열기", "AX Copilot 설정 창을 엽니다. 런처가 자동으로 숨겨집니다.", "\ue713", "#44546A"));
list.Add(MakeShortcut("런처 기능", "Ctrl + L", "입력창 전체 초기화", "현재 입력된 검색어·예약어를 모두 지우고 커서를 빈 입력창으로 돌립니다.", "\ue894", "#4B5EFC"));
list.Add(MakeShortcut("런처 기능", "Ctrl + C", "선택 항목 파일 이름 복사", "파일·앱 항목이 선택된 경우 확장자를 제외한 파일 이름을 클립보드에 복사하고 토스트로 알립니다.", "\ue8c8", "#8764B8"));
list.Add(MakeShortcut("런처 기능", "Ctrl + Shift + C", "선택 항목 전체 경로 복사", "선택된 파일·폴더의 절대 경로(예: C:\\Users\\...)를 클립보드에 복사합니다.", "\ue8c8", "#C55A11"));
list.Add(MakeShortcut("런처 기능", "Ctrl + Shift + E", "파일 탐색기에서 선택 항목 열기", "Windows 탐색기가 열리고 해당 파일·폴더가 하이라이트 선택된 상태로 표시됩니다.", "\ue838", "#107C10"));
list.Add(MakeShortcut("런처 기능", "Ctrl + Enter", "관리자(UAC) 권한으로 실행", "선택된 파일·앱을 UAC 권한 상승 후 실행합니다. 설치 프로그램이나 시스템 설정 앱에 유용합니다.", "\ue7ef", "#C50F1F"));
list.Add(MakeShortcut("런처 기능", "Alt + Enter", "파일 속성 대화 상자 열기", "Windows의 '파일 속성' 창(크기·날짜·권한 등)을 엽니다.", "\ue946", "#6B2C91"));
list.Add(MakeShortcut("런처 기능", "Ctrl + T", "선택 항목 위치에서 터미널 열기", "선택된 파일이면 해당 폴더에서, 폴더이면 그 경로에서 Windows Terminal(wt.exe)이 열립니다. wt가 없으면 cmd로 대체됩니다.", "\ue756", "#323130"));
list.Add(MakeShortcut("런처 기능", "Ctrl + P", "즐겨찾기 즉시 추가 / 제거 (핀)", "파일·폴더 항목을 선택한 상태에서 누르면 favorites.json 에 추가하거나 이미 있으면 제거합니다. 토스트로 결과를 알립니다.", "\ue734", "#D97706"));
list.Add(MakeShortcut("런처 기능", "Ctrl + B", "즐겨찾기 목록 보기 / 닫기 토글", "입력창이 'fav' 이면 초기화하고, 아니면 'fav' 를 입력해 즐겨찾기 목록을 표시합니다.", "\ue735", "#D97706"));
list.Add(MakeShortcut("런처 기능", "Ctrl + R", "최근 실행 목록 보기 / 닫기 토글", "'recent' 를 입력해 최근 실행 항목을 표시합니다.", "\ue81c", "#0078D4"));
list.Add(MakeShortcut("런처 기능", "Ctrl + H", "클립보드 히스토리 목록 열기", "'#' 를 입력해 클립보드에 저장된 최근 복사 항목 목록을 표시합니다.", "\ue77f", "#8B2FC9"));
list.Add(MakeShortcut("런처 기능", "Ctrl + D", "다운로드 폴더 바로가기", "사용자 홈의 Downloads 폴더 경로를 입력창에 채워 탐색기로 열 수 있게 합니다.", "\ue8b7", "#107C10"));
list.Add(MakeShortcut("런처 기능", "Ctrl + F", "파일 검색 모드로 전환", "입력창을 초기화하고 포커스를 이동합니다. 이후 파일명을 바로 타이핑해 검색할 수 있습니다.", "\ue71e", "#4B5EFC"));
list.Add(MakeShortcut("런처 기능", "Ctrl + W", "런처 창 즉시 닫기", "현재 입력 내용에 관계없이 런처를 즉시 숨깁니다.", "\ue711", "#9999BB"));
list.Add(MakeShortcut("런처 기능", "Ctrl + K", "단축키 참조 모달 창 열기", "모든 단축키와 설명을 보여주는 별도 모달 창이 열립니다. Esc 또는 닫기 버튼으로 닫습니다.", "\ue8fd", "#4B5EFC"));
list.Add(MakeShortcut("런처 기능", "Ctrl + 1 ~ 9", "N번째 결과 항목 바로 실행", "목록에 번호 배지(1~9)가 표시된 항목을 해당 숫자 키로 즉시 실행합니다. 마우스 없이 빠른 실행에 유용합니다.", "\ue8c4", "#107C10"));
list.Add(MakeShortcut("기타 창", "← / →", "헬프 창 카테고리 이동", "이 도움말 창에서 하위 카테고리 탭을 왼쪽/오른쪽으로 이동합니다.", "\ue76b", "#4455AA"));
list.Add(MakeShortcut("기타 창", "1 / 2 / 3", "헬프 창 상단 메뉴 전환", "이 도움말 창에서 개요(1), 단축키 현황(2), 예약어 현황(3)을 키보드로 전환합니다.", "\ue8bd", "#4455AA"));
list.Add(MakeShortcut("기타 창", "방향키 (캡처 중)", "영역 선택 경계 1px 미세 조정", "화면 캡처의 영역 선택 모드에서 선택 영역 경계를 1픽셀씩 정밀 조정합니다.", "\ue745", "#BE185D"));
list.Add(MakeShortcut("기타 창", "Shift + 방향키 (캡처 중)", "영역 선택 경계 10px 이동", "화면 캡처의 영역 선택 모드에서 선택 영역 경계를 10픽셀씩 빠르게 이동합니다.", "\ue745", "#BE185D"));
return list;
}
private static SolidColorBrush ParseColor(string hex)
{
try
{
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(hex));
}
catch
{
return new SolidColorBrush(Colors.Gray);
}
}
private static HelpItemModel MakeShortcut(string cat, string key, string title, string desc, string symbol, string color)
{
return new HelpItemModel
{
Category = cat,
Command = key,
Title = title,
Description = desc,
Symbol = symbol,
ColorBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(color))
};
}
private void BuildTopMenu()
{
TopMenuBar.Children.Clear();
(TopMenu, string, string)[] topMenus = TopMenus;
for (int i = 0; i < topMenus.Length; i++)
{
(TopMenu, string, string) tuple = topMenus[i];
TopMenu item = tuple.Item1;
string item2 = tuple.Item2;
string item3 = tuple.Item3;
TopMenu k = item;
StackPanel stackPanel = new StackPanel
{
Orientation = Orientation.Horizontal
};
stackPanel.Children.Add(new TextBlock
{
Text = item3,
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontSize = 14.0,
Foreground = ThemeAccent,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(0.0, 0.0, 6.0, 0.0)
});
stackPanel.Children.Add(new TextBlock
{
Text = item2,
FontSize = 12.0,
VerticalAlignment = VerticalAlignment.Center
});
Button button = new Button
{
Content = stackPanel,
FontWeight = FontWeights.SemiBold,
Padding = new Thickness(16.0, 8.0, 16.0, 8.0),
Margin = new Thickness(4.0, 0.0, 4.0, 0.0),
Cursor = Cursors.Hand,
Background = Brushes.Transparent,
Foreground = ThemeSecondary,
BorderThickness = new Thickness(0.0, 0.0, 0.0, 2.0),
BorderBrush = Brushes.Transparent,
Tag = k
};
button.Click += delegate
{
SwitchTopMenu(k);
};
TopMenuBar.Children.Add(button);
}
}
private void SwitchTopMenu(TopMenu menu)
{
_currentTopMenu = menu;
foreach (object child in TopMenuBar.Children)
{
if (!(child is Button { Tag: var tag } button))
{
continue;
}
bool flag = tag is TopMenu topMenu && topMenu == menu;
button.BorderBrush = (flag ? ThemeAccent : Brushes.Transparent);
button.Foreground = (flag ? ThemePrimary : ThemeSecondary);
if (!(button.Content is StackPanel stackPanel))
{
continue;
}
foreach (object child2 in stackPanel.Children)
{
if (child2 is TextBlock textBlock && textBlock.FontFamily.Source != "Segoe MDL2 Assets")
{
textBlock.Foreground = button.Foreground;
}
}
}
switch (menu)
{
case TopMenu.Overview:
BuildCategoryBarFor(_overviewItems);
break;
case TopMenu.Shortcuts:
BuildCategoryBarFor(_shortcutItems);
break;
case TopMenu.Prefixes:
BuildCategoryBarFor(_prefixItems);
break;
}
}
private void BuildCategoryBarFor(List<HelpItemModel> sourceItems)
{
HashSet<string> hashSet = new HashSet<string>();
_categories = new List<string> { "전체" };
if (_currentTopMenu == TopMenu.Prefixes)
{
_categories.Add("⭐ 인기");
}
foreach (HelpItemModel sourceItem in sourceItems)
{
if (hashSet.Add(sourceItem.Category))
{
_categories.Add(sourceItem.Category);
}
}
BuildCategoryBar();
NavigateToPage(0);
}
private void BuildCategoryBar()
{
CategoryBar.Children.Clear();
for (int i = 0; i < _categories.Count; i++)
{
string content = _categories[i];
int idx = i;
Button button = new Button
{
Content = content,
FontSize = 10.5,
FontWeight = FontWeights.SemiBold,
Padding = new Thickness(9.0, 4.0, 9.0, 4.0),
Margin = new Thickness(0.0, 0.0, 3.0, 0.0),
Cursor = Cursors.Hand,
Background = Brushes.Transparent,
Foreground = ThemeSecondary,
BorderThickness = new Thickness(0.0),
Tag = idx
};
button.Click += delegate
{
NavigateToPage(idx);
};
CategoryBar.Children.Add(button);
}
}
private List<HelpItemModel> GetCurrentSourceItems()
{
TopMenu currentTopMenu = _currentTopMenu;
if (1 == 0)
{
}
List<HelpItemModel> result = currentTopMenu switch
{
TopMenu.Overview => _overviewItems,
TopMenu.Shortcuts => _shortcutItems,
TopMenu.Prefixes => _prefixItems,
_ => _overviewItems,
};
if (1 == 0)
{
}
return result;
}
private void NavigateToPage(int pageIndex)
{
if (_categories.Count == 0)
{
return;
}
_currentPage = Math.Clamp(pageIndex, 0, _categories.Count - 1);
List<HelpItemModel> currentSourceItems = GetCurrentSourceItems();
string cat = _categories[_currentPage];
List<HelpItemModel> list;
if (cat == "전체")
{
list = currentSourceItems;
}
else if (cat == "⭐ 인기")
{
HashSet<string> popularCmds = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "파일/폴더", "?", "#", "!", "clip", "pipe", "diff", "win" };
list = currentSourceItems.Where((HelpItemModel i) => popularCmds.Contains(i.Command) || i.Command.StartsWith("?") || i.Title.Contains("검색") || i.Title.Contains("클립보드") || (i.Title.Contains("파일") && i.Category != "키보드")).ToList();
}
else
{
list = currentSourceItems.Where((HelpItemModel i) => i.Category == cat).ToList();
}
ItemsHost.ItemsSource = list;
for (int num = 0; num < CategoryBar.Children.Count; num++)
{
if (CategoryBar.Children[num] is Button button)
{
if (num == _currentPage)
{
button.Background = ThemeAccent;
button.Foreground = Brushes.White;
}
else
{
button.Background = Brushes.Transparent;
button.Foreground = ThemeSecondary;
}
}
}
PageIndicator.Text = $"{cat} ({list.Count}개)";
PrevBtn.Visibility = ((_currentPage <= 0) ? Visibility.Hidden : Visibility.Visible);
NextBtn.Visibility = ((_currentPage >= _categories.Count - 1) ? Visibility.Hidden : Visibility.Visible);
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Invalid comparison between Unknown and I4
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Invalid comparison between Unknown and I4
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Expected I4, but got Unknown
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Invalid comparison between Unknown and I4
Key key = e.Key;
Key val = key;
if ((int)val <= 23)
{
if ((int)val != 13)
{
if ((int)val == 23)
{
if (_currentPage > 0)
{
NavigateToPage(_currentPage - 1);
}
e.Handled = true;
}
}
else
{
Close();
}
}
else if ((int)val != 25)
{
switch (val - 35)
{
case 0:
SwitchTopMenu(TopMenu.Overview);
e.Handled = true;
break;
case 1:
SwitchTopMenu(TopMenu.Shortcuts);
e.Handled = true;
break;
case 2:
SwitchTopMenu(TopMenu.Prefixes);
e.Handled = true;
break;
}
}
else
{
if (_currentPage < _categories.Count - 1)
{
NavigateToPage(_currentPage + 1);
}
e.Handled = true;
}
}
private void Prev_Click(object sender, RoutedEventArgs e)
{
NavigateToPage(_currentPage - 1);
}
private void Next_Click(object sender, RoutedEventArgs e)
{
NavigateToPage(_currentPage + 1);
}
private void Close_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
{
string query = SearchBox.Text.Trim();
if (string.IsNullOrEmpty(query))
{
NavigateToPage(_currentPage);
return;
}
List<HelpItemModel> currentSourceItems = GetCurrentSourceItems();
List<HelpItemModel> list = currentSourceItems.Where((HelpItemModel i) => i.Title.Contains(query, StringComparison.OrdinalIgnoreCase) || i.Command.Contains(query, StringComparison.OrdinalIgnoreCase) || i.Description.Contains(query, StringComparison.OrdinalIgnoreCase) || i.Category.Contains(query, StringComparison.OrdinalIgnoreCase)).ToList();
ItemsHost.ItemsSource = list;
PageIndicator.Text = $"검색: \"{query}\" ({list.Count}개)";
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Pressed)
{
try
{
DragMove();
}
catch
{
}
}
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Invalid comparison between Unknown and I4
if ((int)e.Key == 13)
{
Close();
}
}
[DebuggerNonUserCode]
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
public void InitializeComponent()
{
if (!_contentLoaded)
{
_contentLoaded = true;
Uri resourceLocator = new Uri("/AxCopilot;component/views/helpdetailwindow.xaml", UriKind.Relative);
Application.LoadComponent(this, resourceLocator);
}
}
[DebuggerNonUserCode]
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
[EditorBrowsable(EditorBrowsableState.Never)]
void IComponentConnector.Connect(int connectionId, object target)
{
switch (connectionId)
{
case 1:
((HelpDetailWindow)target).MouseDown += Window_MouseDown;
((HelpDetailWindow)target).KeyDown += Window_KeyDown;
break;
case 2:
SubtitleText = (TextBlock)target;
break;
case 3:
((Button)target).Click += Close_Click;
break;
case 4:
TopMenuBar = (StackPanel)target;
break;
case 5:
SearchBox = (TextBox)target;
SearchBox.TextChanged += SearchBox_TextChanged;
break;
case 6:
CategoryBar = (WrapPanel)target;
break;
case 7:
ItemsHost = (ItemsControl)target;
break;
case 8:
PrevBtn = (Button)target;
PrevBtn.Click += Prev_Click;
break;
case 9:
PageIndicator = (TextBlock)target;
break;
case 10:
NextBtn = (Button)target;
NextBtn.Click += Next_Click;
break;
default:
_contentLoaded = true;
break;
}
}
}