| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- using System;
- using System.IO;
- using System.Text.Json;
- using System.Timers;
- using System.Windows;
- using System.Windows.Forms;
- using XafPet.Desktop.PetEngine;
- 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<CfcTask>(), 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(); 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");
- StartPolling();
- }
- }
- private async void OnClosed(object? sender, EventArgs e)
- {
- _taskTimer?.Stop(); _energyTimer?.Stop(); _waterTimer?.Stop();
- _taskTimer?.Dispose(); _energyTimer?.Dispose(); _waterTimer?.Dispose();
- _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) { /* 默认浠宝 */ }
- }
- }
|