using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; namespace JJServiceManager { /// 바인딩용 기본 클래스 public abstract class ObservableObject : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected bool Set(ref T field, T value, [CallerMemberName] string name = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(name); return true; } protected void OnPropertyChanged([CallerMemberName] string name = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } /// 로그창 띄우기 방식 public enum LogWindowMode { Individual = 0, // 개별 창 Tabs = 1, // 하나의 창에 탭 Split = 2 // 창을 좌우로 나누어 비교 } /// Esc 키 동작 public enum EscAction { Tray = 0, // 트레이로 (백그라운드) Exit = 1 // 완전 종료 } /// 등록된 서비스 한 건 public class ServiceEntry { public string ServiceName { get; set; } = ""; public string DisplayName { get; set; } = ""; /// 로그 파일 경로 또는 로그 폴더 경로 (없으면 빈 값) public string LogPath { get; set; } = ""; /// true면 LogPath는 폴더이며, 그 안의 가장 최근 수정 파일을 표시 public bool LogIsFolder { get; set; } /// 로그 인코딩: auto / utf-8 / cp949 public string LogEncoding { get; set; } = "auto"; } /// 프로그램 설정 (settings.json) public class AppSettings { public List Services { get; set; } = new List(); /// 컴퓨터 시작 시 기동 public bool RunAtStartup { get; set; } /// 단축키 사용 여부 public bool HotkeyEnabled { get; set; } = true; /// 단축키 보조키 (System.Windows.Input.ModifierKeys 값) public int HotkeyModifiers { get; set; } = 2 | 4; // Ctrl + Shift /// 단축키 키 (System.Windows.Input.Key 값) public int HotkeyKey { get; set; } = 44; // Key.A /// 서비스 시작 시 로그보기 = 작업 로그를 화면 하단에 표시할지 여부 public bool ShowOperationLog { get; set; } = true; /// 로그창 띄우기 방식 public LogWindowMode LogWindowMode { get; set; } = LogWindowMode.Individual; /// Esc 키 동작 public EscAction EscAction { get; set; } = EscAction.Tray; /// Windows 강제종료 / 재시작 버튼 표시 public bool ShowShutdownButtons { get; set; } = true; /// 창 크기·위치 public double WindowLeft { get; set; } = double.NaN; public double WindowTop { get; set; } = double.NaN; public double WindowWidth { get; set; } = 1000; public double WindowHeight { get; set; } = 720; } /// 설정 파일 저장/불러오기 public static class SettingsStore { public static string DataFolder { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "JJServiceManager"); public static string SettingsPath => Path.Combine(DataFolder, "settings.json"); private static readonly JsonSerializerOptions Options = new JsonSerializerOptions { WriteIndented = true, NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, Converters = { new JsonStringEnumConverter() } }; public static AppSettings Load() { try { if (File.Exists(SettingsPath)) { var json = File.ReadAllText(SettingsPath); var s = JsonSerializer.Deserialize(json, Options); if (s != null) { s.Services ??= new List(); return s; } } } catch { // 설정 파일이 손상된 경우 기본값 사용 (원본 파일은 지우지 않음) } return new AppSettings(); } public static void Save(AppSettings settings) { try { Directory.CreateDirectory(DataFolder); var tmp = SettingsPath + ".tmp"; File.WriteAllText(tmp, JsonSerializer.Serialize(settings, Options)); File.Copy(tmp, SettingsPath, true); File.Delete(tmp); } catch { // 저장 실패는 무시 (다음 저장 때 다시 시도) } } } /// 작업 로그를 날짜별 파일에 추가 기록 (삭제 기능 없음) public static class OperationLogFile { private static readonly object Sync = new object(); public static string Folder => Path.Combine(SettingsStore.DataFolder, "logs"); public static void Append(DateTime time, string text) { try { lock (Sync) { Directory.CreateDirectory(Folder); var path = Path.Combine(Folder, time.ToString("yyyy-MM-dd") + ".log"); File.AppendAllText(path, $"[{time:yyyy-MM-dd HH:mm:ss}] {text}{Environment.NewLine}"); } } catch { // 기록 실패는 무시 } } } }