|
|
@@ -1,218 +0,0 @@
|
|
|
-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<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(); 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) { /* 默认浠宝 */ }
|
|
|
- }
|
|
|
-}
|