[Phase 41] SettingsViewModel·AgentLoopService 파셜 클래스 분할
SettingsViewModel (1,855줄 → 320줄, 82.7% 감소): - SettingsViewModel.Properties.cs (837줄): 바인딩 프로퍼티 전체 - SettingsViewModel.Methods.cs (469줄): Save/Browse/Add 등 메서드 - SettingsViewModelModels.cs (265줄): 6개 모델 클래스 분리 AgentLoopService (1,823줄 → 1,334줄, 26.8% 감소): - AgentLoopService.Execution.cs (498줄): 병렬 도구 실행, ToolExecutionState - 빌드: 경고 0, 오류 0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
469
src/AxCopilot/ViewModels/SettingsViewModel.Methods.cs
Normal file
469
src/AxCopilot/ViewModels/SettingsViewModel.Methods.cs
Normal file
@@ -0,0 +1,469 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using AxCopilot.Models;
|
||||
using AxCopilot.Services;
|
||||
using AxCopilot.Themes;
|
||||
using AxCopilot.Views;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public partial class SettingsViewModel
|
||||
{
|
||||
// ─── 인덱스 경로 메서드 ──────────────────────────────────────────────
|
||||
public void AddIndexPath(string path)
|
||||
{
|
||||
var trimmed = path.Trim();
|
||||
if (string.IsNullOrWhiteSpace(trimmed)) return;
|
||||
if (IndexPaths.Any(p => p.Equals(trimmed, StringComparison.OrdinalIgnoreCase))) return;
|
||||
IndexPaths.Add(trimmed);
|
||||
}
|
||||
|
||||
public void RemoveIndexPath(string path) => IndexPaths.Remove(path);
|
||||
|
||||
// ─── 인덱스 확장자 메서드 ──────────────────────────────────────────
|
||||
public void AddExtension(string ext)
|
||||
{
|
||||
var trimmed = ext.Trim().ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(trimmed)) return;
|
||||
if (!trimmed.StartsWith(".")) trimmed = "." + trimmed;
|
||||
if (IndexExtensions.Any(e => e.Equals(trimmed, StringComparison.OrdinalIgnoreCase))) return;
|
||||
IndexExtensions.Add(trimmed);
|
||||
}
|
||||
|
||||
public void RemoveExtension(string ext) => IndexExtensions.Remove(ext);
|
||||
|
||||
public void BrowseIndexPath()
|
||||
{
|
||||
using var dlg = new FolderBrowserDialog
|
||||
{
|
||||
Description = "인덱스할 폴더 선택",
|
||||
UseDescriptionForTitle = true,
|
||||
ShowNewFolderButton = false
|
||||
};
|
||||
if (dlg.ShowDialog() != DialogResult.OK) return;
|
||||
AddIndexPath(dlg.SelectedPath);
|
||||
}
|
||||
|
||||
// ─── 빠른 실행 단축키 메서드 ──────────────────────────────────────────
|
||||
public bool AddShortcut()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_newKey) || string.IsNullOrWhiteSpace(_newTarget))
|
||||
return false;
|
||||
|
||||
// 중복 키 확인
|
||||
if (AppShortcuts.Any(s => s.Key.Equals(_newKey.Trim(), StringComparison.OrdinalIgnoreCase)))
|
||||
return false;
|
||||
|
||||
AppShortcuts.Add(new AppShortcutModel
|
||||
{
|
||||
Key = _newKey.Trim(),
|
||||
Description = _newDescription.Trim(),
|
||||
Target = _newTarget.Trim(),
|
||||
Type = _newType
|
||||
});
|
||||
|
||||
NewKey = ""; NewDescription = ""; NewTarget = ""; NewType = "app";
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveShortcut(AppShortcutModel shortcut) => AppShortcuts.Remove(shortcut);
|
||||
|
||||
/// <summary>파일 선택 대화상자. 선택 시 NewTarget에 자동 설정.</summary>
|
||||
public void BrowseTarget()
|
||||
{
|
||||
using var dlg = new OpenFileDialog
|
||||
{
|
||||
Filter = "실행 파일 (*.exe)|*.exe|모든 파일 (*.*)|*.*",
|
||||
Title = "앱 선택"
|
||||
};
|
||||
if (dlg.ShowDialog() != DialogResult.OK) return;
|
||||
|
||||
NewTarget = dlg.FileName;
|
||||
NewType = "app";
|
||||
if (string.IsNullOrWhiteSpace(NewDescription))
|
||||
NewDescription = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName);
|
||||
}
|
||||
|
||||
public void SelectTheme(string key)
|
||||
{
|
||||
SelectedThemeKey = key;
|
||||
ThemePreviewRequested?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void PickColor(ColorRowModel row)
|
||||
{
|
||||
using var dlg = new ColorDialog { FullOpen = true };
|
||||
try
|
||||
{
|
||||
var color = ThemeResourceHelper.HexColor(row.Hex);
|
||||
dlg.Color = System.Drawing.Color.FromArgb(color.R, color.G, color.B);
|
||||
}
|
||||
catch (Exception) { /* 기본값 사용 */ }
|
||||
|
||||
if (dlg.ShowDialog() != DialogResult.OK) return;
|
||||
|
||||
row.Hex = $"#{dlg.Color.R:X2}{dlg.Color.G:X2}{dlg.Color.B:X2}";
|
||||
if (_selectedThemeKey == "custom")
|
||||
ThemePreviewRequested?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
// 시스템 예약 프리픽스 (핸들러에서 이미 사용 중인 키)
|
||||
private static readonly HashSet<string> ReservedPrefixes = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"=", "?", "#", "$", ";", "@", "~", ">", "!",
|
||||
"emoji", "color", "recent", "note", "uninstall", "kill", "media",
|
||||
"info", "*", "json", "encode", "port", "env", "snap", "help",
|
||||
"pick", "date", "svc", "pipe", "journal", "routine", "batch",
|
||||
"diff", "win", "stats", "fav", "rename", "monitor", "scaffold",
|
||||
};
|
||||
|
||||
/// <summary>설정 저장 전 프리픽스/키워드 충돌을 검사합니다. 충돌 시 메시지를 반환합니다.</summary>
|
||||
public string? ValidateBeforeSave()
|
||||
{
|
||||
// 캡처 프리픽스 충돌 검사
|
||||
var cap = string.IsNullOrWhiteSpace(_capPrefix) ? "cap" : _capPrefix.Trim();
|
||||
if (cap != "cap" && ReservedPrefixes.Contains(cap))
|
||||
return $"캡처 프리픽스 '{cap}'은(는) 이미 사용 중인 예약어입니다.";
|
||||
|
||||
// 빠른 실행 별칭 키 중복 검사
|
||||
var aliasKeys = AppShortcuts.Select(s => s.Key.ToLowerInvariant()).ToList();
|
||||
var duplicateAlias = aliasKeys.GroupBy(k => k).FirstOrDefault(g => g.Count() > 1);
|
||||
if (duplicateAlias != null)
|
||||
return $"빠른 실행 키워드 '{duplicateAlias.Key}'이(가) 중복되었습니다.";
|
||||
|
||||
// 빠른 실행 별칭 키 vs 예약 프리픽스 충돌
|
||||
foreach (var key in aliasKeys)
|
||||
{
|
||||
if (ReservedPrefixes.Contains(key))
|
||||
return $"빠른 실행 키워드 '{key}'은(는) 시스템 예약어와 충돌합니다.";
|
||||
}
|
||||
|
||||
// 배치 명령 키 중복 검사
|
||||
var batchKeys = BatchCommands.Select(b => b.Key.ToLowerInvariant()).ToList();
|
||||
var duplicateBatch = batchKeys.GroupBy(k => k).FirstOrDefault(g => g.Count() > 1);
|
||||
if (duplicateBatch != null)
|
||||
return $"배치 명령 키워드 '{duplicateBatch.Key}'이(가) 중복되었습니다.";
|
||||
|
||||
return null; // 문제 없음
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
// 충돌 검사
|
||||
var conflict = ValidateBeforeSave();
|
||||
if (conflict != null)
|
||||
{
|
||||
CustomMessageBox.Show(
|
||||
conflict,
|
||||
"AX Copilot — 설정 저장 오류",
|
||||
System.Windows.MessageBoxButton.OK,
|
||||
System.Windows.MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var s = _service.Settings;
|
||||
s.Hotkey = _hotkey;
|
||||
s.Launcher.MaxResults = _maxResults;
|
||||
s.Launcher.Opacity = _opacity;
|
||||
s.Launcher.Theme = _selectedThemeKey;
|
||||
s.Launcher.Position = _launcherPosition;
|
||||
s.Launcher.WebSearchEngine = _webSearchEngine;
|
||||
s.Launcher.SnippetAutoExpand = _snippetAutoExpand;
|
||||
s.Launcher.Language = _language;
|
||||
L10n.SetLanguage(_language);
|
||||
|
||||
// 기능 토글 저장
|
||||
s.Launcher.ShowNumberBadges = _showNumberBadges;
|
||||
s.Launcher.EnableFavorites = _enableFavorites;
|
||||
s.Launcher.EnableRecent = _enableRecent;
|
||||
s.Launcher.EnableActionMode = _enableActionMode;
|
||||
s.Launcher.CloseOnFocusLost = _closeOnFocusLost;
|
||||
s.Launcher.ShowPrefixBadge = _showPrefixBadge;
|
||||
s.Launcher.EnableIconAnimation = _enableIconAnimation;
|
||||
s.Launcher.EnableRainbowGlow = _enableRainbowGlow;
|
||||
s.Launcher.EnableSelectionGlow = _enableSelectionGlow;
|
||||
s.Launcher.EnableRandomPlaceholder = _enableRandomPlaceholder;
|
||||
s.Launcher.ShowLauncherBorder = _showLauncherBorder;
|
||||
s.Launcher.ShortcutHelpUseThemeColor = _shortcutHelpUseThemeColor;
|
||||
s.Launcher.EnableTextAction = _enableTextAction;
|
||||
s.Launcher.EnableFileDialogIntegration = _enableFileDialogIntegration;
|
||||
s.Launcher.EnableClipboardAutoCategory = _enableClipboardAutoCategory;
|
||||
s.Launcher.MaxPinnedClipboardItems = _maxPinnedClipboardItems;
|
||||
s.Launcher.TextActionTranslateLanguage = _textActionTranslateLanguage;
|
||||
s.Llm.MaxSubAgents = _maxSubAgents;
|
||||
s.Llm.PdfExportPath = _pdfExportPath;
|
||||
s.Llm.TipDurationSeconds = _tipDurationSeconds;
|
||||
|
||||
// LLM 공통 설정 저장
|
||||
s.Llm.Service = _llmService;
|
||||
s.Llm.Streaming = _llmStreaming;
|
||||
s.Llm.MaxContextTokens = _llmMaxContextTokens;
|
||||
s.Llm.RetentionDays = _llmRetentionDays;
|
||||
s.Llm.Temperature = _llmTemperature;
|
||||
s.Llm.DefaultAgentPermission = _defaultAgentPermission;
|
||||
s.Llm.DefaultOutputFormat = _defaultOutputFormat;
|
||||
s.Llm.DefaultMood = _defaultMood;
|
||||
s.Llm.AutoPreview = _autoPreview;
|
||||
s.Llm.MaxAgentIterations = _maxAgentIterations;
|
||||
s.Llm.MaxRetryOnError = _maxRetryOnError;
|
||||
s.Llm.AgentLogLevel = _agentLogLevel;
|
||||
s.Llm.AgentDecisionLevel = _agentDecisionLevel;
|
||||
s.Llm.PlanMode = _planMode;
|
||||
s.Llm.EnableMultiPassDocument = _enableMultiPassDocument;
|
||||
s.Llm.EnableCoworkVerification = _enableCoworkVerification;
|
||||
s.Llm.EnableFilePathHighlight = _enableFilePathHighlight;
|
||||
s.Llm.FolderDataUsage = _folderDataUsage;
|
||||
s.Llm.EnableAuditLog = _enableAuditLog;
|
||||
s.Llm.EnableAgentMemory = _enableAgentMemory;
|
||||
s.Llm.EnableProjectRules = _enableProjectRules;
|
||||
s.Llm.MaxMemoryEntries = _maxMemoryEntries;
|
||||
s.Llm.EnableImageInput = _enableImageInput;
|
||||
s.Llm.MaxImageSizeKb = _maxImageSizeKb;
|
||||
s.Llm.EnableToolHooks = _enableToolHooks;
|
||||
s.Llm.ToolHookTimeoutMs = _toolHookTimeoutMs;
|
||||
s.Llm.EnableSkillSystem = _enableSkillSystem;
|
||||
s.Llm.SkillsFolderPath = _skillsFolderPath;
|
||||
s.Llm.SlashPopupPageSize = _slashPopupPageSize;
|
||||
s.Llm.EnableDragDropAiActions = _enableDragDropAiActions;
|
||||
s.Llm.DragDropAutoSend = _dragDropAutoSend;
|
||||
s.Llm.Code.EnableCodeReview = _enableCodeReview;
|
||||
s.Llm.EnableAutoRouter = _enableAutoRouter;
|
||||
s.Llm.AutoRouterConfidence = _autoRouterConfidence;
|
||||
s.Llm.EnableChatRainbowGlow = _enableChatRainbowGlow;
|
||||
s.Llm.NotifyOnComplete = _notifyOnComplete;
|
||||
s.Llm.ShowTips = _showTips;
|
||||
s.Llm.DevMode = _devMode;
|
||||
s.Llm.DevModeStepApproval = _devModeStepApproval;
|
||||
s.Llm.WorkflowVisualizer = _workflowVisualizer;
|
||||
s.Llm.FreeTierMode = _freeTierMode;
|
||||
s.Llm.FreeTierDelaySeconds = _freeTierDelaySeconds;
|
||||
s.Llm.ShowTotalCallStats = _showTotalCallStats;
|
||||
|
||||
// 서비스별 독립 설정 저장
|
||||
s.Llm.OllamaEndpoint = _ollamaEndpoint;
|
||||
s.Llm.OllamaModel = _ollamaModel;
|
||||
s.Llm.VllmEndpoint = _vllmEndpoint;
|
||||
s.Llm.VllmModel = _vllmModel;
|
||||
s.Llm.GeminiModel = _geminiModel;
|
||||
s.Llm.ClaudeModel = _claudeModel;
|
||||
s.Llm.GeminiApiKey = _geminiApiKey;
|
||||
s.Llm.ClaudeApiKey = _claudeApiKey;
|
||||
|
||||
// 내부 서비스 API 키 저장 (암호화 분기)
|
||||
if (!string.IsNullOrEmpty(_ollamaApiKey) && _ollamaApiKey != "(저장됨)")
|
||||
s.Llm.OllamaApiKey = CryptoService.EncryptIfEnabled(_ollamaApiKey, s.Llm.EncryptionEnabled);
|
||||
if (!string.IsNullOrEmpty(_vllmApiKey) && _vllmApiKey != "(저장됨)")
|
||||
s.Llm.VllmApiKey = CryptoService.EncryptIfEnabled(_vllmApiKey, s.Llm.EncryptionEnabled);
|
||||
|
||||
// 활성 서비스의 설정을 기존 호환 필드에도 동기화 (LlmService.cs 호환)
|
||||
switch (_llmService)
|
||||
{
|
||||
case "ollama":
|
||||
s.Llm.Endpoint = _ollamaEndpoint;
|
||||
s.Llm.Model = _ollamaModel;
|
||||
s.Llm.EncryptedApiKey = s.Llm.OllamaApiKey;
|
||||
break;
|
||||
case "vllm":
|
||||
s.Llm.Endpoint = _vllmEndpoint;
|
||||
s.Llm.Model = _vllmModel;
|
||||
s.Llm.EncryptedApiKey = s.Llm.VllmApiKey;
|
||||
break;
|
||||
case "gemini":
|
||||
s.Llm.ApiKey = _geminiApiKey;
|
||||
s.Llm.Model = _geminiModel;
|
||||
break;
|
||||
case "claude":
|
||||
s.Llm.ApiKey = _claudeApiKey;
|
||||
s.Llm.Model = _claudeModel;
|
||||
break;
|
||||
}
|
||||
|
||||
// 등록 모델 저장
|
||||
s.Llm.RegisteredModels = RegisteredModels
|
||||
.Where(rm => !string.IsNullOrWhiteSpace(rm.Alias))
|
||||
.Select(rm => new RegisteredModel
|
||||
{
|
||||
Alias = rm.Alias,
|
||||
EncryptedModelName = rm.EncryptedModelName,
|
||||
Service = rm.Service,
|
||||
Endpoint = rm.Endpoint,
|
||||
ApiKey = rm.ApiKey,
|
||||
AuthType = rm.AuthType ?? "bearer",
|
||||
Cp4dUrl = rm.Cp4dUrl ?? "",
|
||||
Cp4dUsername = rm.Cp4dUsername ?? "",
|
||||
Cp4dPassword = rm.Cp4dPassword ?? "",
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 프롬프트 템플릿 저장
|
||||
s.Llm.PromptTemplates = PromptTemplates
|
||||
.Where(pt => !string.IsNullOrWhiteSpace(pt.Name))
|
||||
.Select(pt => new PromptTemplate { Name = pt.Name, Content = pt.Content, Icon = pt.Icon })
|
||||
.ToList();
|
||||
|
||||
// 인덱스 경로 + 확장자 저장
|
||||
s.IndexPaths = IndexPaths.ToList();
|
||||
s.IndexExtensions = IndexExtensions.ToList();
|
||||
s.IndexSpeed = _indexSpeed;
|
||||
|
||||
// 커스텀 색상 + 모양 저장
|
||||
var c = s.Launcher.CustomTheme ??= new CustomThemeColors();
|
||||
foreach (var row in ColorRows)
|
||||
{
|
||||
var prop = typeof(CustomThemeColors).GetProperty(row.Property);
|
||||
prop?.SetValue(c, row.Hex);
|
||||
}
|
||||
c.WindowCornerRadius = _customWindowCornerRadius;
|
||||
c.ItemCornerRadius = _customItemCornerRadius;
|
||||
|
||||
// 빠른 실행 단축키 저장:
|
||||
// batch/api/clipboard type은 그대로 유지, app/url/folder는 ViewModel 내용으로 교체
|
||||
var otherAliases = s.Aliases
|
||||
.Where(a => a.Type is not ("app" or "url" or "folder" or "batch"))
|
||||
.ToList();
|
||||
s.Aliases = otherAliases
|
||||
.Concat(AppShortcuts.Select(sc => new AliasEntry
|
||||
{
|
||||
Key = sc.Key,
|
||||
Type = sc.Type,
|
||||
Target = sc.Target,
|
||||
Description = string.IsNullOrWhiteSpace(sc.Description) ? null : sc.Description
|
||||
}))
|
||||
.Concat(BatchCommands.Select(b => new AliasEntry
|
||||
{
|
||||
Key = b.Key,
|
||||
Type = "batch",
|
||||
Target = b.Command,
|
||||
ShowWindow = b.ShowWindow
|
||||
}))
|
||||
.ToList();
|
||||
|
||||
// 스니펫 저장
|
||||
s.Snippets = Snippets.Select(sn => new SnippetEntry
|
||||
{
|
||||
Key = sn.Key,
|
||||
Name = sn.Name,
|
||||
Content = sn.Content
|
||||
}).ToList();
|
||||
|
||||
// 알림 설정 저장
|
||||
s.Reminder.Enabled = _reminderEnabled;
|
||||
s.Reminder.Corner = _reminderCorner;
|
||||
s.Reminder.IntervalMinutes = _reminderIntervalMinutes;
|
||||
s.Reminder.DisplaySeconds = _reminderDisplaySeconds;
|
||||
|
||||
// 캡처 설정 저장
|
||||
s.ScreenCapture.Prefix = string.IsNullOrWhiteSpace(_capPrefix) ? "cap" : _capPrefix.Trim();
|
||||
s.ScreenCapture.GlobalHotkeyEnabled = _capGlobalHotkeyEnabled;
|
||||
s.ScreenCapture.GlobalHotkey = string.IsNullOrWhiteSpace(_capGlobalHotkey) ? "PrintScreen" : _capGlobalHotkey.Trim();
|
||||
s.ScreenCapture.GlobalHotkeyMode = _capGlobalMode;
|
||||
s.ScreenCapture.ScrollDelayMs = Math.Max(50, _capScrollDelayMs);
|
||||
|
||||
// 클립보드 히스토리 설정 저장
|
||||
s.ClipboardHistory.Enabled = _clipboardEnabled;
|
||||
s.ClipboardHistory.MaxItems = _clipboardMaxItems;
|
||||
|
||||
// 시스템 명령 설정 저장
|
||||
var sc = s.SystemCommands;
|
||||
sc.ShowLock = _sysShowLock;
|
||||
sc.ShowSleep = _sysShowSleep;
|
||||
sc.ShowRestart = _sysShowRestart;
|
||||
sc.ShowShutdown = _sysShowShutdown;
|
||||
sc.ShowHibernate = _sysShowHibernate;
|
||||
sc.ShowLogout = _sysShowLogout;
|
||||
sc.ShowRecycleBin = _sysShowRecycleBin;
|
||||
|
||||
// 시스템 명령 별칭 저장
|
||||
var cmdAliases = new Dictionary<string, List<string>>();
|
||||
void SaveAlias(string key, string val)
|
||||
{
|
||||
var list = ParseAliases(val);
|
||||
if (list.Count > 0) cmdAliases[key] = list;
|
||||
}
|
||||
SaveAlias("lock", _aliasLock);
|
||||
SaveAlias("sleep", _aliasSleep);
|
||||
SaveAlias("restart", _aliasRestart);
|
||||
SaveAlias("shutdown", _aliasShutdown);
|
||||
SaveAlias("hibernate", _aliasHibernate);
|
||||
SaveAlias("logout", _aliasLogout);
|
||||
SaveAlias("recycle", _aliasRecycle);
|
||||
sc.CommandAliases = cmdAliases;
|
||||
|
||||
_service.Save();
|
||||
SaveCompleted?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public bool AddBatchCommand()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_newBatchKey) || string.IsNullOrWhiteSpace(_newBatchCommand))
|
||||
return false;
|
||||
if (BatchCommands.Any(b => b.Key.Equals(_newBatchKey.Trim(), StringComparison.OrdinalIgnoreCase)))
|
||||
return false;
|
||||
|
||||
BatchCommands.Add(new BatchCommandModel
|
||||
{
|
||||
Key = _newBatchKey.Trim(),
|
||||
Command = _newBatchCommand.Trim(),
|
||||
ShowWindow = _newBatchShowWindow
|
||||
});
|
||||
NewBatchKey = ""; NewBatchCommand = ""; NewBatchShowWindow = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveBatchCommand(BatchCommandModel cmd) => BatchCommands.Remove(cmd);
|
||||
|
||||
// ─── 스니펫 메서드 ──────────────────────────────────────────────────────
|
||||
public bool AddSnippet()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_newSnippetKey) || string.IsNullOrWhiteSpace(_newSnippetContent))
|
||||
return false;
|
||||
if (Snippets.Any(sn => sn.Key.Equals(_newSnippetKey.Trim(), StringComparison.OrdinalIgnoreCase)))
|
||||
return false;
|
||||
|
||||
Snippets.Add(new SnippetRowModel
|
||||
{
|
||||
Key = _newSnippetKey.Trim(),
|
||||
Name = _newSnippetName.Trim(),
|
||||
Content = _newSnippetContent.Trim()
|
||||
});
|
||||
NewSnippetKey = ""; NewSnippetName = ""; NewSnippetContent = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveSnippet(SnippetRowModel row) => Snippets.Remove(row);
|
||||
|
||||
// ─── 캡처 메서드 ────────────────────────────────────────────────────────
|
||||
public void ResetCapPrefix() => CapPrefix = "cap";
|
||||
|
||||
public void ResetCapGlobalHotkey()
|
||||
{
|
||||
CapGlobalHotkey = "PrintScreen";
|
||||
CapGlobalMode = "screen";
|
||||
}
|
||||
|
||||
// ─── 알림 메서드 ────────────────────────────────────────────────────────
|
||||
public List<string> GetReminderCategories() => _service.Settings.Reminder.EnabledCategories;
|
||||
|
||||
// ─── 시스템 명령 메서드 ─────────────────────────────────────────────────
|
||||
public void ResetSystemCommandAliases()
|
||||
{
|
||||
AliasLock = ""; AliasSleep = ""; AliasRestart = "";
|
||||
AliasShutdown = ""; AliasHibernate = ""; AliasLogout = ""; AliasRecycle = "";
|
||||
}
|
||||
|
||||
private static string FormatAliases(Dictionary<string, List<string>> dict, string key)
|
||||
=> dict.TryGetValue(key, out var list) ? string.Join(", ", list) : "";
|
||||
|
||||
private static List<string> ParseAliases(string input)
|
||||
=> input.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.ToList();
|
||||
|
||||
public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
|
||||
protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string? n = null)
|
||||
=> PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(n));
|
||||
}
|
||||
Reference in New Issue
Block a user