using System; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.Threading; using Notify.Ipc; using Notify.Models; using Notify.Services; using Notify.ViewModels; using Notify.Views; namespace Notify; public partial class App : Application { private SettingsWindow? _settingsWindow; private SpoolWatcher? _spoolWatcher; public static new App Current => (App)Application.Current!; public SettingsService Settings { get; } = new(); public ToastManager Toasts { get; private set; } = null!; public override void Initialize() => AvaloniaXamlLoader.Load(this); public override void OnFrameworkInitializationCompleted() { Settings.Load(); Toasts = new ToastManager(Settings); // 监视 spool 目录,把 CLI 投递的请求转成 toast _spoolWatcher = new SpoolWatcher(OnNotify); _spoolWatcher.Start(); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { // 无主窗口的常驻进程:仅托盘存在,靠托盘菜单或外部请求驱动 desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown; // --demo:启动即弹一条 toast 并打开设置,便于无托盘交互地验证 if (desktop.Args is { Length: > 0 } args && System.Array.IndexOf(args, "--demo") >= 0) { Dispatcher.UIThread.Post(RunDemo); } } base.OnFrameworkInitializationCompleted(); } // 监视线程收到请求,切回 UI 线程弹出 toast private void OnNotify(NotifyMessage message) { if (Settings.Current.PlaySound) { Notify.Interop.Sound.Play(); } // 目标窗口已是前台(你正盯着看):完成类通知弹一下即可,用更短的停留 int? durationOverride = null; if (!message.InputMode && message.TargetHwnd != 0 && Notify.Interop.Win32.GetForegroundWindow().ToInt64() == message.TargetHwnd) { durationOverride = Settings.Current.FocusedDurationSeconds; } Dispatcher.UIThread.Post(() => Toasts.Show(new ToastRequest { Title = message.Title, Message = message.Message, InputMode = message.InputMode, Sticky = message.Sticky, TargetHwnd = message.TargetHwnd, WtRuntimeId = message.WtRuntimeId, IconPath = message.IconPath, DurationSecondsOverride = durationOverride, })); } private void RunDemo() { // 普通:会自动消失 Toasts.Show(new ToastRequest { Title = "Claude Code", Message = "任务已完成 — 4 秒后自动消失" }); // 常驻:InputMode 且 Sticky,不点不消失 Toasts.Show(new ToastRequest { Title = "需要你的输入", Message = "权限请求 — 常驻,点击 / ✕ 才关闭", InputMode = true, Sticky = true, }); } // 左键单击托盘图标直接打开设置 private void OnTrayClicked(object? sender, EventArgs e) => OpenSettings(); private void OpenSettings() { if (_settingsWindow is { } w) { w.Activate(); return; } _settingsWindow = new SettingsWindow { DataContext = new SettingsViewModel(Settings, Toasts), }; _settingsWindow.Closed += (_, _) => _settingsWindow = null; _settingsWindow.Show(); } private void OnExitClick(object? sender, EventArgs e) { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { desktop.Shutdown(); } } }