diff --git a/src/SpamGuard/Tray/TrayApplicationContext.cs b/src/SpamGuard/Tray/TrayApplicationContext.cs new file mode 100644 index 0000000..ac552fe --- /dev/null +++ b/src/SpamGuard/Tray/TrayApplicationContext.cs @@ -0,0 +1,110 @@ +// src/SpamGuard/Tray/TrayApplicationContext.cs +namespace SpamGuard.Tray; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using SpamGuard.Services; + +public sealed class TrayApplicationContext : ApplicationContext +{ + private readonly NotifyIcon _notifyIcon; + private readonly System.Windows.Forms.Timer _refreshTimer; + private readonly ActivityLog _activityLog; + private readonly InboxMonitorService _monitor; + private readonly IHost _host; + private ActivityLogForm? _logForm; + private readonly ToolStripMenuItem _pauseMenuItem; + + public TrayApplicationContext(IHost host) + { + _host = host; + _activityLog = host.Services.GetRequiredService(); + _monitor = host.Services.GetRequiredService(); + + _pauseMenuItem = new ToolStripMenuItem("Pause", null, OnPauseResume); + + var contextMenu = new ContextMenuStrip(); + contextMenu.Items.Add("View Activity Log", null, OnViewLog); + contextMenu.Items.Add(_pauseMenuItem); + contextMenu.Items.Add(new ToolStripSeparator()); + contextMenu.Items.Add("Quit", null, OnQuit); + + _notifyIcon = new NotifyIcon + { + Icon = IconGenerator.Green, + Text = "SpamGuard - Starting...", + Visible = true, + ContextMenuStrip = contextMenu + }; + + _notifyIcon.DoubleClick += OnViewLog; + + _refreshTimer = new System.Windows.Forms.Timer { Interval = 5000 }; + _refreshTimer.Tick += OnRefreshTick; + _refreshTimer.Start(); + } + + private void OnRefreshTick(object? sender, EventArgs e) + { + var checked_ = _activityLog.TodayChecked; + var spam = _activityLog.TodaySpam; + _notifyIcon.Text = $"SpamGuard - {checked_} checked, {spam} spam caught today"; + + // Update icon based on state + if (!_monitor.IsPaused) + { + var recent = _activityLog.GetRecent(1); + var hasRecentError = recent.Count > 0 + && recent[0].Verdict == Models.Verdict.Error + && recent[0].Timestamp > DateTime.UtcNow.AddMinutes(-5); + _notifyIcon.Icon = hasRecentError ? IconGenerator.Red : IconGenerator.Green; + } + + _logForm?.RefreshData(); + } + + private void OnViewLog(object? sender, EventArgs e) + { + if (_logForm == null || _logForm.IsDisposed) + { + _logForm = new ActivityLogForm(_activityLog); + } + _logForm.Show(); + _logForm.BringToFront(); + } + + private void OnPauseResume(object? sender, EventArgs e) + { + if (_monitor.IsPaused) + { + _monitor.Resume(); + _pauseMenuItem.Text = "Pause"; + _notifyIcon.Icon = IconGenerator.Green; + } + else + { + _monitor.Pause(); + _pauseMenuItem.Text = "Resume"; + _notifyIcon.Icon = IconGenerator.Yellow; + } + } + + private async void OnQuit(object? sender, EventArgs e) + { + _notifyIcon.Visible = false; + _refreshTimer.Stop(); + await _host.StopAsync(); + Application.Exit(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _refreshTimer.Dispose(); + _notifyIcon.Dispose(); + _logForm?.Dispose(); + } + base.Dispose(disposing); + } +}