using System; using System.Drawing; using System.IO; using System.Net.Http; using System.Text.Json; using System.Timers; using System.Windows; using System.Windows.Forms; using System.Windows.Input; using XafPet.Desktop.PetEngine; using Timer = System.Timers.Timer; namespace XafPet.Desktop; public partial class MainWindow : Window { private NotifyIcon? _trayIcon; private ApiClient? _api; private Timer? _taskTimer; private Timer? _energyTimer; private Timer? _waterTimer; private string _baseUrl = "http://localhost:9082"; public MainWindow() { InitializeComponent(); RootGrid.MouseLeftButtonDown += (s, e) => { if (e.ButtonState == MouseButtonState.Pressed) DragMove(); }; PetHost.InteractionReceived += OnInteractionReceived; Loaded += OnLoaded; Closed += OnClosed; } private void OnLoaded(object sender, RoutedEventArgs e) { var token = TokenStore.Load(); _api = new ApiClient(new HttpClient(), _baseUrl, token ?? "dev-token"); StartPolling(); SetupTray(); _ = SyncMascotAsync(); } private void StartPolling() { _taskTimer = new Timer(30_000) { AutoReset = true }; _taskTimer.Elapsed += async (_, _) => await PollTasksAsync(); _taskTimer.Start(); _energyTimer = new Timer(60_000) { AutoReset = true }; _energyTimer.Elapsed += async (_, _) => await PollHealthAsync(); _energyTimer.Start(); StartWaterReminder(); } private async Task PollTasksAsync() { if (_api == null) return; try { var tasks = await _api.GetTodayTasksAsync(); var state = StateManager.MapState(tasks ?? new List(), null, null, false); PushState(state, "tasks"); } catch (ApiException ex) { PushBubble($"服务暂时不可用({ex.ApiCode})"); } catch (Exception) { PushBubble("连接后端失败,请检查服务"); } } private async Task PollHealthAsync() { if (_api == null) return; try { var energy = await _api.GetEnergyOverviewAsync(); var checkin = await _api.GetDailyCheckinAsync(); var state = StateManager.MapState(null, energy, checkin, false); PushState(state, "health"); } catch (Exception) { /* 静默 */ } } private void PushState(PetState state, string reason) { var payload = new PetStatePayload(StateManager.StateToCamelCase(state), reason, null); PetHost.NotifyState(JsonSerializer.Serialize(payload)); } private void PushBubble(string text) { PetHost.ShowBubble(text, 5000); } private void SetupTray() { var menu = new ContextMenuStrip(); menu.Items.Add("设置", null, (_, _) => ShowSettings()); menu.Items.Add("显示/隐藏", null, (_, _) => ToggleVisible()); menu.Items.Add("退出", null, (_, _) => { _trayIcon?.Dispose(); System.Windows.Application.Current.Shutdown(); }); _trayIcon = new NotifyIcon { Text = "浠艾福桌面宠物", Icon = SystemIcons.Application, ContextMenuStrip = menu, Visible = true }; _trayIcon.DoubleClick += (_, _) => ToggleVisible(); } private void ToggleVisible() { Visibility = Visibility == Visibility.Visible ? Visibility.Hidden : Visibility.Visible; } private void ShowSettings() { var win = new SettingsWindow(TokenStore.Load(), _baseUrl) { Owner = this }; if (win.ShowDialog() == true) { _baseUrl = win.BaseUrl; if (!string.IsNullOrEmpty(win.Token)) TokenStore.Save(win.Token); _api = new ApiClient(new HttpClient(), _baseUrl, TokenStore.Load() ?? "dev-token"); StopPolling(); StartPolling(); } } private void StopPolling() { _taskTimer?.Stop(); _energyTimer?.Stop(); _waterTimer?.Stop(); _taskTimer?.Dispose(); _energyTimer?.Dispose(); _waterTimer?.Dispose(); _taskTimer = _energyTimer = _waterTimer = null; } private void OnClosed(object? sender, EventArgs e) { StopPolling(); _trayIcon?.Dispose(); } // ── 喝水提醒 ───────────────────────────────────────────── private void StartWaterReminder() { _waterTimer = new Timer(60 * 60 * 1000) { AutoReset = true }; _waterTimer.Elapsed += async (_, _) => await CheckWaterAsync(); _waterTimer.Start(); _ = CheckWaterAsync(); } private async Task CheckWaterAsync() { if (_api == null) return; var hour = DateTime.Now.Hour; if (hour < 10 || hour > 20) return; try { var checkin = await _api.GetDailyCheckinAsync(); if (checkin != null && !checkin.Items.Contains("water")) { PushState(PetState.WaitingForInteraction, "drink_water"); PetHost.ShowBubble("该喝水啦~点我确认完成!", 15000); } } catch (Exception) { } } private void OnInteractionReceived(string action, string? dataJson) { switch (action) { case "click": _ = HandleClickAsync(); break; case "pet": PetHost.ShowBubble("嘻嘻~", 2000); break; } } private async Task HandleClickAsync() { if (_api == null) return; try { var result = await _api.CompleteDrinkWaterAsync(); if (result?.IsSuccess == true) { PushState(PetState.Happy, "drink_complete"); PetHost.ShowBubble("喝水打卡成功!太棒了~", 4000); } } catch (Exception) { PushBubble("打卡失败,请稍后再试"); } } // ── 吉祥物同步 ─────────────────────────────────────────── private async Task SyncMascotAsync() { if (_api == null) return; try { var mascot = await _api.GetMascotAsync(); var petName = mascot?.MascotId ?? "xibao"; var cfgPath = Path.Combine(AppContext.BaseDirectory, "DefaultPets", petName, "pet-config.json"); if (File.Exists(cfgPath)) { var json = File.ReadAllText(cfgPath); var parsed = PetConfig.Parse(json); PetHost.LoadPetConfig(JsonSerializer.Serialize(parsed)); } } catch (Exception) { /* 默认浠宝 */ } } }